Ich habe einen WCF-Dienst und möchte ihn sowohl als RESTfull-Dienst als auch als SOAP-Dienst verfügbar machen. Hat jemand so etwas schon mal gemacht?
Ich habe einen WCF-Dienst und möchte ihn sowohl als RESTfull-Dienst als auch als SOAP-Dienst verfügbar machen. Hat jemand so etwas schon mal gemacht?
Antworten:
Sie können den Dienst an zwei verschiedenen Endpunkten verfügbar machen. Der SOAP kann die Bindung verwenden, die SOAP unterstützt, z. B. basicHttpBinding, der RESTful kann die webHttpBinding verwenden. Ich gehe davon aus, dass sich Ihr REST-Service in JSON befindet. In diesem Fall müssen Sie die beiden Endpunkte mit der folgenden Verhaltenskonfiguration konfigurieren
<endpointBehaviors>
<behavior name="jsonBehavior">
<enableWebScript/>
</behavior>
</endpointBehaviors>
Ein Beispiel für die Endpunktkonfiguration in Ihrem Szenario ist
<services>
<service name="TestService">
<endpoint address="soap" binding="basicHttpBinding" contract="ITestService"/>
<endpoint address="json" binding="webHttpBinding" behaviorConfiguration="jsonBehavior" contract="ITestService"/>
</service>
</services>
Der Service wird also unter verfügbar sein
Wenden Sie [WebGet] auf den Betriebsvertrag an, um ihn RESTful zu machen. z.B
public interface ITestService
{
[OperationContract]
[WebGet]
string HelloWorld(string text)
}
Wenn sich der REST-Service nicht in JSON befindet, dürfen die Parameter der Operationen keinen komplexen Typ enthalten.
Für einfaches altes XML als Rückgabeformat ist dies ein Beispiel, das sowohl für SOAP als auch für XML funktionieren würde.
[ServiceContract(Namespace = "http://test")]
public interface ITestService
{
[OperationContract]
[WebGet(UriTemplate = "accounts/{id}")]
Account[] GetAccount(string id);
}
POX-Verhalten für REST Plain Old XML
<behavior name="poxBehavior">
<webHttp/>
</behavior>
Endpunkte
<services>
<service name="TestService">
<endpoint address="soap" binding="basicHttpBinding" contract="ITestService"/>
<endpoint address="xml" binding="webHttpBinding" behaviorConfiguration="poxBehavior" contract="ITestService"/>
</service>
</services>
Der Service wird unter verfügbar sein
REST-Anfrage versuchen Sie es im Browser,
Konfiguration des SOAP-Anforderungsclientendpunkts für den SOAP-Dienst nach Hinzufügen der Dienstreferenz
<client>
<endpoint address="http://www.example.com/soap" binding="basicHttpBinding"
contract="ITestService" name="BasicHttpBinding_ITestService" />
</client>
in C #
TestServiceClient client = new TestServiceClient();
client.GetAccount("A123");
Eine andere Möglichkeit besteht darin, zwei verschiedene Serviceverträge mit jeweils einer bestimmten Konfiguration verfügbar zu machen. Dies kann einige Duplikate auf Codeebene erzeugen, aber am Ende des Tages möchten Sie, dass es funktioniert.
Dieser Beitrag hat bereits eine sehr gute Antwort von "Community Wiki" und ich empfehle auch, sich Rick Strahls Web Blog anzusehen, es gibt viele gute Beiträge über WCF Rest wie diesen .
Ich habe beide verwendet, um diese Art von MyService-Service zu erhalten ... Dann kann ich die REST-Schnittstelle von jQuery oder SOAP von Java verwenden.
Dies ist aus meiner Web.Config:
<system.serviceModel>
<services>
<service name="MyService" behaviorConfiguration="MyServiceBehavior">
<endpoint name="rest" address="" binding="webHttpBinding" contract="MyService" behaviorConfiguration="restBehavior"/>
<endpoint name="mex" address="mex" binding="mexHttpBinding" contract="MyService"/>
<endpoint name="soap" address="soap" binding="basicHttpBinding" contract="MyService"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="restBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
Und das ist meine Service-Klasse (.svc-Codebehind, keine Schnittstellen erforderlich):
/// <summary> MyService documentation here ;) </summary>
[ServiceContract(Name = "MyService", Namespace = "http://myservice/", SessionMode = SessionMode.NotAllowed)]
//[ServiceKnownType(typeof (IList<MyDataContractTypes>))]
[ServiceBehavior(Name = "MyService", Namespace = "http://myservice/")]
public class MyService
{
[OperationContract(Name = "MyResource1")]
[WebGet(ResponseFormat = WebMessageFormat.Xml, UriTemplate = "MyXmlResource/{key}")]
public string MyResource1(string key)
{
return "Test: " + key;
}
[OperationContract(Name = "MyResource2")]
[WebGet(ResponseFormat = WebMessageFormat.Json, UriTemplate = "MyJsonResource/{key}")]
public string MyResource2(string key)
{
return "Test: " + key;
}
}
Eigentlich benutze ich nur Json oder Xml, aber beide sind hier für einen Demo-Zweck. Das sind GET-Anfragen zum Abrufen von Daten. Zum Einfügen von Daten würde ich eine Methode mit Attributen verwenden:
[OperationContract(Name = "MyResourceSave")]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "MyJsonResource")]
public string MyResourceSave(string thing){
//...
Wenn Sie nur einen einzigen Webdienst entwickeln und auf vielen verschiedenen Endpunkten hosten lassen möchten (z. B. SOAP + REST mit XML-, JSON-, CSV- und HTML-Ausgaben). Sie sollten auch die Verwendung von ServiceStack in Betracht ziehen, den ich genau für diesen Zweck erstellt habe, bei dem jeder von Ihnen entwickelte Service automatisch auf SOAP- und REST-Endpunkten verfügbar ist, ohne dass eine Konfiguration erforderlich ist.
Das Hello World- Beispiel zeigt, wie Sie einen einfachen Dienst mit nur (keine Konfiguration erforderlich) erstellen:
public class Hello {
public string Name { get; set; }
}
public class HelloResponse {
public string Result { get; set; }
}
public class HelloService : IService
{
public object Any(Hello request)
{
return new HelloResponse { Result = "Hello, " + request.Name };
}
}
Es ist keine andere Konfiguration erforderlich, und dieser Service ist mit REST sofort verfügbar in:
Es ist außerdem mit einer benutzerfreundlichen HTML-Ausgabe ausgestattet (wenn es mit einem HTTP-Client mit Accept: text / html, z. B. einem Browser, aufgerufen wird ), damit Sie die Ausgabe Ihrer Dienste besser visualisieren können.
Der Umgang mit verschiedenen REST-Verben ist ebenfalls trivial. Hier ist eine vollständige REST-Service-CRUD-App auf einer Seite von C # (weniger als für die Konfiguration von WCF erforderlich;):
MSDN scheint jetzt einen Artikel dafür zu haben:
https://msdn.microsoft.com/en-us/library/bb412196(v=vs.110).aspx
Intro:
Standardmäßig stellt Windows Communication Foundation (WCF) Endpunkte nur SOAP-Clients zur Verfügung. Unter Gewusst wie: Erstellen eines einfachen WCF-Web-HTTP-Dienstes wird ein Endpunkt Nicht-SOAP-Clients zur Verfügung gestellt. Es kann vorkommen, dass Sie denselben Vertrag in beide Richtungen als Webendpunkt und als SOAP-Endpunkt verfügbar machen möchten. Dieses Thema zeigt ein Beispiel dafür.
Wir müssen die Verhaltenskonfiguration für den REST- Endpunkt definieren
<endpointBehaviors>
<behavior name="restfulBehavior">
<webHttp defaultOutgoingResponseFormat="Json" defaultBodyStyle="Wrapped" automaticFormatSelectionEnabled="False" />
</behavior>
</endpointBehaviors>
und auch zu einem Service
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
Nach dem Verhalten sind die Bindungen der nächste Schritt. Zum Beispiel basicHttpBinding an SOAP- Endpunkt und webHttpBinding an REST .
<bindings>
<basicHttpBinding>
<binding name="soapService" />
</basicHttpBinding>
<webHttpBinding>
<binding name="jsonp" crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
</bindings>
Schließlich müssen wir den 2-Endpunkt in der Service-Definition definieren. Achtung für die Adresse = "" des Endpunktes, wo REST-Service nicht notwendig ist, nichts.
<services>
<service name="ComposerWcf.ComposerService">
<endpoint address="" behaviorConfiguration="restfulBehavior" binding="webHttpBinding" bindingConfiguration="jsonp" name="jsonService" contract="ComposerWcf.Interface.IComposerService" />
<endpoint address="soap" binding="basicHttpBinding" name="soapService" contract="ComposerWcf.Interface.IComposerService" />
<endpoint address="mex" binding="mexHttpBinding" name="metadata" contract="IMetadataExchange" />
</service>
</services>
In der Schnittstelle des Dienstes definieren wir die Operation mit ihren Attributen.
namespace ComposerWcf.Interface
{
[ServiceContract]
public interface IComposerService
{
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "/autenticationInfo/{app_id}/{access_token}", ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)]
Task<UserCacheComplexType_RootObject> autenticationInfo(string app_id, string access_token);
}
}
Dies ist unsere WCF system.serviceModel-Definition.
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="restfulBehavior">
<webHttp defaultOutgoingResponseFormat="Json" defaultBodyStyle="Wrapped" automaticFormatSelectionEnabled="False" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="soapService" />
</basicHttpBinding>
<webHttpBinding>
<binding name="jsonp" crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
</bindings>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service name="ComposerWcf.ComposerService">
<endpoint address="" behaviorConfiguration="restfulBehavior" binding="webHttpBinding" bindingConfiguration="jsonp" name="jsonService" contract="ComposerWcf.Interface.IComposerService" />
<endpoint address="soap" binding="basicHttpBinding" name="soapService" contract="ComposerWcf.Interface.IComposerService" />
<endpoint address="mex" binding="mexHttpBinding" name="metadata" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
Um beide Endpunkte zu testen, können wir WCFClient für SOAP und PostMan für REST verwenden .
Das habe ich getan, damit es funktioniert.
Stellen Sie sicher, dass Sie webHttpomaticFormatSelectionEnabled = "true" in das Endpunktverhalten einfügen .
[ServiceContract]
public interface ITestService
{
[WebGet(BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "/product", ResponseFormat = WebMessageFormat.Json)]
string GetData();
}
public class TestService : ITestService
{
public string GetJsonData()
{
return "I am good...";
}
}
Inside Service-Modell
<service name="TechCity.Business.TestService">
<endpoint address="soap" binding="basicHttpBinding" name="SoapTest"
bindingName="BasicSoap" contract="TechCity.Interfaces.ITestService" />
<endpoint address="mex"
contract="IMetadataExchange" binding="mexHttpBinding"/>
<endpoint behaviorConfiguration="jsonBehavior" binding="webHttpBinding"
name="Http" contract="TechCity.Interfaces.ITestService" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8739/test" />
</baseAddresses>
</host>
</service>
EndPoint-Verhalten
<endpointBehaviors>
<behavior name="jsonBehavior">
<webHttp automaticFormatSelectionEnabled="true" />
<!-- use JSON serialization -->
</behavior>
</endpointBehaviors>