Eu tenho um serviço WCF e quero expô-lo como um serviço RESTfull e como um serviço SOAP. Alguém já fez algo assim antes?
Eu tenho um serviço WCF e quero expô-lo como um serviço RESTfull e como um serviço SOAP. Alguém já fez algo assim antes?
Respostas:
Você pode expor o serviço em dois pontos de extremidade diferentes. o SOAP pode usar a ligação que suporta SOAP, por exemplo, basicHttpBinding, o RESTful pode usar o webHttpBinding. Presumo que seu serviço REST esteja em JSON; nesse caso, você precisa configurar os dois pontos de extremidade com a seguinte configuração de comportamento
<endpointBehaviors>
<behavior name="jsonBehavior">
<enableWebScript/>
</behavior>
</endpointBehaviors>
Um exemplo de configuração de terminal em seu cenário é
<services>
<service name="TestService">
<endpoint address="soap" binding="basicHttpBinding" contract="ITestService"/>
<endpoint address="json" binding="webHttpBinding" behaviorConfiguration="jsonBehavior" contract="ITestService"/>
</service>
</services>
portanto, o serviço estará disponível em
Aplique [WebGet] ao contrato de operação para torná-lo RESTful. por exemplo
public interface ITestService
{
[OperationContract]
[WebGet]
string HelloWorld(string text)
}
Observe que, se o serviço REST não estiver em JSON, os parâmetros das operações não poderão conter um tipo complexo.
Para XML antigo simples como formato de retorno, este é um exemplo que funcionaria tanto para SOAP quanto XML.
[ServiceContract(Namespace = "http://test")]
public interface ITestService
{
[OperationContract]
[WebGet(UriTemplate = "accounts/{id}")]
Account[] GetAccount(string id);
}
Comportamento do POX para XML antigo simples REST
<behavior name="poxBehavior">
<webHttp/>
</behavior>
Pontos finais
<services>
<service name="TestService">
<endpoint address="soap" binding="basicHttpBinding" contract="ITestService"/>
<endpoint address="xml" binding="webHttpBinding" behaviorConfiguration="poxBehavior" contract="ITestService"/>
</service>
</services>
O serviço estará disponível em
Solicitação REST, experimente no navegador,
SOAP solicita a configuração do terminal do cliente para o serviço SOAP após incluir a referência de serviço,
<client>
<endpoint address="http://www.example.com/soap" binding="basicHttpBinding"
contract="ITestService" name="BasicHttpBinding_ITestService" />
</client>
em c #
TestServiceClient client = new TestServiceClient();
client.GetAccount("A123");
Outra maneira de fazer isso é expor dois contratos de serviço diferentes e cada um com configuração específica. Isso pode gerar algumas duplicatas no nível do código; no entanto, no final do dia, você deseja fazê-lo funcionar.
Este post já tem uma resposta muito boa por "wiki comunitário" e eu também recomendo a olhar para Web Blog do Rick Strahl, há muitas mensagens boas sobre WCF de lazer como este .
Eu usei os dois para obter esse tipo de serviço MyService ... Então eu posso usar a interface REST do jQuery ou SOAP do Java.
Isto é do meu 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 esta é a minha classe de serviço (.svc-codebehind, sem necessidade de interfaces):
/// <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;
}
}
Na verdade, eu uso apenas Json ou Xml, mas os dois estão aqui para fins de demonstração. Essas são solicitações GET para obter dados. Para inserir dados, eu usaria o método com atributos:
[OperationContract(Name = "MyResourceSave")]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "MyJsonResource")]
public string MyResourceSave(string thing){
//...
Se você deseja desenvolver apenas um único serviço da Web e hospedá-lo em muitos pontos de extremidade diferentes (por exemplo, SOAP + REST, com saídas XML, JSON, CSV, HTML). Você também deve considerar usar o ServiceStack que eu criei exatamente para esse fim, onde todos os serviços que você desenvolve estão automaticamente disponíveis nos pontos de extremidade SOAP e REST prontos para uso, sem a necessidade de nenhuma configuração.
O exemplo Hello World mostra como criar um serviço simples com apenas (nenhuma configuração necessária):
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 };
}
}
Nenhuma outra configuração é necessária e este serviço está disponível imediatamente com o REST em:
Ele também vem embutido com uma saída HTML amigável (quando chamada com um cliente HTTP que possui Accept: text / html, por exemplo, um navegador) para que você possa visualizar melhor a saída de seus serviços.
A manipulação de verbos REST diferentes também é tão trivial. Aqui está um aplicativo CRUD de serviço REST completo em 1 página de C # (menos do que seria necessário para configurar o WCF;):
O MSDN parece ter um artigo para isso agora:
https://msdn.microsoft.com/en-us/library/bb412196(v=vs.110).aspx
Introdução:
Por padrão, o Windows Communication Foundation (WCF) disponibiliza pontos de extremidade apenas para clientes SOAP. Em Como: Criar um Serviço HTTP da Web Básico do WCF, um ponto de extremidade é disponibilizado para clientes não SOAP. Pode haver momentos em que você queira disponibilizar o mesmo contrato nos dois sentidos, como um terminal da Web e SOAP. Este tópico mostra um exemplo de como fazer isso.
Devemos definir a configuração de comportamento para o terminal REST
<endpointBehaviors>
<behavior name="restfulBehavior">
<webHttp defaultOutgoingResponseFormat="Json" defaultBodyStyle="Wrapped" automaticFormatSelectionEnabled="False" />
</behavior>
</endpointBehaviors>
e também para um serviço
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
Após os comportamentos, o próximo passo é as ligações. Por exemplo, basicHttpBinding para o terminal SOAP e webHttpBinding para REST .
<bindings>
<basicHttpBinding>
<binding name="soapService" />
</basicHttpBinding>
<webHttpBinding>
<binding name="jsonp" crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
</bindings>
Finalmente, devemos definir o ponto final 2 na definição de serviço. Atenção para o endereço = "" do nó de extremidade, onde REST o serviço não é necessário nada.
<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>
Na interface do serviço, definimos a operação com seus atributos.
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);
}
}
Juntando-se a todas as partes, esta será a nossa definição system.serviceModel do 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>
Para testar os dois pontos de extremidade, podemos usar WCFClient para SOAP e PostMan para REST .
Isto é o que eu fiz para fazê-lo funcionar. Certifique-se de colocar
webHttp automaticFormatSelectionEnabled = "true" dentro do comportamento do terminal.
[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...";
}
}
Modelo de serviço 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 do EndPoint
<endpointBehaviors>
<behavior name="jsonBehavior">
<webHttp automaticFormatSelectionEnabled="true" />
<!-- use JSON serialization -->
</behavior>
</endpointBehaviors>