WCF サービス操作から EF4 POCO を返すときに CommunicationException が発生する

StackOverflow https://stackoverflow.com/questions/4605910

質問

次のコードは、 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();
        }

解決するために何時間もデバッグと検索を行ってきました なぜ これが起こることとそれを修正する方法。これまでに見つけたこと:

  1. これはおそらくシリアル化の問題です
  2. を外すと、 データメンバー属性 から セッション クラスの 所有者 メンバーの場合、例外は消えますが、これはシリアル化されないことを意味します。

誰かがこの問題に光を当ててくれれば幸いです。

以下はサービス コントラクトと 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クラスの属性ます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top