โปรเจ็กส์ WCF แบบ REST

เมื่อสร้างโปรเจ็กส์แบบ WCF Service Application จะเป็นแบบ SOAP ถ้าจะให้เป็น REST ต้องมา config

  1. สร้างโปรเจ็กส์แบบ WCF
  2. ทดลองรัน
  3. ทำให้รองรับการเรียกแบบ GET
  4. ทำให้รองรับการเรียกแบบ POST
  5. คอนฟิกให้ใช้ https

1.สร้างโปรเจ็กส์แบบ WCF

สร้างโปรเจ็กส์แบบ WCF Service Application ชื่อ WcfService1

จะได้ไฟล์ IService1.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfService1
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
    [ServiceContract]
    public interface IService1
    {

        [OperationContract]
        string GetData(int value);

        [OperationContract]
        CompositeType GetDataUsingDataContract(CompositeType composite);

        // TODO: Add your service operations here
    }


    // Use a data contract as illustrated in the sample below to add composite types to service operations.
    [DataContract]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";

        [DataMember]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }

        [DataMember]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
    }
}

และได้ไฟล์ Service1.svc

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfService1
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
    // NOTE: In order to launch WCF Test Client for testing this service, please select Service1.svc or Service1.svc.cs at the Solution Explorer and start debugging.
    public class Service1 : IService1
    {
        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }

        public CompositeType GetDataUsingDataContract(CompositeType composite)
        {
            if (composite == null)
            {
                throw new ArgumentNullException("composite");
            }
            if (composite.BoolValue)
            {
                composite.StringValue += "Suffix";
            }
            return composite;
        }
    }
}

เมธอด GetData นี้เดี๋ยวเราจะลองเรียกใช้แบบ GET

2.ทดลองรัน

รัน จะเห็น WCF Test Client เป็นอันใช้ได้

ดูว่า Service เรารันอยู่ที่ port ไหน ดูได้จากหน้านี้

ทีนี้ลองเรียกไปที่ http://localhost:55653/Service1.svc จะเห็นแบบนี้

แต่พอลองเรียกแบบ GET ตามนี้ http://localhost:55653/Service1.svc/GetData?value=5 จะขึ้น Error แบบนี้

3.ทำให้รองรับการเรียกแบบ GET

ให้แก้ไขไฟล์ IService1.cs และไฟล์ Web.config

ไฟล์ IService1.cs เพิ่มบรรทัดที่ 6

[ServiceContract]
public interface IService1
{

    [OperationContract]
    [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped)]
    string GetData(int value);

    [OperationContract]
    CompositeType GetDataUsingDataContract(CompositeType composite);

    // TODO: Add your service operations here
}

ไฟล์ Web.config

<?xml version="1.0"?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.6.1" />
    <httpRuntime targetFramework="4.6.1"/>
  </system.web>
  <system.serviceModel>
    <services>
      <service name="WcfService1.Service1" behaviorConfiguration="ServiceBehaviour">
        <endpoint address="" binding="webHttpBinding" contract="WcfService1.IService1" behaviorConfiguration="web"></endpoint>
      </service>
    </services>

    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehaviour">
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>

      <endpointBehaviors>
        <behavior name="web">
          <webHttp automaticFormatSelectionEnabled="true" />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <protocolMapping>
      <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>

</configuration>

บรรทัดที่ 13-14 ต้องใส่ชื่อ namespace ให้ถูกด้วย (ตัวอย่างนี้ namespace เป็น WcfService1)

รันอีกทีจะเรียกแบบ GET ได้ละ

แต่ที่ WCF Test Client จะไม่ขึ้นละ แบบนี้

4.ทำให้รองรับการเรียกแบบ POST

แก้ไขไฟล์ IService1.cs และไฟล์ Service1.svc.cs

ไฟล์ IService1.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfService1
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
    [ServiceContract]
    public interface IService1
    {

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped)]
        string GetData(int value);

        [OperationContract]
        CompositeType GetDataUsingDataContract(CompositeType composite);

        // TODO: Add your service operations here
        [OperationContract]
        [WebInvoke(Method = "POST",
                   RequestFormat = WebMessageFormat.Json,
                   ResponseFormat = WebMessageFormat.Json)]
        Student GetUpdatedStudent(Student std);

    }

    [DataContract]
    public class Student
    {
        [DataMember]
        public string RollNumber { get; set; }
        [DataMember]
        public string Name { get; set; }
    }

    // Use a data contract as illustrated in the sample below to add composite types to service operations.
    [DataContract]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";

        [DataMember]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }

        [DataMember]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
    }
}

ไฟล์ Service1.svc.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfService1
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
    // NOTE: In order to launch WCF Test Client for testing this service, please select Service1.svc or Service1.svc.cs at the Solution Explorer and start debugging.
    public class Service1 : IService1
    {
        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }

        public CompositeType GetDataUsingDataContract(CompositeType composite)
        {
            if (composite == null)
            {
                throw new ArgumentNullException("composite");
            }
            if (composite.BoolValue)
            {
                composite.StringValue += "Suffix";
            }
            return composite;
        }

        public Student GetUpdatedStudent(Student std)
        {
            std.Name = "I have Updated Student Name";
            return std;
        }
    }
}

ตัวอย่างการส่งค่าไปให้ POST

{
    "RollNumber": 1,
    "Name": "Phaisarn"
}

ค่าที่ได้กลับมา

{
    "Name": "I have Updated Student Name",
    "RollNumber": "1"
}

Link

5.คอนฟิกให้ใช้ https

ไฟล์ Web.config

<?xml version="1.0"?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5"/>
  </system.web>
  <system.serviceModel>
    <services>
      <service name="WcfService1.Service1" behaviorConfiguration="ServiceBehaviour">
        <endpoint address="" binding="webHttpBinding" contract="WcfService1.IService1"
                  bindingConfiguration="sslBinding"
                  behaviorConfiguration="web"></endpoint>
        <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />

      </service>
    </services>

    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehaviour">
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>

      <endpointBehaviors>
        <behavior name="web">
          <webHttp automaticFormatSelectionEnabled="true" />
        </behavior>
      </endpointBehaviors>
    </behaviors>

    <bindings>
      <webHttpBinding>
        <binding name="sslBinding" crossDomainScriptAccessEnabled="true">
          <security mode="Transport">
          </security>
        </binding>
      </webHttpBinding>
    </bindings>

    <protocolMapping>
      <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>

</configuration>