Ho un servizio WCF e voglio esporlo sia come servizio RESTfull che come servizio SOAP. Qualcuno ha fatto qualcosa di simile prima?
Ho un servizio WCF e voglio esporlo sia come servizio RESTfull che come servizio SOAP. Qualcuno ha fatto qualcosa di simile prima?
Risposte:
È possibile esporre il servizio in due diversi endpoint. quello SOAP può usare l'associazione che supporta SOAP, ad esempio basicHttpBinding, quello RESTful può usare webHttpBinding. Presumo che il servizio REST sarà in JSON, in tal caso, è necessario configurare i due endpoint con la seguente configurazione comportamentale
<endpointBehaviors>
<behavior name="jsonBehavior">
<enableWebScript/>
</behavior>
</endpointBehaviors>
Un esempio di configurazione dell'endpoint nel tuo scenario è
<services>
<service name="TestService">
<endpoint address="soap" binding="basicHttpBinding" contract="ITestService"/>
<endpoint address="json" binding="webHttpBinding" behaviorConfiguration="jsonBehavior" contract="ITestService"/>
</service>
</services>
quindi, il servizio sarà disponibile all'indirizzo
Applicare [WebGet] al contratto di operazione per renderlo RESTful. per esempio
public interface ITestService
{
[OperationContract]
[WebGet]
string HelloWorld(string text)
}
Nota, se il servizio REST non è in JSON, i parametri delle operazioni non possono contenere tipi complessi.
Per il semplice vecchio XML come formato di ritorno, questo è un esempio che funzionerebbe sia per SOAP che per XML.
[ServiceContract(Namespace = "http://test")]
public interface ITestService
{
[OperationContract]
[WebGet(UriTemplate = "accounts/{id}")]
Account[] GetAccount(string id);
}
Comportamento POX per REST Plain Old XML
<behavior name="poxBehavior">
<webHttp/>
</behavior>
endpoint
<services>
<service name="TestService">
<endpoint address="soap" binding="basicHttpBinding" contract="ITestService"/>
<endpoint address="xml" binding="webHttpBinding" behaviorConfiguration="poxBehavior" contract="ITestService"/>
</service>
</services>
Il servizio sarà disponibile all'indirizzo
Richiesta REST provalo nel browser,
Configurazione dell'endpoint del client richiesta SOAP per il servizio SOAP dopo aver aggiunto il riferimento al servizio,
<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");
Un altro modo per farlo è quello di esporre due diversi contratti di servizio e ognuno con una configurazione specifica. Questo può generare alcuni duplicati a livello di codice, tuttavia alla fine della giornata, vuoi farlo funzionare.
Questo post ha già un'ottima risposta da "Community wiki" e consiglio anche di consultare il Blog Web di Rick Strahl, ci sono molti buoni post su WCF Rest come questo .
Ho usato entrambi per ottenere questo tipo di servizio MyService ... Quindi posso usare l'interfaccia REST da jQuery o SOAP da Java.
Questo è dal mio 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>
E questa è la mia classe di servizio (.svc-codebehind, nessuna interfaccia richiesta):
/// <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;
}
}
In realtà uso solo Json o Xml ma entrambi sono qui per uno scopo dimostrativo. Quelle sono richieste GET per ottenere dati. Per inserire dati vorrei usare il metodo con gli attributi:
[OperationContract(Name = "MyResourceSave")]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "MyJsonResource")]
public string MyResourceSave(string thing){
//...
Se si desidera sviluppare un solo servizio Web e averlo ospitato su molti endpoint diversi (ad esempio SOAP + REST, con output XML, JSON, CSV, HTML). Dovresti anche considerare l'utilizzo di ServiceStack che ho creato esattamente per questo scopo in cui ogni servizio che sviluppi è automaticamente disponibile su endpoint SOAP e REST immediatamente senza alcuna configurazione richiesta.
L' esempio Hello World mostra come creare un servizio semplice con solo (nessuna configurazione richiesta):
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 };
}
}
Non è richiesta altra configurazione e questo servizio è immediatamente disponibile con REST in:
Viene inoltre integrato con un output HTML intuitivo (quando viene chiamato con un client HTTP che ha Accept: text / html, ad esempio un browser) in modo da poter visualizzare meglio l'output dei tuoi servizi.
Gestire diversi verbi REST è altrettanto banale, ecco un'app CRUD completa di servizi REST in 1 pagina di C # (meno di quanto sarebbe necessario per configurare WCF;):
MSDN sembra avere un articolo per questo ora:
https://msdn.microsoft.com/en-us/library/bb412196(v=vs.110).aspx
Intro:
Per impostazione predefinita, Windows Communication Foundation (WCF) rende gli endpoint disponibili solo per i client SOAP. In Procedura: creare un servizio HTTP Web WCF di base, un endpoint è reso disponibile per i client non SOAP. In alcuni casi è possibile rendere disponibile lo stesso contratto in entrambi i modi, come endpoint Web e endpoint SOAP. Questo argomento mostra un esempio di come eseguire questa operazione.
Dobbiamo definire la configurazione del comportamento sull'endpoint REST
<endpointBehaviors>
<behavior name="restfulBehavior">
<webHttp defaultOutgoingResponseFormat="Json" defaultBodyStyle="Wrapped" automaticFormatSelectionEnabled="False" />
</behavior>
</endpointBehaviors>
e anche a un servizio
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
Dopo i comportamenti, il passo successivo sono i vincoli. Ad esempio basicHttpBinding su endpoint SOAP e webHttpBinding su REST .
<bindings>
<basicHttpBinding>
<binding name="soapService" />
</basicHttpBinding>
<webHttpBinding>
<binding name="jsonp" crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
</bindings>
Infine, dobbiamo definire l'endpoint 2 nella definizione del servizio. Attenzione per l'indirizzo = "" dell'endpoint, dove al servizio REST non è necessario nulla.
<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 Interfaccia del servizio definiamo l'operazione con i suoi attributi.
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);
}
}
Unendo tutte le parti, questa sarà la nostra definizione di system.serviceModel WCF.
<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>
Per testare entrambi gli endpoint, possiamo usare WCFClient per SOAP e PostMan per REST .
Questo è quello che ho fatto per farlo funzionare. Assicurati di mettere
webHttp automaticFormatSelectionEnabled = "true" all'interno del comportamento dell'endpoint.
[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...";
}
}
Modello di servizio interno
<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>
Comportamento di EndPoint
<endpointBehaviors>
<behavior name="jsonBehavior">
<webHttp automaticFormatSelectionEnabled="true" />
<!-- use JSON serialization -->
</behavior>
</endpointBehaviors>