Domanda

Ho il seguente:

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

Quando eseguo il metodo Get ottengo il seguente errore:

  

Si è verificato un errore durante il tentativo di serializzare parametro http://tempuri.org/:GetResult . Il messaggio era InnerException 'Tipo' PPS.Core.DomainModel.Support.Action.ActionResult`1 [[PPS.Core.DomainModel.SportProgram.ISportProgram, PPS.Core.DomainModel, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null]] 'con il nome del contratto di dati' ActionResultOfanyType: http: // schemas.datacontract.org/2004/07/PPS.Core.DomainModel.Support.Action ' non è previsto. Aggiungere tutti i tipi non noti staticamente alla lista dei tipi conosciuti - per esempio, utilizzando l'attributo KnownTypeAttribute o aggiungendoli alla lista dei tipi conosciuti passati a DataContractSerializer '.. Si prega di consultare InnerException per maggiori dettagli.

Da questo errore posso vedere che si può risolvere ActionResult ma non può risolvere ISportProgram anche se ho ServiceKnownType (typeof (ActionResult )) sulla mia interfaccia di servizio ...

Nota: questo è lo stub di riferimento che viene generato assomiglia a questo, così posso vedere che i tipi noti vengono portati in tutto correttamente:

[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);
}

Perché questo andando male ???? Nota la sua sempre attraverso il servizio WCF in modo corretto ... ma genera l'eccezione quando il risultato viene restituito.

Infine ActionResult assomiglia a questo:

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

Saluti Anthony

È stato utile?

Soluzione

Bene, credo che questo sia un altro caso della SOA o OOP "disadattamento di impedenza". I due mondi sono nettamente distinte.

In WCF, tutto ciò che viene passato dal client al server viene passato come messaggi serializzati -. Non ci sono riferimenti vengono usati

Ciò significa: tutto ciò che si vuole serializzare sul client, inviarlo attraverso al server, e deserializzare e usarlo lì, deve essere cemento - non è possibile passare in giro le interfacce, non è possibile utilizzare generici "non risolto" - è necessario chiarirne il significato. In pratica, tutto ciò che è stato passato dal client sul filo per il server deve essere esprimibile in schema XML.

Questo ha un sacco di implicazioni:

  • Non ci sono interfacce - non si può passare intorno interfacce - è necessario lavorare con i tipi concreti
  • nessuna eredità "automatico" - non si può solo definire una classe base e passare classi intorno derivate basate su di esso - quelli devono essere specificied troppo (che è quello che l'attributo ServiceKnownType è per)
  • Non ci sono farmaci generici automatici - ancora una volta, è necessario utilizzare tipi concreti al posto

Questo può sembrare un sacco di restrizioni - ma è perché WCF sta usando tutta la comunicazione basata su messaggi - non può che fare con REFERENZE, ereditarietà, farmaci generici, ecc - è necessario chiarirne il significato

.

Quindi in realtà non hanno una risposta per voi in sé -. Penso solo che è necessario ripensare la vostra strategia e cambiare il modo in cui il client e il server si scambiano informazioni su WCF

Marc

PS: ho fatto qualche ricerca più, e contrariamente a tutta la mia comprensione, sembra che ci sia un modo per serializzare tutto ciò che si basa su un'interfaccia e / o classe di base astratta attraverso il filo, fino a quando si può essere sicuri che sia sempre solo NET su entrambe le estremità del filo (cioè è non interoperabile con es Java).

Aaron Skonnard blog post sul NetDataContractSerializer e un altro post sul blog e ancora un altro che mostrano come utilizzare il NetDataContractSerializer per essere in grado passare intorno le cose come IPerson come parametri ai vostri metodi.

Altri suggerimenti

Questo è uno dei problemi che ho risolvere con ServiceStack.NET - My Open Source .NET e Web MONO Services Framework.

Servizio Stack è stato fortemente influenzato da modello Martin Fowlers Data Transfer Object in quanto ti permette di semplicemente utilizzare DTO per definire i servizi web - vale a dire il modo in cui SOA:.)

evito questa limitazione che è insito in WCF generando mia WSDL di che si comportano come ci si aspetterebbe loro di. Come un vantaggio di sostituire / modello di configurazione complessa di WCF di ServiceContract - I servizi SOAP web funziona anche su Mono - vedi il live demo .

E 'una vecchia questione e, anche se la risposta accettata è del tutto corretto, ho stumpled su questo nella ricerca di un problema simile e pensavo di poter condividere le mie esperienze. E 'spesso un mal di testa, ma è possibile utilizzare farmaci generici in combinazione con le interfacce con WCF. Ecco un esempio di lavoro di un'altra implementazione (simile) che ho fatto:

[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 chiave qui è quello di utilizzare la combinazione di KnownType e ServiceKnownType.

Quindi nel tuo caso si può fare qualcosa di simile:

[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; }
}

Ciò funzionerà se si dispone di un contratto condiviso (l'accesso all'interfaccia di servizio effettivo) e consumare il contratto con ChannelFactory<ISportProgramBl>. Non so se funziona con un servizio di riferimento.

Tuttavia, sembra esserci alcuni problemi con l'attuazione, come indicato qui:

WCF Con un'interfaccia e un modello generico

E un'altra domanda simile chiesto e ha risposto qui:

tipi restituiti generici con il tipo di interfaccia params in WCF

si restituisce un IList di T. E 'forse che il sistema ha problemi di scoprire ciò che T è.

Non è sicuro se è ok per tornare un'interfaccia piuttosto che un tipo.

Si sta specificate le interfacce negli oggetti e non tipi concreti?

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

Modifica:

Quello che sto dicendo è che sono tutti i tipi concreti che si stanno passando i farmaci generici (anche in sub oggetto tramite interfacce) essere passato nella lista di tipi conosciuti. Abbiamo avuto problemi serialasation dove tutti i tipi non erano noti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top