Points de terminaison REST / SOAP pour un service WCF

425

J'ai un service WCF et je veux l'exposer en tant que service RESTfull et en tant que service SOAP. Quelqu'un a déjà fait quelque chose comme ça avant?

Wessam Zeidan
la source
bonne question et bonnes réponses.
chandra rv

Réponses:

584

Vous pouvez exposer le service dans deux points de terminaison différents. le SOAP peut utiliser la liaison qui prend en charge SOAP, par exemple basicHttpBinding, le RESTful peut utiliser le webHttpBinding. Je suppose que votre service REST sera en JSON, dans ce cas, vous devez configurer les deux points de terminaison avec la configuration de comportement suivante

<endpointBehaviors>
  <behavior name="jsonBehavior">
    <enableWebScript/>
  </behavior>
</endpointBehaviors>

Un exemple de configuration de point de terminaison dans votre scénario est

<services>
  <service name="TestService">
    <endpoint address="soap" binding="basicHttpBinding" contract="ITestService"/>
    <endpoint address="json" binding="webHttpBinding"  behaviorConfiguration="jsonBehavior" contract="ITestService"/>
  </service>
</services>

donc, le service sera disponible à

Appliquez [WebGet] au contrat d'exploitation pour le rendre RESTful. par exemple

public interface ITestService
{
   [OperationContract]
   [WebGet]
   string HelloWorld(string text)
}

Notez que si le service REST n'est pas en JSON, les paramètres des opérations ne peuvent pas contenir de type complexe.

Répondre au message de SOAP et RESTful POX (XML)

Pour le vieux XML pur comme format de retour, ceci est un exemple qui fonctionnerait à la fois pour SOAP et XML.

[ServiceContract(Namespace = "http://test")]
public interface ITestService
{
    [OperationContract]
    [WebGet(UriTemplate = "accounts/{id}")]
    Account[] GetAccount(string id);
}

Comportement POX pour REST Plain Old XML

<behavior name="poxBehavior">
  <webHttp/>
</behavior>

Points de terminaison

<services>
  <service name="TestService">
    <endpoint address="soap" binding="basicHttpBinding" contract="ITestService"/>
    <endpoint address="xml" binding="webHttpBinding"  behaviorConfiguration="poxBehavior" contract="ITestService"/>
  </service>
</services>

Le service sera disponible à

Demande REST essayez-le dans le navigateur,

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

Configuration du point de terminaison client de demande SOAP pour le service SOAP après l'ajout de la référence de service,

  <client>
    <endpoint address="http://www.example.com/soap" binding="basicHttpBinding"
      contract="ITestService" name="BasicHttpBinding_ITestService" />
  </client>

en C #

TestServiceClient client = new TestServiceClient();
client.GetAccount("A123");

Une autre façon de le faire est d'exposer deux contrats de service différents et chacun avec une configuration spécifique. Cela peut générer des doublons au niveau du code, mais à la fin de la journée, vous souhaitez le faire fonctionner.

codemeit
la source
11
À quoi cela ressemble-t-il lorsque j'ai .svc hébergé dans IIS dans un répertoire virtuel comme someserver / myvirtualdir / service.svc ? Comment dois-je y accéder?
Sunny Milenov
Je voudrais aller plus loin et ajouter une liaison à HTTPS pour l'adresse JSON. Comment je fais ça? stackoverflow.com/questions/18213472/…
Steve
Cela signifie que mon contrat IEvents n'est pas valide lorsque j'essaie de référencer mon interface de service: <service name = "Events"> <endpoint address = "json" binding = "webHttpBinding" behaviorConfiguration = "jsonBehavior" contract = "IEvents" />. Mon IEvents a un attribut [ServiceContract] sur l'interface, donc je ne sais pas pourquoi. </service>
PositiveGuy
Je peux faire fonctionner localhost: 44652 / MyResource / json mais je ne peux pas obtenir un identifiant pour travailler localhost: 44652 / MyResource / 98 / json . J'ai essayé d'ajouter un UriTemplate de "/ {id}", j'ai également essayé "events / {id} mais il ne le trouve pas quand j'essaye de toucher le service. Seul le premier fonctionne, je ne sais pas comment obtenir le dernier au travail.
PositiveGuy
2
Comment cela peut-il fonctionner sans fichier physique? Il semble que j'obtienne 404 erreurs, il
me
39

Ce message a déjà une très bonne réponse de "Community wiki" et je recommande également de consulter le blog Web de Rick Strahl, il existe de nombreux bons messages sur WCF Rest comme celui-ci .

J'ai utilisé les deux pour obtenir ce type de service MyService ... Ensuite, je peux utiliser l'interface REST de jQuery ou SOAP de Java.

C'est de mon 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>

Et voici ma classe de service (.svc-codebehind, aucune interface requise):

    /// <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;
    }
}

En fait, j'utilise uniquement Json ou Xml, mais les deux sont ici à des fins de démonstration. Ce sont des demandes GET pour obtenir des données. Pour insérer des données, j'utiliserais une méthode avec des attributs:

