WCF サービス操作から EF4 POCO を返すときに CommunicationException が発生する
-
25-09-2019 - |
質問
次のコードは、 System.ServiceModel.CommunicationException. 。という WCF サービス操作を呼び出しています。 ログイン これは EF4 POCO を返します。
var client = new AuthServiceReference.AuthServiceClient();
try
{
Console.Write("Trying to logon...");
var session = client.Login("user", "password"); // throws CommunicationException
Console.WriteLine("done!");
Console.WriteLine("Session ID: {0}. Expires {1}",
session.Id, session.UtcExpires.ToLocalTime());
}
finally
{
client.Close();
}
解決するために何時間もデバッグと検索を行ってきました なぜ これが起こることとそれを修正する方法。これまでに見つけたこと:
- これはおそらくシリアル化の問題です
- を外すと、 データメンバー属性 から セッション クラスの 所有者 メンバーの場合、例外は消えますが、これはシリアル化されないことを意味します。
誰かがこの問題に光を当ててくれれば幸いです。
以下はサービス コントラクトと POCO クラスのコードです。
[ServiceContract]
public interface IAuthService
{
[OperationContract]
Session Login(string username, string passwordHash);
[OperationContract]
void Logout(Guid sessionId);
}
[DataContract]
public class Session
{
[DataMember]
public Guid Id { get; set; }
[DataMember]
public DateTime UtcCreated { get; set; }
[DataMember]
public DateTime UtcExpires { get; set; }
[DataMember] // serializes correctly if commented out
public virtual User Owner { get; set; }
public static Session Create(User owner)
{
return new Session
{
Owner = owner,
Id = Guid.NewGuid(),
UtcCreated = DateTime.UtcNow,
UtcExpires = DateTime.UtcNow.AddDays(1)
};
}
}
[DataContract]
public class User
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string PasswordHash { get; set; }
[DataMember]
public string PasswordSalt { get; set; }
[DataMember]
public bool IsContributor { get; set; }
[DataMember]
public bool IsConfirmed { get; set; }
[DataMember]
public bool IsAdmin { get; set; }
[DataMember]
public string Email { get; set; }
[DataMember]
public virtual ICollection<Post> Posts { get; set; }
[DataMember]
public virtual ICollection<Comment> Comments { get; set; }
}
解決
WCFとPOCOプロキシをシリアル化するとき、
この結局のところは既知の問題です。 MSDN walkthough には、を使用して、それを回避する方法を説明しているがありますSystem.Data.Objects.ProxyDataContractResolver の
基本的に、あなたはと呼ばれる新しいクラスを作成します。のApplyDataContractResolverAttribute のとPOCOSを返すサービスメソッドに適用します:
[ServiceContract]
public interface IAuthService
{
[OperationContract]
[ApplyDataContractResolver]
Session Login(string username, string passwordHash);
}
<時間>
using System;
using System.Data.Objects;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
namespace WcfExampleBlog.Services
{
public class ApplyDataContractResolverAttribute : Attribute, IOperationBehavior
{
#region IOperationBehavior Members
public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
{
}
public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
{
var dataContractSerializerOperationBehavior =
description.Behaviors.Find<DataContractSerializerOperationBehavior>();
dataContractSerializerOperationBehavior.DataContractResolver =
new ProxyDataContractResolver();
}
public void ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch)
{
var dataContractSerializerOperationBehavior =
description.Behaviors.Find<DataContractSerializerOperationBehavior>();
dataContractSerializerOperationBehavior.DataContractResolver =
new ProxyDataContractResolver();
}
public void Validate(OperationDescription description)
{
// Do validation.
}
#endregion
}
}
他のヒント
私は、「ユーザー」クラスはカスタムクラスであることを前提としていますか?もしそうなら、あなただけのServiceContract属性の下にこれを追加する必要があります:
[KnownType(typeof(User))]
また、セットアップに必要があるでしょうあなたの[DataMemberプロパティ]および[のServiceContract]同様Userクラスの属性ます。
所属していません StackOverflow