Mam usługę WCF i chcę ją udostępnić zarówno jako usługę RESTfull, jak i jako usługę SOAP. Czy ktoś zrobił coś takiego wcześniej?
Mam usługę WCF i chcę ją udostępnić zarówno jako usługę RESTfull, jak i jako usługę SOAP. Czy ktoś zrobił coś takiego wcześniej?
Odpowiedzi:
Możesz udostępnić usługę w dwóch różnych punktach końcowych. SOAP można użyć powiązania, które obsługuje SOAP, np. basicHttpBinding, RESTful można użyć webHttpBinding. Zakładam, że twoja usługa REST będzie w JSON, w takim przypadku musisz skonfigurować dwa punkty końcowe za pomocą następującej konfiguracji zachowania
<endpointBehaviors>
<behavior name="jsonBehavior">
<enableWebScript/>
</behavior>
</endpointBehaviors>
Przykład konfiguracji punktu końcowego w twoim scenariuszu to
<services>
<service name="TestService">
<endpoint address="soap" binding="basicHttpBinding" contract="ITestService"/>
<endpoint address="json" binding="webHttpBinding" behaviorConfiguration="jsonBehavior" contract="ITestService"/>
</service>
</services>
usługa będzie dostępna pod adresem
Zastosuj [WebGet] do umowy operacyjnej, aby ją zrestartować. na przykład
public interface ITestService
{
[OperationContract]
[WebGet]
string HelloWorld(string text)
}
Uwaga: jeśli usługa REST nie znajduje się w JSON, parametry operacji nie mogą zawierać typu złożonego.
Dla zwykłego starego XML jako formatu zwracanego jest to przykład, który działałby zarówno dla SOAP, jak i XML.
[ServiceContract(Namespace = "http://test")]
public interface ITestService
{
[OperationContract]
[WebGet(UriTemplate = "accounts/{id}")]
Account[] GetAccount(string id);
}
Zachowanie POX dla REST Plain Old XML
<behavior name="poxBehavior">
<webHttp/>
</behavior>
Punkty końcowe
<services>
<service name="TestService">
<endpoint address="soap" binding="basicHttpBinding" contract="ITestService"/>
<endpoint address="xml" binding="webHttpBinding" behaviorConfiguration="poxBehavior" contract="ITestService"/>
</service>
</services>
Usługa będzie dostępna pod adresem
Żądanie REST spróbuj w przeglądarce,
Konfiguracja punktu końcowego klienta żądania SOAP dla usługi SOAP po dodaniu odwołania do usługi,
<client>
<endpoint address="http://www.example.com/soap" binding="basicHttpBinding"
contract="ITestService" name="BasicHttpBinding_ITestService" />
</client>
w C #
TestServiceClient client = new TestServiceClient();
client.GetAccount("A123");
Innym sposobem jest ujawnienie dwóch różnych umów serwisowych i każdego z określoną konfiguracją. Może to generować niektóre duplikaty na poziomie kodu, jednak pod koniec dnia chcesz, aby działało.
Ten post ma już bardzo dobrą odpowiedź przez „Community wiki”, a także polecam zajrzeć na blog internetowy Ricka Strahla, istnieje wiele dobrych postów na temat WCF Rest w ten sposób .
Użyłem obu, aby uzyskać tego rodzaju usługę MyService ... Następnie mogę użyć interfejsu REST z jQuery lub SOAP z Java.
To jest z mojego 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>
A to moja klasa usług (.svc-codebehind, nie wymaga interfejsów):
/// <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;
}
}
Właściwie używam tylko Jsona lub Xml, ale oba są tutaj w celach demonstracyjnych. Są to żądania GET, aby uzyskać dane. Aby wstawić dane, użyłbym metody z atrybutami:
[OperationContract(Name = "MyResourceSave")]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "MyJsonResource")]
public string MyResourceSave(string thing){
//...
Jeśli chcesz opracować tylko jedną usługę internetową i hostować ją w wielu różnych punktach końcowych (tj. SOAP + REST, z wyjściami XML, JSON, CSV, HTML). Powinieneś także rozważyć użycie ServiceStack, który zbudowałem właśnie do tego celu, w którym każda usługa, którą opracowujesz, jest automatycznie dostępna w punktach końcowych SOAP i REST natychmiast po wyjęciu z pudełka, bez wymaganej konfiguracji.
Przykład Hello World pokazuje, jak stworzyć prosty z usługą za pomocą just (nie wymaga konfiguracji):
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 };
}
}
Żadna inna konfiguracja nie jest wymagana, a ta usługa jest natychmiast dostępna z REST w:
Jest również wbudowany w przyjazny wynik HTML (gdy jest wywoływany z klientem HTTP, który ma opcję Akceptuj: tekst / HTML np. Przeglądarka), dzięki czemu możesz lepiej wizualizować wyniki swoich usług.
Obsługa różnych czasowników REST jest równie trywialna, oto pełna aplikacja CRUD z usługą REST na 1 stronie C # (mniej niż zajęłoby to skonfigurowanie WCF;):
Wydaje się, że MSDN ma teraz na ten temat artykuł:
https://msdn.microsoft.com/en-us/library/bb412196(v=vs.110).aspx
Wprowadzenie:
Domyślnie Windows Communication Foundation (WCF) udostępnia punkty końcowe tylko klientom SOAP. W temacie: Tworzenie podstawowej usługi HTTP HTTP WCF punkt końcowy został udostępniony klientom innym niż SOAP. Może się zdarzyć, że chcesz udostępnić tę samą umowę w obie strony, jako punkt końcowy sieci Web i punkt końcowy SOAP. W tym temacie pokazano przykład tego, jak to zrobić.
Musimy zdefiniować konfigurację zachowania do punktu końcowego REST
<endpointBehaviors>
<behavior name="restfulBehavior">
<webHttp defaultOutgoingResponseFormat="Json" defaultBodyStyle="Wrapped" automaticFormatSelectionEnabled="False" />
</behavior>
</endpointBehaviors>
a także do usługi
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
Po zachowaniach następnym krokiem są powiązania. Na przykład basicHttpBinding do punktu końcowego SOAP i webHttpBinding do REST .
<bindings>
<basicHttpBinding>
<binding name="soapService" />
</basicHttpBinding>
<webHttpBinding>
<binding name="jsonp" crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
</bindings>
Wreszcie musimy zdefiniować 2 punkt końcowy w definicji usługi. Uwaga na adres = "" punktu końcowego, gdzie do usługi REST nie jest konieczne nic.
<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>
W interfejsie usługi definiujemy operację za pomocą jej atrybutów.
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);
}
}
Dołączając do wszystkich stron, będzie to nasza definicja systemu WCF. ServiceModel.
<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>
Aby przetestować oba punkty końcowe, możemy użyć WCFClient do SOAP i PostMan do REST .
Tak zrobiłem, aby działało. Upewnij się, że umieściłeś
webHttp automaticFormatSelectionEnabled = "true" w zachowaniu punktu końcowego.
[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...";
}
}
Wewnątrz model serwisowy
<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>
Zachowanie EndPoint
<endpointBehaviors>
<behavior name="jsonBehavior">
<webHttp automaticFormatSelectionEnabled="true" />
<!-- use JSON serialization -->
</behavior>
</endpointBehaviors>