2009-09-24 2 views
3

[Проблема]
Создав общую библиотеку, которая должна быть развернута на компьютере-сервере и клиентской машине, как я могу общаться между клиент-сервер с классами, предоставляемых библиотекой ?Как вернуть пользовательские объекты с WebServices

Передача информации через веб-службы не работает, поскольку сериализованный объект, возвращаемый веб-службой, является классом webservice, который не преобразуется в общую библиотеку.

Я использую веб-службы неправильно? Есть ли способ лучше?

[Пример]

MyLibrary.cs и SubLibrary.cs находится в общей сборки, который должен быть использован приложением клиента.

MyLibrary.cs

public class MyLibrary 
{ 
    private SubLibrary sublib = new SubLibrary(); 

    public class MyLibrary() 
    { 
    } 

    public string GetValue() 
    { 
     return sublib.GetValue(); 
    } 
} 

SubLibrary.cs

public class SubLibrary 
{ 
    private string str = "Hello World"; 

    public SubLibrary() 
    { 
    } 

    public string GetValue() 
    { 
     return str; 
    } 
} 

WebService.asmx.cs

[WebMethod] 
public MyLibrary GetInfo() 
{ 
    return new MyLibrary(); 
} 

Клиент App

private void GetInfo_Click(object sender, System.EventArgs e) 
{ 
    WS.WebService services = new WS.WebService(); 

    MyLibrary info = services.GetInfo(); // This of course doesn't convert. 

    MessageBox.Show(info.GetValue()); 
} 

ответ

5

Короче говоря, это является боль в 1.1 (и частично 2,0 тоже). Совместное использование разделов (или разделение типов) только действительно начал функционировать в WCF (.NET 3.0). Прокси, сгенерированные в 1.1, никогда не будут напрямую совместимы с «актуальными» классами; вы можете использовать одни и те же прокси между несколькими службами («sharetypes»?), но не с независимыми исходными файлами, IIRC.

И поскольку это C# 1.2, у вас нет ни частичных классов, ни методов расширения, чтобы обманывать их, чтобы их перевести.

Варианты (что я могу видеть):

  • написать статический метод полезности кропотливо переводить между двумя моделями объектов
  • Дитто, но с использованием XmlSerializer (меньше кода, но не так быстро)
  • жить с ним
  • обновления для WCF (довольно значительные изменения)
+0

+1 @Marc: Спасибо за понимание и альтернативные варианты. Это правда, что это большая боль в 1.1. –

+0

@Marc: Если вы были на .NET 3.5, как бы вы использовали частичные классы или методы расширения для преобразования объектов? –

+0

С частичными классами вы можете добавить статические операторы преобразования (явные/неявные). С помощью метода расширения вы можете добавить методы 'ConvertToFoo()' и т. Д. –

1

с веб-службы, тип каждого объекта, который вы отправляете по кабелю, ДОЛЖНЫ быть сериализуемыми. Вы можете сделать сериализацию SubLibrary путем реализации интерфейса IXmlSerializable.

public class SubLibrary : IXmlSerializable 
{ 
    private string str = "Hello World"; 

    public SubLibrary() 
    { 
    } 

    public string GetValue() 
    { 
     return str; 
    } 

    public XmlSchema GetSchema() 
    { 
     return null; 
    } 

    public void ReadXml(XmlReader reader) 
    { 
     //... 
    } 

    public void WriteXml(XmlWriter writer) 
    { 
     //... 
    } 
} 

Одно предостережение, хотя: Так как вы передаете как MyLibrary и подбиблиотеке через WS, вы должны убедиться, что они оба сериализации.Кроме того, поскольку вы передаете MyLibrary, и в нем содержит экземпляр SubLibrary, вы должны поддерживать связь между MyLibrary и SubLibrary во время сериализации, и это будет проблемой. Если у вас нет другой причины для того, чтобы захотеть инкапсулировать экземпляр SubLibrary внутри MyLibrary, о котором я не знаю, я бы избавился от этого среднего уровня и попросил веб-службу вернуть экземпляр SubLibrary. Таким образом, вы бы просто:

[WebMethod] 
public SubLibrary GetInfo() 
{ 

    return new Sublibrary(); 
} 

И в приложении клиента:

private void GetInfo_Click(object sender, System.EventArgs e) 
{ 
    WS.WebService services = new WS.WebService(); 

    SubLibrary info = services.GetInfo(); // This of course doesn't convert. 

    MessageBox.Show(info.GetValue()); 
} 

Хороший способ вещь прохождения сложных объектов с помощью веб-служб: вы сериализации всех членов данных экземпляр в XML, отправка его по проводу, а затем десериализация его обратно в реальные данные на другом конце. Не думайте об этом как отправке фактического класса (с не-данными) по проводке.

+0

Использование 'IXmlSerializable' имеет тенденцию добавлять больше путаницы к веб-сервисам, поскольку прокси не будет иметь код ... –

+0

Он говорит об использовании тех же классов в с обеих сторон провода, так что это не должно быть проблемой. Если ОП разрабатывает веб-сервисы для общественного потребления, я определенно согласен с вашей точкой зрения. – HiredMind

0

Как правило, вы должны добавить веб-ссылку на свой сервис. Это создает прокси-сервер на стороне клиента, который содержит классы, которые клиент может использовать для вызова веб-службы вместо вашей общей библиотеки.

В вашем случае это, вероятно, выглядеть так:

WS.WebService services = new WS.WebService(); 

// Use client side proxy in same namespace as generated web reference 
WS.MyLibrary info = services.GetInfo(); 


Я припоминаю, подставляя свою общую библиотеку в созданном прокси-классе (как тест), и все, казалось, работало. Но это не рекомендуется и не гарантируется.

Это может быть ваш пример, но ваш класс MyLibrary не имеет данных для возврата. Причина в том, что XmlSerializer (используемый средой выполнения для преобразования между объектами XML и CLR) только сериализует общедоступные свойства и поля объекта. В MyLibrary и SubLibrary не отображаются никакие свойства или общедоступные поля, поэтому никакие данные не сериализуются. Для получения дополнительной информации см. XML and SOAP Serialization

+0

-1: Он должен использовать классы в общей библиотеке. –

+0

Я понимаю это. Я старался * сделать 3 очка: каким будет типичный подход (поскольку нет элегантного решения), что я сделал это раньше, изменив прокси-сервер и удалив созданные объекты и добавив использование для моей общей библиотеки (но что это не очень хорошая идея, IMO) и что образец кода не раскрывает никаких свойств (он использует методы, которые не сериализованы). Конечно, я, возможно, потерпел неудачу. :) –

+0

ПРИМЕЧАНИЕ. Реализация, которую мне сказали использовать, такая же, как вы сказали Tuzo с модификацией сгенерированных объектов. Лично я предпочитаю подход Марка к созданию адаптера как такового. Лучше локализовать боль в многоуровневом подходе, чем прибегать к ручному редактированию сгенерированного кода. Кроме того, мы обнаружили, что вручную редактирование сгенерированных объектов должен быть изменен исходный дизайн и код, чтобы разрешить сериализацию веб-сервисов. Это приводит к получению дизайна, поскольку необходимо подвергать классы методам, которые не должны быть. –

Смежные вопросы