Конечные точки REST / SOAP для службы WCF

425

У меня есть служба WCF, и я хочу представить ее как службу RESTfull и как службу SOAP. Кто-нибудь делал что-то подобное раньше?

Вессам Зейдан
источник
Хороший вопрос и отличные ответы.
чандр с.в.

Ответы:

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>

Endpoints

<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-запроса для службы 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");

Еще один способ сделать это - выставить два разных сервисных контракта и каждый с определенной конфигурацией. Это может создать некоторые дубликаты на уровне кода, однако в конце дня вы хотите, чтобы он работал.

codemeit
источник
11
Как это выглядит, когда я размещаю .svc в IIS в каком-то виртуальном каталоге, например someserver / myvirtualdir / service.svc ? Как мне получить к нему доступ?
Солнечный Миленов
Я хотел бы сделать еще один шаг и добавить привязку к HTTPS для адреса JSON. Как я могу это сделать? stackoverflow.com/questions/18213472/…
Стив
Это говорит о том, что мой контракт IEvents недействителен, когда я пытаюсь сослаться на мой интерфейс службы: <имя службы = "События"> <адрес конечной точки = "json" binding = "webHttpBinding" поведениеConfiguration = "jsonBehavior" contract = "IEvents" />. Мой IEvents имеет атрибут [ServiceContract] на интерфейсе, поэтому не уверен, почему. </ service>
PositiveGuy
Я могу получить localhost: 44652 / MyResource / json для работы, но я не могу получить идентификатор для работы localhost: 44652 / MyResource / 98 / json . Я пытался добавить UriTemplate с "/ {id}", также пробовал "events / {id}, но он не находит его, когда я пытаюсь попасть в сервис. Работает только первый, не уверен, как получить последний на работу.
PositiveGuy
2
Как это может работать без физического файла там? Я просто, кажется, получаю 404 ошибки, должно быть чего-то не хватает
RoboJ1M
39

На этот пост уже получен очень хороший ответ от "Сообщества вики", и я также рекомендую взглянуть на веб-блог Рика Страла, там много хороших постов о WCF Rest, как это .

Я использовал оба, чтобы получить этот вид 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/…
Туомас Хиетанен
Это для целей тестирования. Просто чтобы посмотреть, работают ли ваши конечные точки. Вы смотрели на SoapUI? soapui.org
Даррел Миллер
@TuomasHietanen - я не получаю ответ типа JSON, используя поведение webHttp, но используя enableWebScript, я получаю ответ типа JSON. Я поместил ResponseFormat как WebMessageFormat.Json. С другой стороны, я не могу использовать URItemplate, если я использую поведение enableWebScript. Любые идеи?
smile.al.d.way
1
@CoffeeAddict - Почему вы должны использовать интерфейс? Просто иметь интерфейс? Вы не будете использовать этот интерфейс никогда. Это проще
Туомас Хиетанен
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: text / html, например, браузер), чтобы вы могли лучше визуализировать выходные данные своих служб.

Обработка различных глаголов REST также тривиальна, вот полное CRUD-приложение REST-service на 1 странице C # (меньше, чем требуется для настройки WCF;):

mythz
источник
7

У MSDN сейчас есть статья для этого:

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

Вступление:

По умолчанию Windows Communication Foundation (WCF) делает конечные точки доступными только для клиентов SOAP. В разделе Практическое руководство. Создание базовой веб-службы WCF HTTP конечная точка становится доступной для клиентов, не являющихся SOAP. Могут возникнуть ситуации, когда вы захотите сделать один и тот же контракт доступным в обоих случаях, в качестве конечной точки Web и конечной точки SOAP. В этой теме показан пример того, как это сделать.

FMFF
источник
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);
    }
}

Присоединяясь ко всем сторонам, это будет наше определение 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>

Чтобы протестировать обе конечные точки, мы можем использовать 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>

Поведение конечной точки

  <endpointBehaviors>
    <behavior name="jsonBehavior">
      <webHttp automaticFormatSelectionEnabled="true"  />
      <!-- use JSON serialization -->
    </behavior>
  </endpointBehaviors>
Найас Субраманян
источник