Điểm cuối REST / SOAP cho dịch vụ WCF


425

Tôi có một dịch vụ WCF và tôi muốn trưng bày nó vừa là dịch vụ RESTfull vừa là dịch vụ SOAP. Bất cứ ai đã làm một cái gì đó như thế này trước đây?


câu hỏi hay và câu trả lời tuyệt vời
chandra rv

Câu trả lời:


584

Bạn có thể trưng ra dịch vụ ở hai điểm cuối khác nhau. người SOAP có thể sử dụng liên kết hỗ trợ SOAP, ví dụ basicHttpBinding, RESTful có thể sử dụng webHttpBinding. Tôi giả sử dịch vụ REST của bạn sẽ ở dạng JSON, trong trường hợp đó, bạn cần định cấu hình hai điểm cuối với cấu hình hành vi sau

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

Một ví dụ về cấu hình điểm cuối trong kịch bản của bạn là

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

vì vậy, dịch vụ sẽ có sẵn tại

Áp dụng [WebGet] cho hợp đồng vận hành để biến nó thành RESTful. ví dụ

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

Lưu ý, nếu dịch vụ REST không có trong JSON, các tham số của các hoạt động không thể chứa loại phức tạp.

Trả lời bài đăng cho SOAP và RESTful POX (XML)

Đối với XML cũ đơn giản là định dạng trả về, đây là một ví dụ sẽ hoạt động cho cả SOAP và XML.

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

Hành vi POX cho REST Plain XML cũ

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

Điểm cuối

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

Dịch vụ sẽ có sẵn tại

Yêu cầu REST thử nó trong trình duyệt,

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

SOAP yêu cầu cấu hình điểm cuối của máy khách cho dịch vụ SOAP sau khi thêm tham chiếu dịch vụ,

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

trong C #

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

Một cách khác để làm điều đó là để lộ hai hợp đồng dịch vụ khác nhau và mỗi hợp đồng có cấu hình cụ thể. Điều này có thể tạo ra một số trùng lặp ở cấp mã, tuy nhiên vào cuối ngày, bạn muốn làm cho nó hoạt động.


11
Nó trông như thế nào khi tôi có .svc được lưu trữ trong IIS trong một số thư mục ảo như someserver / myvirtualdir / service.svc ? Làm thế nào tôi nên truy cập nó?
Nắng Milenov

Tôi muốn tiến thêm một bước này và thêm một ràng buộc vào HTTPS cho địa chỉ JSON. Làm thế nào để làm điều đó? stackoverflow.com/questions/18213472/ Mạnh
Steve

Điều đó nói rằng hợp đồng của tôi IEvents không hợp lệ khi tôi cố gắng tham chiếu Giao diện dịch vụ của mình: <service name = "Events"> <endpoint address = "json" bind = "webHttpBinding" behaviorConfiguration = "jsonBehavior" hợp đồng = "IEvents" />. IEvents của tôi có thuộc tính [ServiceContract] trên giao diện nên không biết tại sao. </ dịch vụ>
positiveGuy

Tôi có thể làm cho localhost: 44652 / MyResource / json hoạt động nhưng tôi không thể có id để hoạt động localhost: 44652 / MyResource / 98 / json . Tôi đã thử thêm một UriTemplate của "/ {id}", cũng đã thử "sự kiện / {id} nhưng nó không tìm thấy nó khi tôi cố gắng truy cập dịch vụ. Chỉ có hoạt động đầu tiên, không biết làm thế nào để có được cái sau để làm việc.
positiveGuy

2
Làm thế nào nó có thể làm việc mà không có tập tin vật lý ở đó? Tôi dường như nhận được lỗi 404, phải thiếu một cái gì đó
RoboJ1M

39

Bài đăng này đã có một câu trả lời rất hay của "Cộng đồng wiki" và tôi cũng khuyên bạn nên xem Blog Web của Rick Strahl, có nhiều bài viết hay về WCF Rest như thế này .

Tôi đã sử dụng cả hai để có được loại dịch vụ MyService này ... Sau đó tôi có thể sử dụng giao diện REST từ jQuery hoặc SOAP từ Java.

Đây là từ Web.Config của tôi:

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

Và đây là lớp dịch vụ của tôi (.svc-codebehind, không yêu cầu giao diện):

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

Trên thực tế tôi chỉ sử dụng Json hoặc Xml nhưng cả hai đều ở đây cho mục đích demo. Đó là những yêu cầu GET để lấy dữ liệu. Để chèn dữ liệu tôi sẽ sử dụng phương thức với các thuộc tính:

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

Tôi tò mò muốn biết những lợi ích mà bạn tin rằng bạn sẽ nhận được bằng cách thêm các thuộc tính WebGet và WebInvoke này.
Darrel Miller

