Подтвердить что ты не робот

Полиморфизм в WCF

Я ищу создание службы WCF, которая может хранить/извлекать ряд различных типов. Является ли следующий пример работоспособным и считается приемлемым:

[ServiceContract]
public interface IConnection
{        
   [OperationContract]
    IObject RetrieveObject(Guid ObjectID); 

   [OperationContract]
    Guid StoreObject(IObject NewObject); 


}

[ServiceContract]
[ServiceKnownType(IOne)]
[ServiceKnownType(ITwo)]
public interface IObject
{
    [DataMember]
    Guid ObjectID;

}

[ServiceContract]
public interface IOne:IObject
{
    [DataMember]
    String StringOne;

}

[ServiceContract]
public interface ITwo:IObject
{
    [DataMember]
    String StringTwo;

}

При использовании службы мне нужно будет передать дочерние типы в метод StoreObject и вернуть их в качестве своего типа Child из метода RetrieveObject.

Есть ли лучшие варианты?

Спасибо, Rob

4b9b3361

Ответ 1

Ваш пример не будет компилироваться, потому что интерфейсы не могут содержать поля, которые являются объектами ObjectID, StringOne и StringTwo. То, что вы пытаетесь определить с помощью IObject, IOne и ITwo, - это контракт с данными, а не контракт на обслуживание. Таким образом, вы должны использовать атрибут DataContract, а не атрибут ServiceContract и классы, а не интерфейсы.

[DataContract]
[KnownType(typeof(MyOne))]
[KnownType(typeof(MyTwo))]
public class MyObject
{
    [DataMember]
    Guid ObjectID;
}
[DataContract]
public class MyOne : MyObject
{
    [DataMember]
    String StringOne;
}
[DataContract]
public class MyTwo : MyObject
{
    [DataMember]
    String StringTwo;
}

Обратите внимание, что это классы, а не интерфейсы. Атрибут DataContract заменил атрибут ServiceContract. Атрибут KnownType заменил атрибут ServiceKnownType. Это более канонично из того, что я видел.

Тогда ваш контракт на обслуживание будет определен следующим образом:

[ServiceContract]
public interface IConnection
{
    [OperationContract]
    [ServiceKnownType(typeof(MyOne))]
    [ServiceKnownType(typeof(MyTwo))]
    MyObject RetrieveObject(Guid ObjectID);

    [OperationContract]
    [ServiceKnownType(typeof(MyOne))]
    [ServiceKnownType(typeof(MyTwo))]
    Guid StoreObject(MyObject NewObject);
}

Вы можете поместить атрибуты ServiceKnownType на уровне контракта (т.е. под атрибутом ServiceContract), чтобы применить его ко всем операциям контракта.

[ServiceContract]
[ServiceKnownType(typeof(MyOne))]
[ServiceKnownType(typeof(MyTwo))]
public interface IConnection
{
    [OperationContract]
    MyObject RetrieveObject(Guid ObjectID);

    [OperationContract]
    Guid StoreObject(MyObject NewObject);
}

Вы можете использовать интерфейсы в ваших контрактах данных следующим образом:

interface IEmployee
{
    string FirstName
    { get; set; }
    string LastName
    { get; set; }
}
[DataContact]
class Employee : IEmployee
{...}

Однако интерфейс IEmployee не включен в экспортированные метаданные. Поэтому, если вы используете svcutil для генерации ваших прокси-классов, ваши клиенты не будут знать об IEmployee. Это не имеет большого значения, если ваш сервис и клиент находятся в одном приложении (что является хорошим способом общения между доменами приложений). Однако, если ваш клиент отделен от вашей службы (в подавляющем большинстве случаев это будет), это становится проблематичным, потому что вам придется дублировать интерфейс IEmployee на стороне клиента вручную.