Кінцеві точки REST / SOAP для послуги WCF


425

У мене є служба WCF, і я хочу розкрити її як послугу RESTfull і як послугу SOAP. Хтось робив щось подібне раніше?


гарне запитання та чудові відповіді.
chandra rv

Відповіді:


584

Ви можете виставити послугу у двох різних кінцевих точках. SOAP можна використовувати прив'язку, яка підтримує SOAP, наприклад basicHttpBinding, RESTful може використовувати webHttpBinding. Я припускаю, що ваша послуга REST буде в JSON, у цьому випадку вам потрібно налаштувати дві кінцеві точки з наступною конфігурацією поведінки

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

Приклад конфігурації кінцевої точки у вашому сценарії

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

Таким чином, послуга буде доступна за адресою

Застосуйте [WebGet] до контракту на експлуатацію, щоб зробити його RESTful. напр

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

Зверніть увагу, якщо сервіс REST не знаходиться в JSON, параметри операцій не можуть містити складний тип.

Відповідь на публікацію для SOAP та RESTful POX (XML)

Для простого старого XML як формату повернення - це приклад, який би працював як для SOAP, так і для XML.

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

Поведінка POX для REST Plain Old XML

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

Кінцеві точки

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

Сервіс буде доступний за адресою

REST-запит спробуйте в браузері,

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

Конфігурація кінцевої точки запиту клієнта для сервісу SOAP після додавання довідки про службу,

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

в C #

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

Інший спосіб зробити це - розкрити два різні договори на обслуговування, і кожен з конкретною конфігурацією. Це може генерувати деякі дублікати на рівні коду, проте в кінці дня ви хочете, щоб він працював.


11
Як це виглядає, коли у мене .svc розміщується в IIS у такому віртуальному каталозі, як someserver / myvirtualdir / service.svc ? Як я маю отримати доступ до нього?
Сонячний Міленов

Я хотів би зробити цей крок далі і додати прив’язку до HTTPS для адреси JSON. Як це зробити? stackoverflow.com/questions/18213472/…
Стів

Це говорить про те, що мій контракт IEvents недійсний, коли я намагаюся посилатися на мій сервісний інтерфейс: <service name = "Events"> <endpoint address = "json" obavezство = "webHttpBinding" ponašanjeConfiguration = "jsonBehavior" контракт = "IEvents" />. Мій IEvents має атрибут [ServiceContract] в інтерфейсі, тому не знаю, чому. </service>
PositiveGuy

Я можу змусити localhost: 44652 / MyResource / json працювати, але я не можу отримати ідентифікатор для роботи localhost: 44652 / MyResource / 98 / json . Я спробував додати UriTemplate "/ {id}", також спробував "події / {id}, але він не знаходить його, коли я намагаюся потрапити на службу. Тільки перші працюють, не знаю, як отримати останній на роботу.
PositiveGuy

2
Як це може працювати без фізичного файлу там? Я просто начебто отримую 404 помилки, треба щось
бракувати

39

Цей пост вже має дуже гарну відповідь "Вікі спільноти", і я також рекомендую переглянути веб-блог Ріка Страля, є багато хороших дописів про WCF відпочинок, як це .

Я використовував обидва для отримання такого роду MyService-сервісу ... Тоді я можу використовувати інтерфейс REST від jQuery або SOAP від ​​Java.

Це з мого 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>

І це мій сервісний клас (.svc-codebehind, інтерфейси не потрібні):

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

Насправді я використовую лише Json або Xml, але обидва вони тут демонстраційні. Це GET-запити на отримання даних. Для вставки даних я б використав метод з атрибутами:

[OperationContract(Name = "MyResourceSave")]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "MyJsonResource")]
public string MyResourceSave(string thing){
    //...

Мені цікаво дізнатися, які переваги ви вважаєте, що отримаєте, додавши ці атрибути WebGet та WebInvoke.
Даррел Міллер

2
Ви можете робити запити через браузер: localhost / MyService.svc / MyXmlResource / test І чітко сказати формат Json або Xml. Якщо ви хочете відповісти на обидва способи, ось посилання: blogs.msdn.com/dotnetinterop/archive/2008/11/04/…
Tuomas Hietanen

Це для тестування. Просто щоб побачити, чи працюють ваші кінцеві точки. Ви подивилися на SoapUI? soapui.org
Даррел Міллер

@TuomasHietanen - Я не отримую відповіді типу JSON, використовуючи поведінку webHttp, однак за допомогою enableWebScript я отримую відповідь типу JSON. Я поставив ResponseFormat як WebMessageFormat.Json. З іншого боку, я не можу використовувати URItemplate, якщо я використовую enableWebScript поведінку. Будь-які ідеї?
smile.al.d.way

1
@CoffeeAddict - Чому слід використовувати інтефейс? Просто мати інтерфейс? Ви не будете використовувати цей інтерфейс ніколи. Це простіше.
Tuomas Hietanen

25

Якщо ви хочете розробити єдиний веб-сервіс і розмістити його на багатьох різних кінцевих точках (наприклад, SOAP + REST, з виводами XML, JSON, CSV, HTML). Вам слід також розглянути можливість використання ServiceStack, який я створив саме для цієї мети, коли кожна розроблена вами послуга автоматично доступна як у кінцевих точках SOAP, так і в REST, поза коробкою без необхідності будь-якої конфігурації.

Приклад Hello World показує, як створити простий сервіс із простою (конфігурація не потрібна):

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

Інша конфігурація не потрібна, і ця послуга з REST доступна відразу:

Він також вбудований з дружнім HTML-виведенням (коли дзвонить із HTTP-клієнтом, який має Accept: текст / html, наприклад, браузер), щоб ви могли краще візуалізувати результати своїх служб.

Поводження з різними дієсловами REST також тривіальне, ось повний додаток CRUD-служби CRUD на 1 сторінці C # (менше, ніж потрібно для налаштування WCF;):


7

Здається, у MSDN зараз є стаття для цього:

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

Вступ:

За замовчуванням Windows Communication Foundation (WCF) робить кінцеві точки доступними лише для клієнтів SOAP. Як зробити: Створення базової веб-сервісу HTTP WCF, кінцева точка стає доступною для клієнтів, які не входять в SOAP. Можуть бути випадки, коли ви хочете зробити один і той же договір доступним обома способами, як кінцева точка веб-сторінки та кінцева точка SOAP. У цій темі показаний приклад того, як це зробити.


3

Ми повинні визначити конфігурацію поведінки до кінцевої точки REST

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

Після поведінки наступним кроком є ​​прив’язка. Наприклад, basicHttpBinding до кінцевої точки SOAP та webHttpBinding до REST .

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

Нарешті, ми повинні визначити 2 кінцеві точки у визначенні служби. Увага до адреси = "" кінцевої точки, де для обслуговування REST нічого не потрібно.

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

В інтерфейсі служби ми визначаємо операцію з її атрибутами.

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

Приєднавшись до всіх сторін, це буде нашим 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>

Для тестування обох кінцевих точок ми можемо використовувати WCFClient до SOAP та PostMan до REST .


Працює нормально, як очікувалося
Шив

0

Це те, що я зробив, щоб він працював. Переконайтеся, що ви поклали
webHttp automaticFormatSelectionEnabled = "true" у поведінку кінцевої точки.

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

Всередині сервісна модель

   <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

  <endpointBehaviors>
    <behavior name="jsonBehavior">
      <webHttp automaticFormatSelectionEnabled="true"  />
      <!-- use JSON serialization -->
    </behavior>
  </endpointBehaviors>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.