Question

Je donne les résultats suivants:

[ServiceContract]
[ServiceKnownType(typeof(ActionParameters))]
[ServiceKnownType(typeof(SportProgram))]
[ServiceKnownType(typeof(ActionResult<SportProgram>))]
public interface ISportProgramBl  
{
    [OperationContract]
    IActionResult<ISportProgram> Get(IActionParameters parameters);
}

Quand je lance la méthode Get je reçois l'erreur suivante:

  

Il y avait une erreur en essayant de paramètre sérialisation http://tempuri.org/:GetResult . Le message InnerException était 'Type' PPS.Core.DomainModel.Support.Action.ActionResult`1 [[PPS.Core.DomainModel.SportProgram.ISportProgram, PPS.Core.DomainModel, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null]] 'avec le nom de contrat de données' ActionResultOfanyType: http: // schemas.datacontract.org/2004/07/PPS.Core.DomainModel.Support.Action » est pas prévu. Ajoutez tous les types ne sont pas connus statiquement à la liste des types connus - par exemple, en utilisant l'attribut KnownTypeAttribute ou en les ajoutant à la liste des types connus transmis à DataContractSerializer.. S'il vous plaît voir InnerException pour plus de détails.

De cette erreur, je peux voir qu'il peut résoudre ActionResult mais il ne peut pas résoudre ISportProgram même si je ServiceKnownType (typeof (ActionResult )) sur mon interface de service ...

Notez que c'est le talon de référence qui est généré ressemble à ceci, je peux voir que les types connus sont amenés à travers correctement:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="SportProgramStb.ISportProgramBl")]
public interface ISportProgramBl {

    [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ISportProgramBl/Get", ReplyAction="http://tempuri.org/ISportProgramBl/GetResponse")]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(PPS.Core.DomainModel.SportProgram.SportProgram))]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(PPS.Core.DomainModel.Support.Action.ActionParameters))]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(PPS.Core.DomainModel.Support.Action.ActionResult<PPS.Core.DomainModel.SportProgram.SportProgram>))]
    object Get(object parameters);
}

Pourquoi est-ce que ça va mal ???? Notez le faire par le service WCF correctement ... mais il lève l'exception lorsque le résultat est retourné.

Enfin ActionResult ressemble à ceci:

public interface IActionResult<T> 
{
    T Result { get; set; } 
}

Vive Anthony

Était-ce utile?

La solution

Eh bien, je pense que cela est un autre cas de la « différence d'impédance » SOA par rapport à la POO. Les deux monde sont tout à fait séparés.

Dans WCF, tout ce qui est transmis du client au serveur est passé comme messages sérialisés -. Pas de références sont utilisées

Cela signifie: tout ce que vous voulez sérialisation sur le client, l'envoyer sur le serveur, et désérialiser et l'utiliser là, doit être Béton - vous ne pouvez pas passer autour des interfaces, vous ne pouvez pas utiliser génériques « non résolus » - vous devez le préciser. En gros, tout ce qui est transmis d'client sur le fil au serveur doit être exprimable dans le schéma XML.

Cela a beaucoup de conséquences:

  • aucune interface - vous ne pouvez pas passer autour des interfaces - vous devez travailler avec des types concrets
  • pas d'héritage « automatique » - vous ne pouvez pas définir simplement une classe de base et de transmettre les classes autour de dérivés sur cette base - ceux qui ont besoin d'être specificied aussi (c'est ce que l'attribut est ServiceKnownType pour)
  • pas de génériques automatique - encore une fois, vous avez besoin d'utiliser des types de béton à la place

Cela peut sembler beaucoup de restrictions - mais il est parce que WCF est en utilisant toutes les communications à base de messages - il ne peut pas traiter refereces, héritage, etc. génériques - vous devez le préciser

.

Je n'ai pas vraiment une réponse pour vous en tant que tel -. Je pense que vous avez besoin de repenser votre stratégie et changer la façon dont votre client et le serveur échangent des informations sur WCF

Marc

PS: Je l'ai fait quelques recherches, et contrairement à toute ma compréhension, il semble y avoir un moyen de sérialisation tout ce qui est basé sur une interface et / ou classe de base abstraite à travers le fil, aussi longtemps que vous pouvez être sûr qu'il est toujours que .NET à chaque extrémité du fil (il est pas interopérable avec par exemple Java).

Voir Aaron Skonnard blog sur le NetDataContractSerializer et un autre poste href="http://www.thoughtshapes.com/WCF/UsingInterfacesAsParametersTwo.htm" et encore une autre montrant comment utiliser le NetDataContractSerializer pour être en mesure de passer autour des choses comme IPerson en tant que paramètres à vos méthodes.

Autres conseils

Ceci est l'un des problèmes que je résous avec ServiceStack.NET - My Open Source .NET et MONO Web services Framework.

Service Stack a été fortement influencée par car il vous permet simplement utilisons DTO pour définir vos services web - à savoir la façon SOA.)

