2011-09-21 4 views
2

Сценарий:Как сериализовать вложенные типы в ответе WCF?

Я нахожусь в процессе создания службы WCF, который предоставляет пользовательские данные. Экземпляр пользователя имеет свойство «Роль». Если я опускаю это свойство, служба работает; если не опустить свойство, служба терпит неудачу. Ниже приведено (очень) упрощенное представление кода.

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1, EmitConformanceClaims = true)] 
[ServiceContract(Name = "IService", Namespace = "http://local/version1/")] 
public interface IService : IDisposable 
{ 
    [WebMethod] 
    [SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)] 
    [OperationContract(Action = "http://local/version1/GetUser")] 
    GetUserResponse GetUser(GetUserRequest request); 
} 

[MessageContract(IsWrapped = true, WrapperName = "GetUserResponse")] 
[XmlRoot("GetUserResponse")] 
public class GetUserResponse 
{ 
    [XmlElement(ElementName = "User")] 
    [MessageBodyMember(Order = 0)] 
    public User User { get; set; } 
} 

public class User 
{ 
    public int UserId { get; set; } 

    public string UserName { get; set; } 

    public Role Role { get; set; } 
} 

public class Role 
{ 
    public string Name { get; set; } 
} 

Корень проблемы заключается в том, что роль является вложенной/встроенным (как вы это называете ...) в классе User. Кажется, он не может быть сериализован таким образом.

Если поиск по возможным решениям, но не может найти правильное решение. Я пробовал что-то с KnownTypeAttribute в контракте, а также в классе User, но это не сработало.

Вопросы:

  • Что такое правильный способ включить свойство Role на классе User?
  • Какие атрибуты необходимо добавить, где это сделать?
  • Возможные интерфейсы для реализации сериализации?

Заранее благодарим за любые ответы!

Update # 1

После предложений @CPX, я создал дополнительный тестовый код на стороне сервера:

using (StringWriter stringWriter = new StringWriter()) 
{ 
    XmlSerializer serializer = new XmlSerializer(typeof(GetUserResponse)); 
    serializer.Serialize(stringWriter, response); 
    string result = stringWriter.ToString(); 
} 

Это приводит к InvalidOperationException с сообщением «Была ошибка порождающей XML-документ ". Это исключение имеет InvalidOperationException (снова) как InnerException, с сообщением «Тип System.Data.Entity.DynamicProxies.User_FAC9CE2C5C9966932C0C37E6677D35437C14CDD08 884AD33C546805E62B7101E не ожидался. Используйте атрибуты XmlInclude или SoapInclude, чтобы указать типы, которые не известны статически. '.

Забыл упомянуть в сообщении, что классы пользователя и роли используются в Entity Framework 4.1. Не догадывалась, должно быть, проблема, но, видимо, это так.

+0

Просьба дать описание того, как служба не работает. Какое исключение вы получаете? –

+0

Вы пытались поместить атрибут [DataContract] и [DataMember]? –

+0

Вы должны добавить атрибуты DataContract и DataMember – meziantou

ответ

2

Возможно, что-то связано с созданием прокси.

Попробуйте установить следующее: context.ContextOptions.ProxyCreationEnabled = false;

+0

Как указано в «Обновлении №1» в начале сообщения, я забыл упомянуть, что я использовал Entity Framework. Только когда я протестировал процесс сериализации (см. Также «Обновление №1»), я обнаружил, что это как-то связано с Entity Framework. Это правило кода, которое вы предлагаете, является именно таким решением! Он не генерирует никаких дополнительных классов на основе User/Role. Дело только в том, что вы должны включать объект «Роль» при запросе. –

0

Добавить DataContract атрибуты классов и DataMember атрибуты каждого свойства вы хотите сериализовать

1
[DataContract] 
    public class User { 

    [DataMember] 
    public int UserId { get; set; }  

    [DataMember] 
    public string UserName { get; set; } 

    [DataMember]  
    public Role role { get; set; } } 

    [DataContract] 
    public class Role 
    { 
     [DataMember] 
     public string Name { get; set; } 
    } 
+0

Я попробую это. –

+0

Я пробовал это решение. К сожалению, он имеет те же результаты. –

+0

Попробуйте изменить роль Роль в роли Роль –

2

Вам нужно будет сделать User и Role DataContracts так:

[DataContract] 
public class User 
{ 
    [DataMember] 
    public int UserId { get; set; } 

    [DataMember] 
    public string UserName { get; set; } 

    [DataMember] 
    public Role Role { get; set; } 
} 

[DataContract] 
public class Role 
{ 
    [DataMember] 
    public string Name { get; set; } 
} 

Это позволяет WCF знать как и что сериализуем. Существует пример смешивания MessageContract и DataContract, как вы это делаете в своем случае, на MSDN здесь: http://msdn.microsoft.com/en-us/library/ff648210.aspx

+0

Немного другой ответ, чем у @GregoryNozik. Я пробовал это, но также у меня такие же результаты, как и без ... Думаю, я что-то пропускаю, но не знаю, что. –

+0

Окончательное решение может быть выполнено полностью без атрибутов DataContract/DataMember в классах User/Role. Однако мне нравится ваш пост, и ссылка MSDN объясняет это также очень хорошо. –

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

  • Нет связанных вопросов^_^