Я создаю службу 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; }
}
Из сообщения OP: «Я также добавил атрибуты DataContract и DataMember ко всем моим POCOs, поскольку сообщение об ошибке указывает, но безрезультатно». – Tim