2009-03-25 2 views
12

Я ищу создание службы 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 и получить их обратно в качестве типа ребенка от RetrieveObject метод.

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

Спасибо, Роб

ответ

17

Ваш пример не скомпилируется, поскольку интерфейсы не могут содержать поля, что и 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 на стороне клиента вручную.

+0

Возможно ли вам составить конкретный пример того, как использовать интерфейс IEmployee, который вы упомянули, с WCF? – Kenci

+0

@Matt Дэвис, одна вещь отсутствует :) Может быть, какой-то кусок xml? – 2017-02-16 17:46:52