2
Bạn có thể thực hiện các yêu cầu bằng trình duyệt: localhost / MyService.svc / MyXmlResource / test Và nói rõ ràng định dạng Json hoặc Xml. Nếu bạn muốn cùng một phương thức trả lời cả hai, đây là một liên kết: blog.msdn.com/dotnetinterop/archive/2008/11/04/ ám
Tuomas Hietanen

Đây là cho mục đích thử nghiệm. Chỉ để xem các điểm cuối của bạn đang làm việc. Bạn đã xem SoapUI chưa? Soapui.org
Darrel Miller

@TuomasHietanen - Tôi không nhận được phản hồi loại JSON bằng cách sử dụng hành vi webHttp tuy nhiên sử dụng enableWebScript tôi nhận được phản hồi loại JSON. Tôi đã đặt FeedbackFormat là WebMessageFormat.Json. Mặt khác, tôi không thể sử dụng URItemplate nếu tôi sử dụng hành vi enableWebScript. Có ý kiến ​​gì không?
smile.al.d.way

1
@CoffeeAddict - Tại sao bạn nên sử dụng inteface? Chỉ để có giao diện? Bạn sẽ không sử dụng lại giao diện này bao giờ. Điều này đơn giản hơn.
Tuomas Hietanen

25

Nếu bạn chỉ muốn phát triển một dịch vụ web duy nhất và được lưu trữ trên nhiều điểm cuối khác nhau (ví dụ SOAP + REST, với các kết quả XML, JSON, CSV, HTML). Bạn cũng nên cân nhắc sử dụng ServiceStack mà tôi đã xây dựng cho chính xác mục đích này, nơi mọi dịch vụ bạn phát triển đều tự động có sẵn trên cả hai điểm cuối SOAP và REST mà không cần bất kỳ cấu hình nào.

Các Hello World ví dụ cho thấy cách để tạo ra một đơn giản với dịch vụ chỉ với (không cần config):

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

Không cần cấu hình nào khác và dịch vụ này ngay lập tức có sẵn với REST trong:

Nó cũng được tích hợp sẵn với đầu ra HTML thân thiện (khi được gọi với ứng dụng khách HTTP có Chấp nhận: text / html, ví dụ như trình duyệt) để bạn có thể hình dung rõ hơn về đầu ra của dịch vụ.

Xử lý các động từ REST khác nhau cũng không đáng kể, đây là một ứng dụng CRUD dịch vụ REST hoàn chỉnh trong 1 trang của C # (ít hơn mức cần thiết để định cấu hình WCF;):


7

MSDN dường như có một bài viết cho điều này ngay bây giờ:

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

Giới thiệu:

Theo mặc định, Windows Communication Foundation (WCF) chỉ cung cấp các điểm cuối cho các máy khách SOAP. Trong Cách thực hiện: Tạo Dịch vụ HTTP Web WCF cơ bản, điểm cuối được cung cấp cho các máy khách không SOAP. Có thể đôi khi bạn muốn cung cấp cùng một hợp đồng theo cả hai cách, như một điểm cuối Web và như một điểm cuối SOAP. Chủ đề này cho thấy một ví dụ về cách làm điều này.


3

Chúng ta phải xác định cấu hình hành vi cho điểm cuối REST

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

và cũng cho một dịch vụ

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

Sau các hành vi, bước tiếp theo là các ràng buộc. Ví dụ: basicHttpBinding to SOAP endpoint và webHttpBinding to REST .

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

Cuối cùng, chúng ta phải xác định 2 điểm cuối trong định nghĩa dịch vụ. Chú ý đến địa chỉ = "" của điểm cuối, nơi dịch vụ REST không cần thiết.

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

Trong Giao diện của dịch vụ, chúng tôi xác định hoạt động với các thuộc tính của nó.

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

Tham gia tất cả các bên, đây sẽ là định nghĩa WCF system.serviceModel của chúng tôi.

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

Để kiểm tra cả hai điểm cuối, chúng ta có thể sử dụng WCFClient để SOAPPostMan để REST .


Hoạt động tốt như mong đợi
Shiv

0

Đây là những gì tôi đã làm để làm cho nó hoạt động. Hãy chắc chắn rằng bạn đặt
webHttp AutomaticFormatSelectionEnables = "true" bên trong hành vi điểm cuối.

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

Mô hình dịch vụ bên trong

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

Hành vi Endpoint

  <endpointBehaviors>
    <behavior name="jsonBehavior">
      <webHttp automaticFormatSelectionEnabled="true"  />
      <!-- use JSON serialization -->
    </behavior>
  </endpointBehaviors>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.