2009-08-31 6 views
5

Ich habe eine Anwendung, wo Client und Server teilen Arten und Interoperabilität ist nicht eines unserer Anliegen. Ich plane, ein einzelnes Repository für alle Web-fähigen Objekte zu haben, und ich dachte an eine generische Schnittstelle für meinen exponierten Service.wcf ausgesetzt generics

so etwas wie T GetObject (int id)

aber wcf tut, wie es seit seinem Versuch, das Schema zu belichten (was ich wirklich über dont care)

ist es möglich, so etwas mit WCF zu tun ?, ich kann jede Art von Bindung verwenden müssen nicht Httbinding oder wsbinding ...

+0

Siehe auch http://StackOverflow.com/Questions/6223886/Generic-Service-Interface –

Antwort

2

Ich nehme an, dies möglich ist, aber ich bin nicht sicher, Sie dies wünschen würde. Ich würde den folgenden Ansatz nehmen (ungetestet, nicht sicher, ob es funktioniert).Zunächst erstellen Sie die folgende Projektstruktur in Ihrer Lösung:

  • ServiceInterfaces
  • ServiceImplementations (Referenzen ServiceInterfaces und ModelClasses)
  • ModelClasses
  • Host (Referenzen ServiceInterfaces und ServiceImplementations)
  • Client (Referenzen ServiceInterfaces und ModelClasses)

In ServiceInterfaces Sie verfügen über eine Schnittstelle wie folgt aus (ich die Namensräume übersprungen, etc das Beispiel kürzer zu machen):

[ServiceContract] 
public interface IMyService<T> 
{ 
    T GetObject(int id); 
} 

In ServiceImplementations Sie haben eine Klasse, die implementiert IMyService<T>:

public class MyService<T> : IMyService<T> 
{ 
    T GetObject(int id) 
    { 
     // Create something of type T and return it. Rather difficult 
     // since you only know the type at runtime. 
    } 
} 

In Host haben Sie die richtige Konfiguration für Ihren Dienst in einer App.config (oder Web.config) Datei und den folgenden Code, um Ihren Dienst zu hosten (da es sich um eine eigenständige Anwendung handelt) :

ServiceHost host = new ServiceHost(typeof(MessageManager.MessageManagerService)) 
host.Open(); 

Und schließlich in Client verwenden Sie eine ChannelFactory<TChannel> Klasse einen Proxy zu definieren:

Binding binding = new BasicHttpBinding(); // For the example, could be another binding. 
EndpointAddress address = new EndpointAddress("http://localhost:8000/......"); 
IMyService<string> myService = 
    ChannelFactory<IMyService<string>>.CreateChannel(binding, address); 
string myObject = myService.GetObject(42); 

Wieder bin ich nicht sicher, ob das funktioniert. Der Trick besteht darin, Ihre Serviceschnittstellen (in ServiceInterfaces) und Domänenmodellobjekte (in ModelClasses) zwischen dem Host und dem Client zu teilen. In meinem Beispiel verwende ich eine Zeichenfolge, um von der Service-Methode zurückzukehren, aber es könnte ein beliebiger Datenvertragstyp aus dem Projekt ModelClasses sein.

+0

Ich kann auf die gleichen Assemblys auf dem Client verweisen und die Registerkarte "Advance" des Dienstverweises verwenden (ich rate Svcutil), um Typen zu teilen, das funktioniert, aber jetzt möchte ich machen, ist abstrakt, rate ich bin auf der Suche nach einem Remotint-Typ Lösung, sollte aber möglich sein auf wcf ... –

+0

Sie sollten nicht das 'Add Service Reference' Dialogfeld in Visual Studio für meinen Ansatz verwenden. Das wird nicht funktionieren. Deshalb verwende ich die ChannelFactory Klasse. Es generiert eine Proxy-Implementierung Ihrer Service-Schnittstelle im laufenden Betrieb, ohne dass Metadaten erforderlich sind. –

+0

