2014-10-23 2 views
0

Я создаю службу RESTful WCF, которая использует EF 6 для доступа к POCOs. Я также использую Ninject и шаблон репозитория для доступа к базе данных. Вот мои настройки службы:Ошибка сериализации WCF с EF 6

Конфигурация

<serviceBehaviors> 
    <behavior name="commonServicebehavior"> 
     <serviceMetadata httpGetEnabled="true" /> 
     <serviceDebug includeExceptionDetailInFaults="true" /> 
    </behavior> 
    </serviceBehaviors> 
    <endpointBehaviors> 
    <behavior name="sbLoginSAS"> 
     <transportClientEndpointBehavior> 
     <tokenProvider> 
      <sharedAccessSignature keyName="RootManageSharedAccessKey" key="oJh2klf242iwISUDcsTQHeR/3W3FlQTQte/M=" /> 
     </tokenProvider> 
     </transportClientEndpointBehavior> 
     <webHttp defaultOutgoingResponseFormat="Json" /> 
     <serviceRegistrySettings discoveryMode="Public" /> 
    </behavior> 

Контракт

[ServiceContract] 
public interface ILoginService 
{ 
    [OperationContract] 
    [WebInvoke(UriTemplate = "")] 
    ErrorCollectionDTO Login(LoginRequestDTO loginRequest); 
} 

Реализация

class LoginService : ILoginService 
{ 
    private readonly ILoginValidator _loginValidator; 
    private readonly IErrorMapper _errorMapper; 
    private readonly IEncryptor _encryptor; 
    private readonly IUserManager _userManager; 

    public LoginService(ILoginValidator loginValidator, IErrorMapper errorMapper, IEncryptor encryptor, IUserManager userManager) 
    { 
     _loginValidator = loginValidator; 
     _errorMapper = errorMapper; 
     _encryptor = encryptor; 
     _userManager = userManager; 
    } 

    public ErrorCollectionDTO Login(LoginRequestDTO loginRequest) 
    { 
     //Validate the request 
     var completeSummary = _loginValidator.Validate(loginRequest); 

     //Maps validation errors to a response DTO 
     var errorCollectionDTO = _errorMapper.Transform(completeSummary); 

     //If request not valid, return errors 
     if (!errorCollectionDTO.IsValid) return errorCollectionDTO; 

     //At this point, user is correctly authenticated 
     //so we prepare and send him an authorization token 
     var user = _userManager.GetUser(loginRequest.CPR); 
     var token = _encryptor.Encrypt(loginRequest.CPR); 

     user.SecurityToken = new SecurityToken 
     { 
      Token = token, 
      ValidUntil = DateTime.Now.AddMinutes(5) 
     }; 

     _userManager.UpdateUser(user); 

     return new LoginResponseDTO(errorCollectionDTO, token.ToString()); 
    } 

Я использую DTO для всех запросов и ответов, которые все используют атрибуты [DataContract]/[DataMember]. Служба принимает запрос JSON должным образом. Однако я получаю сообщение об ошибке в строке:

var completeSummary = _loginValidator.Validate(loginRequest); 

, когда вызывающий метод пытается получить записи из объекта через его хранилище с _userManager.GetUser (entity.CPR):

private IEnumerable<IError> ValidateEntity(LoginRequestDTO entity) 
    { 
     if (entity == null) 
      yield return new Error("Login request was null or invalid"); 
     else 
     { 
      var user = _userManager.GetUser(entity.CPR); 

      if (user == null) 
       yield return new Error("User doesn't exist or password is wrong"); 
     } 
    } 


Type 'System.Data.Entity.DbSet`1[ITU.MAP.Domain.Model.User]' cannot be serialized. 
Consider marking it with the DataContractAttribute attribute, and marking all of its 
members you want serialized with the DataMemberAttribute attribute. If the type is 
a collection, consider marking it with the CollectionDataContractAttribute. 

Что касается как я понимаю, WCF пытается сериализовать записи db, вызываемые методом. Я думал, что это не должно быть проблемой, так как я использую DTO для ответов, и это не так близко к построению ответа. Я гугле вокруг, и я попробовал некоторые решения, такие как

Configuration.ProxyCreationEnabled = false; 

и

Configuration.LazyLoadingEnabled = false; 

, но они не работали. Конечно, я также добавил атрибуты DataContract и DataMember ко всем моим POCOs, поскольку сообщение об ошибке указывает, но безрезультатно.

Обновление: Вот POCO, который WCF пытается сериализовать. Я также пробовал с другими, не абстрактными классами, украшенными только [DataContract] и [DataMember], но та же ошибка возникает. Типы детей в KnownType также правильно оформлены с указанными выше атрибутами.

[DataContract(IsReference = true)] 
[KnownType(typeof(Paramedic))] 
[KnownType(typeof(Resident))] 
[Table("Users")] 
public abstract class User : IIdentifiable 
{ 
    [Key] 
    [DataMember] 
    [DisplayName("Id")] 
    public int Id { get; set; } 

    [DataMember] 
    [DisplayName("CPR")] 
    public string CPR { get; set; } 

    [DataMember] 
    [DisplayName("Password hash")] 
    public byte[] Password { get; set; } 

    [DataMember] 
    [DisplayName("Name")] 
    public string Name { get; set; } 

    [DataMember] 
    [DisplayName("Surname")] 
    public string Surname { get; set; } 

    [DataMember] 
    [DisplayName("Region")] 
    public int RegionId { get; set; } 

    [DataMember] 
    [DisplayName("Region")] 
    [ForeignKey("RegionId")] 
    public virtual Region Region { get; set; } 

    [DataMember] 
    [DisplayName("Age")] 
    public int Age { get; set; } 

    [DataMember] 
    [DisplayName("Blood type")] 
    public BloodType BloodType { get; set; } 

    [DataMember] 
    [DisplayName("Rhesus")] 
    public Rhesus Rhesus { get; set; } 

    [DataMember] 
    public int? SecurityTokenId { get; set; } 

    [DataMember] 
    [DisplayName("Security token")] 
    [ForeignKey("SecurityTokenId")] 
    public virtual SecurityToken SecurityToken { get; set; } 

    [DataMember] 
    public virtual ICollection<Allergy> Allergies { get; set; } 

    [DataMember] 
    public virtual ICollection<Condition> Conditions { get; set; } 

    [DataMember] 
    public virtual ICollection<Prescription> Prescriptions { get; set; } 
} 

ответ

0

Похоже, что WCF не может сериализовать тип IQueryable, который я использовал в своих методах класса универсального репозитория, чтобы возвращать коллекции результатов базы данных. Он работал с использованием List вместо этого, что очень неприятно, если вы спросите меня. Если у кого-то есть лучшее предложение, чем использование списка, пожалуйста, упомяните об этом.

0

Попробуйте украсить класс контрактом на данные и свойствами с атрибутами элементов данных.

+0

Из сообщения OP: «Я также добавил атрибуты DataContract и DataMember ко всем моим POCOs, поскольку сообщение об ошибке указывает, но безрезультатно». – Tim

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