Question

Le code suivant soulève un System.ServiceModel.CommunicationException . Qu'il appelle une opération de service WCF appelé Connexion qui retourne un 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();
        }

J'ai été mise au point et la recherche d'heures à essayer de trouver pourquoi cela arrive et comment y remédier. Ce que j'ai trouvé à ce jour:

  1. Ceci est probablement un problème de sérialisation
  2. Lorsque je supprime DataMemberAttribute de la Session classe de propriétaire membre, l'exception disparaît, mais cela signifie qu'il ne sera pas publié en feuilleton.

Je serais reconnaissant si quelqu'un pouvait faire la lumière sur cette question.

Voici le code pour le contrat de service et les classes 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; }
}
Était-ce utile?

La solution

Transforme c'est un problème connu lors de la sérialisation procurations POCO avec WCF. Il y a un MSDN soluce qui explique comment contourner en utilisant System.Data.Objects.ProxyDataContractResolver .

Pour l'essentiel, vous créez une nouvelle classe appelée ApplyDataContractResolverAttribute et l'appliquer aux méthodes de service retour 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
    }
}

Autres conseils

Je suppose que la classe « User » est une classe personnalisée? Si oui, vous devez ajouter ce juste au-dessous de l'attribut ServiceContract:

[KnownType(typeof(User))]

Vous devez également configurer votre [DataMember] et [ServiceContract] attributs sur la classe utilisateur ainsi.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top