J'évite cette limitation qui est inhérent à la WCF en générant mon propre WSDL de qui se comportent comme vous les attendre à. Comme un avantage de remplacer la configuration complexe / modèle de ServiceContract de WCF - Les services Web SOAP fonctionne également sur MONO -

Il est une question ancienne et même si la réponse acceptée est tout à fait correct, je stumpled sur ce dans la recherche d'un problème et similaire pensé que je pouvais partager mes expériences. Il est souvent un mal de tête, mais il est possible d'utiliser les génériques combinés avec des interfaces avec WCF. Voici un exemple de travail d'une autre mise en œuvre (similaire) que je l'ai fait:

[ServiceContract]
[ServiceKnownType(typeof(CollectionWrapper<IAssociation>))]
public interface IService : 
{
    [OperationContract]
    ICollectionWrapper<IAssociation> FindAssociation(string name, int pageSize, int page);
}

public interface ICollectionWrapper<TModel>
{
    int TotalCount { get; set; }
    IEnumerable<TModel> Items { get; set; }
}

[KnownType(typeof(OrganizationDto))]
[KnownType(typeof(CompanyDto))]
public class CollectionWrapper<TModel> : ICollectionWrapper<TModel>
{
    [DataMember]
    public int TotalCount { get; set; }
    [DataMember]
    public IEnumerable<TModel> Items { get; set; }
}

public class CompanyDto :  IAssociation
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class OrganizationDto :  IAssociation
{
    public int Id { get; set; }
    public string Name { get; set; }
}

La clé ici est d'utiliser la combinaison de KnownType et ServiceKnownType.

Dans votre cas, vous pouvez faire quelque chose comme ceci:

[ServiceContract]
[ServiceKnownType(typeof(ActionParameters))]
[ServiceKnownType(typeof(ActionResult<ISportProgram>))] // Actual implementation of container, but interface of generic.
public interface ISportProgramBl  
{
    [OperationContract]
    IActionResult<ISportProgram> Get(IActionParameters parameters);
}

[KnownType(typeof(SportProgram))] // Actual implementation here.
public class ActionResult<T>
{
    // Other stuff here
    T FooModel { get; set; }
}

Cela fonctionne si vous avez un contrat partagé (accès à l'interface de service réel) et consommer le contrat avec ChannelFactory<ISportProgramBl>. Je ne sais pas si cela fonctionne avec une référence de service.

Cependant, il semble y avoir quelques problèmes avec la mise en œuvre comme mentionné ici:

WCF Avec une interface et un modèle générique

Et une autre question similaire de réponse ici:

types de retour générique avec le type d'interface params dans WCF

Vous retournez un IList de T. Il se peut que le système a des difficultés à trouver ce que T est.

Je ne sais pas s'il est autorisé à retourner une interface plutôt qu'un type.

interfaces spécifions-vous dans les objets et non types concrets?

PPS.Core.DomainModel.Support.Action.ActionListResult<IList<PPS.Core.DomainModel.SportProgram.ISportProgram>>

Edit:

Ce que je veux dire, est-ce que sont tous les types de béton que vous passez dans les génériques (y compris dans l'objet sous via des interfaces) qui sont transmises dans la liste des types connus. Nous avons eu des problèmes de serialasation où tous les types ne sont pas connus.

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