[OperationContract(Name = "MyResourceSave")]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "MyJsonResource")]
public string MyResourceSave(string thing){
    //...
Tuomas Hietanen
la source
Je suis curieux de savoir quels avantages vous pensez que vous obtiendrez en ajoutant ces attributs WebGet et WebInvoke.
Darrel Miller
2
Vous pouvez faire des requêtes par navigateur: localhost / MyService.svc / MyXmlResource / test Et dire explicitement le format Json ou Xml. Si vous souhaitez que les mêmes méthodes répondent aux deux, voici un lien: blogs.msdn.com/dotnetinterop/archive/2008/11/04/…
Tuomas Hietanen
C'est à des fins de test. Juste pour voir si vos terminaux fonctionnent. Avez-vous regardé SoapUI? soapui.org
Darrel Miller
@TuomasHietanen - Je n'obtiens pas de réponse de type JSON en utilisant le comportement webHttp mais en utilisant enableWebScript j'obtiens une réponse de type JSON. J'ai mis ResponseFormat en tant que WebMessageFormat.Json. D'un autre côté, je ne peux pas utiliser URItemplate si j'utilise le comportement enableWebScript. Des idées?
smile.al.d.way
1
@CoffeeAddict - Pourquoi devriez-vous utiliser l'interface? Juste pour avoir une interface? Vous ne réutiliserez jamais cette interface. C'est plus simple.
Tuomas Hietanen
25

Si vous souhaitez uniquement développer un service Web unique et le faire héberger sur de nombreux points de terminaison différents (c.-à-d. SOAP + REST, avec des sorties XML, JSON, CSV, HTML). Vous devriez également envisager d'utiliser ServiceStack que j'ai construit exactement à cette fin, où chaque service que vous développez est automatiquement disponible sur les points de terminaison SOAP et REST prêts à l'emploi sans aucune configuration requise.

L' exemple Hello World montre comment créer un simple avec service avec just (aucune configuration requise):

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 };
    }
}

Aucune autre configuration n'est requise, et ce service est immédiatement disponible avec REST dans:

Il est également livré avec une sortie HTML conviviale (lorsqu'il est appelé avec un client HTTP qui a Accept: text / html, par exemple un navigateur) afin que vous puissiez mieux visualiser la sortie de vos services.

La gestion de différents verbes REST est également aussi triviale, voici une application CRUD de service REST complète en 1 page de C # (moins que ce qu'il faudrait pour configurer WCF;):

mythz
la source
7

MSDN semble avoir un article pour cela maintenant:

https://msdn.microsoft.com/en-us/library/bb412196(v=vs.110).aspx

Intro:

Par défaut, Windows Communication Foundation (WCF) rend les points de terminaison disponibles uniquement pour les clients SOAP. Dans Comment: créer un service HTTP Web WCF de base, un point de terminaison est mis à la disposition des clients non SOAP. Il peut arriver que vous souhaitiez rendre le même contrat disponible dans les deux sens, en tant que point de terminaison Web et en tant que point de terminaison SOAP. Cette rubrique montre un exemple de procédure à suivre.

FMFF
la source
3

Nous devons définir la configuration du comportement au point de terminaison REST

<endpointBehaviors>
  <behavior name="restfulBehavior">
   <webHttp defaultOutgoingResponseFormat="Json" defaultBodyStyle="Wrapped" automaticFormatSelectionEnabled="False" />
  </behavior>
</endpointBehaviors>

et aussi à un service

<serviceBehaviors>
   <behavior>
     <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="false" />
   </behavior>
</serviceBehaviors>

Après les comportements, la prochaine étape est les liaisons. Par exemple, basicHttpBinding vers le point de terminaison SOAP et webHttpBinding vers REST .

<bindings>
   <basicHttpBinding>
     <binding name="soapService" />
   </basicHttpBinding>
   <webHttpBinding>
     <binding name="jsonp" crossDomainScriptAccessEnabled="true" />
   </webHttpBinding>
</bindings>

Enfin, nous devons définir le point final 2 dans la définition du service. Attention pour l'adresse = "" du noeud final, où le service REST n'est pas nécessaire rien.

<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>

Dans Interface du service, nous définissons l'opération avec ses attributs.

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

Rejoindre toutes les parties, ce sera notre définition WCF system.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>

Pour tester les deux points de terminaison, nous pouvons utiliser WCFClient pour SOAP et PostMan pour REST .

Jailson Evora
la source
Fonctionne bien comme prévu
Shiv
0

C'est ce que j'ai fait pour que ça marche. Assurez-vous de mettre
webHttp automaticFormatSelectionEnabled = "true" dans le comportement du point de terminaison.

[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...";
    }
}

Modèle de service interne

   <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>

Comportement EndPoint

  <endpointBehaviors>
    <behavior name="jsonBehavior">
      <webHttp automaticFormatSelectionEnabled="true"  />
      <!-- use JSON serialization -->
    </behavior>
  </endpointBehaviors>
Nayas Subramanian
la source