У клиента WCF возникли проблемы распознавания сервисныхknowntypes?

StackOverflow https://stackoverflow.com/questions/3840435

Вопрос

Как бы я сообщить WCF Service, что известно, чтобы использовать при прохождении данных обратно к клиенту?

Я знаю, что могу использовать [ServiceKnownType] Атрибут, который заставляет вызов сервиса работать штрафом с тестового сервера WCF, однако он все еще не удается от клиента. Я что-то упускаю здесь?

[OperationContract]
[ServiceKnownType(typeof(SubClassA))]
[ServiceKnownType(typeof(SubClassB))]
BaseClassZ GetObject();

Сообщение об ошибке от клиента:

{«Элемент» http://schemas.datacontrtract.org/2004/07/baseclassz "содержит данные из типа, который отображает название« http://schemas.datacontract.org/2004/07/subclassa ». Deserializer Не знает о любом типе, который отображает это имя. Рассмотрим использование DataconTractresolver или добавить тип, соответствующий «подклассию» к списку известных типов - например, с помощью атрибута SEVELYBEEPEATTRIBUTE или добавлением его в список известных типов передается на datacontractserializer. "}

Сериализация / десериализация объекта на сервере WCF с использованием DataContractserializer и список известных пятен работает нормально.

ОБНОВИТЬ: Похоже, что я могу заставить клиента правильно прочитать объект, если я добавляю атрибуты известных пятен в базовый класс, но я все еще ищу об этом, если это возможно, по возможности, поскольку базовый класс используется для многих предметов, и я не Хотите изменить атрибуты SewiveType на базовом классе в любое время добавляете новый элемент.

[DataContract]
[KnownType(typeof(SubClassA))]
[KnownType(typeof(SubClassB))]
public class BaseClassZ 
{
    ...
}
Это было полезно?

Решение

Чтобы избежать сдерживания вашего сервисного кода, поместите известные типы в Web.config службы:

<system.runtime.serialization>
    <dataContractSerializer>
        <declaredTypes>
            <add type="SomeNs.BaseClassZ, SomeAssembly">
                <knownType type="SomeNs.SubClassA, SomeAssembly" />
                <knownType type="SomeNs.SubClassB, SomeAssembly" />
            </add>
        </declaredTypes>
    </dataContractSerializer>
</system.runtime.serialization>

Если вы хотите сделать это по коду, вам нужно использовать этот атрибут на сервисном интерфейсе, а не на методе работы, но я бы предпочел декларативный подход:

[ServiceContract]
[ServiceKnownType(typeof(SubClassA))]
[ServiceKnownType(typeof(SubClassB))]
public interface IFoo
{
    [OperationContract]
    BaseClassZ GetObject();
}

ОБНОВИТЬ:

Я поставил Образец проекта иллюстрирующее использование Web.config для настройки известных типов, которые являются моим предпочтительным подходом. И другой Образец проекта демонстрируя второй подход.


Обновление 2:

После того, как посмотрел на обновленный код с помощью клиента приложения Silverlight, мы замечаем следующее определение:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference1.IService1")]
public interface IService1 {

    [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetMany", ReplyAction="http://tempuri.org/IService1/GetManyResponse")]
    System.IAsyncResult BeginGetMany(System.AsyncCallback callback, object asyncState);

    System.Collections.ObjectModel.ObservableCollection<MyCommonLib.BaseClassZ> EndGetMany(System.IAsyncResult result);

    [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetSingle", ReplyAction="http://tempuri.org/IService1/GetSingleResponse")]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyCommonLib.SubClassA))]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyCommonLib.SubClassB))]
    System.IAsyncResult BeginGetSingle(System.AsyncCallback callback, object asyncState);

    MyCommonLib.BaseClassZ EndGetSingle(System.IAsyncResult result);
}

Обратите внимание, как BeginGetSingle метод содержит известные атрибуты типа, когда BeginGetMany Метод не. На самом деле эти атрибуты должны быть размещены на определении обслуживания, чтобы класс выглядел так.

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference1.IService1")]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyCommonLib.SubClassA))]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyCommonLib.SubClassB))]
public interface IService1
{
    [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetMany", ReplyAction="http://tempuri.org/IService1/GetManyResponse")]
    System.IAsyncResult BeginGetMany(System.AsyncCallback callback, object asyncState);

    System.Collections.ObjectModel.ObservableCollection<MyCommonLib.BaseClassZ> EndGetMany(System.IAsyncResult result);

    [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetSingle", ReplyAction="http://tempuri.org/IService1/GetSingleResponse")]
    System.IAsyncResult BeginGetSingle(System.AsyncCallback callback, object asyncState);

    MyCommonLib.BaseClassZ EndGetSingle(System.IAsyncResult result);
}

Как это автогенеративный класс, может быть ошибка в Slsvcutil.exe. а также svcutil.exe Как это проявляет то же поведение. Помещение известных атрибутов типа на их правильное место решает проблему. Проблема в том, что этот класс аутогенерируется инструментом, и если вы пытаетесь восстановить его из WSDL, он снова будет запущен.

Так кажется, если у вас есть следующее определение сервиса:

[ServiceContract]
[ServiceKnownType(typeof(SubClassA))]
[ServiceKnownType(typeof(SubClassB))]
public interface IService1
{
    [OperationContract]
    BaseClassZ[] GetMany();

    [OperationContract]
    BaseClassZ GetSingle();
}

И, используемые здесь 3 договора данных, передаются между клиентом и сервером при импорте определения службы, метод, который возвращает коллекцию, не получает правильные атрибуты известных типов в сгенерированном клиентском прокси. Может быть, это по дизайну.

Другие советы

Я провел часы сегодня на том, что, как лучше, я могу сказать, является той же проблемой. Для меня решение было использовать метод AddGenericResolver от библиотеки сервопривода Idesignerex.

Примечание: .NET 4.0 Требуется, как он использует Datacontractresolver.

Вы можете найти это на IDesign Загрузки Страница.

Все, что мне нужно было сделать в моем случае, было добавить следующую строку кода:

Client.AddGenericResolver( typeof ( K2Source ) );

Я надеюсь, что это поможет кому-то еще, сэкономить несколько часов!

Вы можете найти больше информации в Книге «Программирование WCF Services: Овладение WCF и Azure AppFabric Service Service», Juval Lowy

Есть еще один способ сделать это. Вместо того, чтобы использовать «Добавить ссылку на обслуживание», вы код прокси-классов. Это немного больше кодирования изначально, но дает вам гораздо более стабильное и надежное решение. Мы обнаружили, что это экономит время в США в долгосрочной перспективе.

Видеть: http://www.dnrtv.com/default.aspx?shownum=122.

Примечание. Это только работает, если у вас есть контроль над сервером, так и клиентом.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top