REST / SOAP-Endpunkte für einen WCF-Dienst

425

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?

Wessam Zeidan
quelle
gute Frage und gute Antworten.
Chandra RV

Antworten:

584

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.

Antwort auf den Beitrag für SOAP und RESTful POX (XML)

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,

http://www.example.com/xml/accounts/A123

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.

Codemeit
quelle
11
Wie sieht das aus, wenn ich .svc in IIS in einem virtuellen Verzeichnis wie someserver / myvirtualdir / service.svc gehostet habe ? Wie soll ich darauf zugreifen?
Sunny Milenov
Ich möchte noch einen Schritt weiter gehen und eine Bindung an HTTPS für die JSON-Adresse hinzufügen. Wie mache ich das? stackoverflow.com/questions/18213472/…
Steve
Es heißt, dass mein Vertrag IEvents ungültig ist, wenn ich versuche, auf meine Service-Schnittstelle zu verweisen: <service name = "Events"> <endpoint address = "json" binding = "webHttpBinding" behaviourConfiguration = "jsonBehavior" contract = "IEvents" />. Mein IEvents hat ein [ServiceContract] -Attribut auf der Schnittstelle, daher weiß ich nicht warum. </ service>
PositiveGuy
Ich kann localhost: 44652 / MyResource / json zum Laufen bringen , aber ich kann keine ID zum Arbeiten bekommen localhost: 44652 / MyResource / 98 / json . Ich habe versucht, ein UriTemplate von "/ {id}" hinzuzufügen, habe aber auch "events / {id}" versucht, aber es wird nicht gefunden, wenn ich versuche, den Dienst zu starten. Nur das erste funktioniert, nicht sicher, wie ich das letztere bekomme zu arbeiten.
PositiveGuy
2
Wie kann es dort ohne physische Datei funktionieren? Ich scheine nur 404 Fehler zu bekommen, muss etwas fehlen
RoboJ1M
39

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){
    //...
Tuomas Hietanen
quelle
Ich bin gespannt, welche Vorteile Sie durch das Hinzufügen dieser WebGet- und WebInvoke-Attribute erhalten.
Darrel Miller
2
Sie können Anfragen per Browser stellen: localhost / MyService.svc / MyXmlResource / test Und sagen Sie explizit Format Json oder Xml. Wenn Sie möchten, dass dieselben Methoden auf beide antworten, finden Sie hier einen Link: blogs.msdn.com/dotnetinterop/archive/2008/11/04/…
Tuomas Hietanen
Dies dient zu Testzwecken. Nur um zu sehen, ob Ihre Endpunkte funktionieren. Haben Sie sich SoapUI angesehen? soapui.org
Darrel Miller
@TuomasHietanen - Ich erhalte keine Antwort vom Typ JSON, wenn ich das Verhalten von webHttp verwende. Bei Verwendung von enableWebScript erhalte ich jedoch eine Antwort vom Typ JSON. Ich habe ResponseFormat als WebMessageFormat.Json eingefügt. Andererseits kann ich URItemplate nicht verwenden, wenn ich das Verhalten von enableWebScript verwende. Irgendwelche Ideen?
smile.al.d.way
1
@CoffeeAddict - Warum sollten Sie inteface verwenden? Nur um eine Schnittstelle zu haben? Sie werden diese Schnittstelle niemals wiederverwenden. Das ist einfacher.
Tuomas Hietanen
25

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;):

Mythos
quelle
7

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.

FMFF
quelle
3

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 .

Jailson Evora
quelle
Funktioniert wie erwartet
Shiv
0

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>
Nayas Subramanian
quelle