WCF: Является сериализация дженерика возможными интерфейсами?

Я пытаюсь реализовать контракт на обслуживание, который содержит метод, который берет универсальный интерфейс, и что самому универсальному интерфейсу дают интерфейсный параметр. Я украсил сервисный интерфейс ServiceKnownType, я украсил реализацию услуги обычным KnownType, и я украсил datacontract реализацию обычным KnownType:

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ICallbacks))]
[ServiceKnownType(typeof(Batch<object>))]
[ServiceKnownType(typeof(Command))]
public interface IActions
{
    [OperationContract]
    IResponse TakeAction(IBatch<ICommand> commands);
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)]
[KnownType(typeof(Batch<object>))]
[KnownType(typeof(Command))]
internal class Actions : IActions
{
}

[DataContract]
[KnownType(typeof(Command))]
public class Batch<T> : IBatch<T>
{
}

Для записи у меня есть Пакет там, потому что кажется, что можно только выразить knowntype для универсального типа однажды - это, кажется, испускает BatchOfanyType, но я не уверен, как обработать это.

Исключение, которое я получаю, - то, " Добавьте, что любые типы, не известные статически списку известных типов - например, при помощи атрибута KnownTypeAttribute или путем добавления их к списку известных типов, передали DataContractSerializer".

Действительно ли там что-нибудь очевидно, что я делаю неправильно? Универсальные интерфейсы интерфейсов просто не поддерживаются? Для записи я нахожусь на C# 2.0 и.NET 3.0 для этого проекта.

6
задан John Saunders 26 July 2010 в 18:25
поделиться

4 ответа

Вы можете использовать интерфейсы в определениях контрактов на обслуживание, если действительно хотите, при условии, что вы включаете известные типы, как вы это делаете (с небольшой корректировкой, см. Ниже).

По всей видимости, использование интерфейса в качестве параметра универсального типа слишком далеко отходит от C # 3.0. Я изменил атрибут известного типа на

[ServiceKnownType(typeof(Batch<Command>))]
public interface IActions
{
}

, что заставляет его работать до определенной степени. Сериализация и десериализация будут работать, но тогда вы столкнетесь с этим исключением:

Невозможно преобразовать объект типа 'Batch`1 [Command]' набрать 'IBatch`1 [ICommand]'.

Для того, чтобы это приведение работало, вам нужна языковая поддержка ковариантности универсального типа, которая появилась в C # 4.0. Однако, чтобы он работал в C # 4.0, вам нужно добавить модификатор дисперсии:

public interface IBatch<out T>
{
}

Тогда он работает отлично ... к сожалению, вы не используете C # 4.0.

И последнее, что касается использования интерфейсов в контракте службы: если вы генерируете ссылку на службу из них, он будет вводить все параметры интерфейса как объект , поскольку исходный тип интерфейса не является частью метаданных. Вы можете обмениваться контрактами через ссылку на сборку или вручную реорганизовать сгенерированный прокси, чтобы исправить это, но в целом использование интерфейсов с WCF, вероятно, больше проблем, чем оно того стоит.

12
ответ дан 8 December 2019 в 14:39
поделиться

WCF - это система, основанная на сообщениях SOA - она может посылать что угодно по проводам в сериализованном формате XML, который может быть выражен в XML-схеме.

К сожалению, XML-схема не знает ни интерфейсов, ни дженериков, так что нет - вы не можете сериализовать их в общем виде - вам нужно использовать конкретные типы.

2
ответ дан 8 December 2019 в 14:39
поделиться

Вы не можете сериализовать интерфейс. Интерфейс просто определяет контракт, а не объект. Думаю, единственным исключением из этого правила является интерфейс ISerializable.

1
ответ дан 8 December 2019 в 14:39
поделиться

Универсальные шаблоны можно сериализовать, но с некоторыми ограничениями. Например, с учетом контракта данных:

[DataContract]
public class Foo<T>
{
     [DataMember]
     public T Value { get; set; }
}

И контракта службы:

[ServiceContract]
public interface IService1
{
     [OperationContract]
     Foo<String> GetData();
}

И реализации службы:

public class Service1 : IService1
{
   public Foo<string> GetData()
   {
       return new Foo<string>() { Value = "My test string" };
   }
}

После установки ссылки на службу для указанной выше службы можно запустить этот код:

ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();

ServiceReference1.FooOfstring temp = client.GetData();

MessageBox.Show(temp.Value);

И окно сообщения с "Моя тестовая строка" отображается.

Обратите внимание, что сама служба не является универсальной, но используется контракт данных. Кроме того, контракт данных, сгенерированный на стороне клиента, не является универсальным, а скорее является «сплющенным» классом, который имеет значение свойства типа строка:

[System.Runtime.Serialization.DataMemberAttribute()]
public string Value 
{ 
   get {...} 
   set {...} 
}
1
ответ дан 8 December 2019 в 14:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: