REST / SOAP titik akhir untuk layanan WCF

425

Saya memiliki layanan WCF dan saya ingin mengeksposnya sebagai layanan RESTfull dan sebagai layanan SOAP. Adakah yang pernah melakukan hal seperti ini sebelumnya?

Wessam Zeidan
sumber
pertanyaan bagus dan jawaban bagus.
chandra rv

Jawaban:

584

Anda dapat mengekspos layanan dalam dua titik akhir yang berbeda. satu SOAP dapat menggunakan pengikatan yang mendukung SOAP misalnya basicHttpBinding, yang SISA dapat menggunakan webHttpBinding. Saya berasumsi layanan REST Anda akan berada di JSON, dalam hal ini, Anda perlu mengonfigurasi dua titik akhir dengan konfigurasi perilaku berikut

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

Contoh konfigurasi titik akhir dalam skenario Anda adalah

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

jadi, layanan akan tersedia di

Terapkan [WebGet] ke kontrak operasi untuk membuatnya TENANG. misalnya

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

Catatan, jika layanan REST tidak dalam JSON, parameter operasi tidak dapat berisi tipe kompleks.

Membalas posting untuk SOAP dan RESTful POX (XML)

Untuk XML tua biasa sebagai format pengembalian, ini adalah contoh yang akan bekerja untuk SOAP dan XML.

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

Perilaku POX untuk REST Plain Old XML

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

Titik akhir

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

Layanan akan tersedia di

Permintaan REST mencobanya di browser,

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

SOAP meminta konfigurasi titik akhir klien untuk layanan SOAP setelah menambahkan referensi layanan,

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

dalam C #

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

Cara lain untuk melakukannya adalah mengekspos dua kontrak layanan yang berbeda dan masing-masing dengan konfigurasi spesifik. Ini dapat menghasilkan beberapa duplikat di tingkat kode, namun pada akhirnya, Anda ingin membuatnya berfungsi.

codemeit
sumber
11
Bagaimana ini terlihat ketika saya memiliki .svc di-host di IIS di beberapa direktori virtual seperti someserver / myvirtualdir / service.svc ? Bagaimana saya harus mengaksesnya?
Sunny Milenov
Saya ingin mengambil langkah ini lebih jauh dan menambahkan ikatan ke HTTPS untuk alamat JSON. Bagaimana aku melakukan itu? stackoverflow.com/questions/18213472/…
Steve
Dikatakan bahwa kontrak IEvents saya tidak valid ketika saya mencoba mereferensikan Antarmuka Layanan saya: <service name = "Events"> <endpoint address = "json" binding = "webHttpBinding" behaviorConfiguration = "jsonBehavior" contract = "IEvents" />. IEvents saya memiliki atribut [ServiceContract] pada antarmuka jadi tidak yakin mengapa. </service>
PositiveGuy
Saya bisa mendapatkan localhost: 44652 / MyResource / json untuk bekerja tetapi saya tidak bisa mendapatkan id untuk bekerja localhost: 44652 / MyResource / 98 / json . Saya sudah mencoba menambahkan UriTemplate "/ {id}", juga mencoba "events / {id} tetapi tidak menemukannya ketika saya mencoba mengakses layanan. Hanya yang pertama berfungsi, tidak yakin bagaimana cara mendapatkan yang terakhir untuk bekerja
PositiveGuy
2
Bagaimana cara kerjanya tanpa file fisik di sana? Saya sepertinya mendapatkan 404 kesalahan, pasti melewatkan sesuatu
RoboJ1M
39

Posting ini sudah memiliki jawaban yang sangat bagus oleh "Komunitas wiki" dan saya juga merekomendasikan untuk melihat Blog Web Rick Strahl, ada banyak posting bagus tentang WCF Istirahat seperti ini .

Saya menggunakan keduanya untuk mendapatkan layanan MyService semacam ini ... Kemudian saya bisa menggunakan antarmuka-REST dari jQuery atau SOAP dari Java.

Ini dari Web saya. Konfigurasi:

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

Dan ini adalah kelas layanan saya (.svc-codebehind, tidak diperlukan antarmuka):

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

Sebenarnya saya hanya menggunakan Json atau Xml tetapi keduanya ada di sini untuk tujuan demo. Itu adalah GET-permintaan untuk mendapatkan data. Untuk memasukkan data, saya akan menggunakan metode dengan atribut:

[OperationContract(Name = "MyResourceSave")]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "MyJsonResource")]
public string MyResourceSave(string thing){
    //...
Tuomas Hietanen
sumber
Saya ingin tahu manfaat apa yang Anda yakin akan dapatkan dengan menambahkan atribut WebGet dan WebInvoke ini.
Darrel Miller
2
Anda dapat membuat permintaan dengan browser: localhost / MyService.svc / MyXmlResource / test Dan secara eksplisit mengatakan format Json atau Xml. Jika Anda ingin metode yang sama merespons keduanya, berikut ini tautannya: blogs.msdn.com/dotnetinterop/archive/2008/11/04/…
Tuomas Hietanen
Ini untuk tujuan pengujian. Hanya untuk melihat apakah titik akhir Anda berfungsi. Sudahkah Anda melihat SoapUI? soapui.org
Darrel Miller
@ TuomasHietanen - Saya tidak mendapatkan respons tipe JSON dengan menggunakan perilaku webHttp namun menggunakan enableWebScript saya mendapatkan respons tipe JSON. Saya memang menaruh ResponseFormat sebagai WebMessageFormat.Json. Di sisi lain saya tidak bisa menggunakan URItemplate jika saya menggunakan perilaku enableWebScript. Ada ide?
smile.al.d.way
1
@CoffeeAddict - Mengapa Anda harus menggunakan inteface? Hanya untuk memiliki antarmuka? Anda tidak akan menggunakan kembali antarmuka ini. Ini lebih sederhana.
Tuomas Hietanen
25

Jika Anda hanya ingin mengembangkan satu layanan web dan memilikinya di-host pada banyak titik akhir yang berbeda (yaitu SOAP + REST, dengan XML, JSON, CSV, output HTML). Anda juga harus mempertimbangkan menggunakan ServiceStack yang telah saya buat untuk tujuan persis ini di mana setiap layanan yang Anda kembangkan tersedia secara otomatis pada SOAP dan REST endpoint out-of-the-box tanpa konfigurasi apa pun yang diperlukan.

Contoh Hello World menunjukkan cara membuat layanan sederhana dengan adil (tidak perlu konfigurasi):

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

Tidak diperlukan konfigurasi lain, dan layanan ini segera tersedia dengan REST di:

Itu juga datang built-in dengan output HTML yang bersahabat (ketika dipanggil dengan klien HTTP yang memiliki Terima: teks / html misalnya browser) sehingga Anda dapat memvisualisasikan output layanan Anda dengan lebih baik.

Menangani berbagai kata kerja REST juga sepele, berikut adalah aplikasi CRUD layanan-REST lengkap dalam 1 halaman C # (kurang dari yang dibutuhkan untuk mengonfigurasi WCF;):

mitos
sumber
7

MSDN tampaknya memiliki artikel untuk ini sekarang:

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

Pengantar:

Secara default, Windows Communication Foundation (WCF) membuat titik akhir hanya tersedia untuk klien SOAP. Dalam Cara: Membuat Layanan HTTP Web WCF Dasar, titik akhir dibuat tersedia untuk klien non-SOAP. Mungkin ada saat-saat ketika Anda ingin membuat kontrak yang sama tersedia dua arah, sebagai titik akhir Web dan sebagai titik akhir SOAP. Topik ini menunjukkan contoh cara melakukan ini.

FMFF
sumber
3

Kita harus mendefinisikan konfigurasi perilaku ke titik akhir REST

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

dan juga ke layanan

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

Setelah perilaku, langkah selanjutnya adalah binding. Misalnya basicHttpBinding ke SOAP endpoint dan webHttpBinding ke REST .

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

Akhirnya kita harus mendefinisikan 2 titik akhir dalam definisi layanan. Perhatian untuk alamat = "" titik akhir, di mana untuk layanan REST tidak diperlukan apa-apa.

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

Dalam Antarmuka layanan, kami mendefinisikan operasi dengan atributnya.

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

Bergabung dengan semua pihak, ini akan menjadi definisi system.serviceModel WCF kami.

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

Untuk menguji kedua titik akhir, kita dapat menggunakan WCFClient untuk SOAP dan PostMan untuk REST .

Jailson Evora
sumber
Bekerja dengan baik seperti yang diharapkan
Shiv
0

Inilah yang saya lakukan untuk membuatnya bekerja. Pastikan Anda memasukkan
webHttp automaticFormatSelectionEnabled = "true" di dalam perilaku endpoint.

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

Model layanan di dalam

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

Perilaku EndPoint

  <endpointBehaviors>
    <behavior name="jsonBehavior">
      <webHttp automaticFormatSelectionEnabled="true"  />
      <!-- use JSON serialization -->
    </behavior>
  </endpointBehaviors>
Subramanian Naya
sumber