Dies wird wahrscheinlich nicht funktionieren (ich kann es jetzt nicht testen), da Sie einen Dienst mit Operationen definieren, die einen generischen Typ "T" zurückgeben - aber um richtig zu funktionieren, muss dieser Typ "T" ein sein DataContract, damit der WCF-Stack Objekte dieses Typs serialisieren und deserialisieren kann. Denken Sie daran: Alles, was Sie zwischen Client und Server passieren, sind ** Nachrichten ** - es gibt keine Objektreferenz oder Schnittstellenreferenz oder irgendetwas, das auf Referenzen basiert! Sie ** müssen ** in der Lage sein, Ihre Anfrage in ein Nachrichtenformat zu serialisieren und am anderen Ende wieder zu entserialisieren - das wird nicht mit Generics funktionieren :-( –

8

Nein, können Sie nicht. Unabhängig davon, ob Sie Interoperabilität wünschen oder benötigen, ist die grundlegende Grundlage von WCF der Nachrichtenaustausch.

Der Client sendet dem Server eine Nachricht und erhält eine Antwort zurück. Diese Nachricht wird nur zwischen Client und Server ausgetauscht und muss in ein XML- oder Binärformat serialisierbar sein. Aus diesem Grund müssen alle Daten, die übergeben werden, atomar sein (wie int, string) oder DataContract - eine Beschreibung für den WCF-Service-Stack zum Serialisieren und Deserialisieren solcher Objekte.

Sie können keine Schnittstellen oder andere "Tricks" weitergeben - alles, was zwischen Client und Server geht, muss grundsätzlich im XML-Schema ausgedrückt werden können.

Also ich fürchte, was Sie erreichen wollen, ist ganz im Gegensatz zu dem, was WCF bietet. Die Welt und die Paradigmen von SOA (Service-Oriented Apps) sind sehr unterschiedlich und nicht immer 100% synchron mit der Idee und den Mechanismen von OOP.

Marc

+0

also, wenn jemand dies tun wollte, welche Technologie Stack bietet MS, ist es besser geeignet für Remoting (wenn das noch am Leben ist) ? Frau erweitert Unterstützung für das Teilen von Typen (netcontractserializer usw.) –

+0

Ich weiß nicht, ob es eine aktuelle Lösung für das Remotieren von Objekten gibt - was Sie im Grunde tun möchten. Dieser Ansatz hat seinen Anteil an Problemen, die MS mit WCF zu lösen versucht - aber um sie zu lösen, muss man zu einem vollständig auf Nachrichten basierenden Modell gehen, das mit Schnittstellen und Generika nicht gut funktioniert. Ja, es unterstützt die Freigabe von CONCRETE-Typen - aber definitiv keine Schnittstellen und nicht wirklich Generika. –

0

Sie können das tun, wenn Sie ServiceKnownTypesDiscovery verwenden.

Zum Beispiel:

public static class ServiceKnownTypesDiscovery 
{ 
    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider) 
    { 
     var types = new List<Type>(); 

     foreach (var asmFile in Directory.GetFiles(AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory, "*.dll")) 
     { 
      Assembly asm = Assembly.LoadFrom(asmFile); 
      types.AddRange(asm.GetTypes().Where(p=> Attribute.IsDefined(p,typeof(DataContractAttribute)))); 
     } 

     return types; 
    } 
} 

mit [Datacontract] (so lange erklärt in diesem Fall alles, wie sie auf dem Server auffindbar sind und die:

[ServiceKnownType("GetKnownTypes", typeof(ServiceKnownTypesDiscovery))] 
public interface ISomeService 
{ 
    [OperationContract] 
    object Request(IRequestBase parameters); 
} 

wo GetKnownTypes könnte wie so deklariert werden Client-Seite) kann serialisiert werden.

Ich hoffe, das hat geholfen!

+1

Aber ... deine Lösung verwendet keine Generika –

0

Nach dem vorherigen Beispiel könnten Sie eine DataContract mit einem Objekt als DataMember deklarieren. Dann können Sie eine Erweiterungsmethode hinzufügen, um einen generischen Typ für das Objektdatenelement abzurufen und festzulegen. Sie könnten dies auch intern machen, auf diese Weise wären Sie verpflichtet, die Erweiterungsmethoden zu verwenden, um den Wert zu erhalten und festzulegen.

Natürlich funktioniert es nur, wenn Sie den Client mit svcutil (oder Visual Studio) generieren und verweisen Sie auf die Assembly, die den Datenvertrag und die Klasse mit den Erweiterungen Methoden enthält.

Hoffe das hilft ...