Legge til REST grensesnitt på eksisterende WCF SOAP kontrakt

Ofte får vi spørsmål om hvordan man kan benytte seg av et eksisterende sett med WCF tjenester og utvide dette for å støtte REST, enten ved at man vil legge til ny funksjonalitet, eller som en utvidelse av eksisterende grensesnitt. De glade nyhetene er at WCF støtter REST ut av esken, og det eneste man behøver å gjøre er noen veldig få ting.

Litt basiskode for WCF

En standard SOAP kontrakt refererer normalt til .Net bibliotekene System.Servicemodel og System.Runtime.Serialization der den finner alt den trenger for å fungere. Førstnevnte gir WCF binding til prosjektet mens sistnevnte hjelper til med automagisk serialisering til XML.

IPeopleService.cs:

 namespace WcfService.ServiceContracts
{
    [ServiceContract]
    public interface IPeopleService
    {
        [OperationContract]
        Task<Person> GetById(int id);

        [OperationContract]
        Task<IEnumerable<Person>> GetAll(int limit);
    }
}

 

Overgang til REST

Overgangen til REST er enkel. Det du må gjøre for å få ut et REST grensesnitt er følgende:

  • Du må referere til Assembly System.ServiceModel.Web
  • Du må legge til verb og adressemal i kontrakten (IPeopleService)
  • App.Config må tilby et ekstra endepunkt for REST tjenestene basert på binding WebHttpBinding
  • En egen bindingBehavior lages og knyttes til endepunktet
  • Ta hensyn til at alle parametre til et REST kall er tegnstrenger:

Etter å ha lagt inn referansen, oppretter vi en ny kontrakt som bare tar imot tegnstrenger

     [ServiceContract]
    public interface IRestPeopleService
    {
        [OperationContract, WebGet(UriTemplate="person/{id}")]
        Task<Person> GetById(string id);

        [OperationContract, WebGet(UriTemplate="all/{limit}")]
        Task<IEnumerable<Person>> GetAll(string limit);
    }

Deretter legger vi til et nytt bindingspunkt i App.Config:

 <endpoint address="rest" 
          binding="webHttpBinding" 
          bindingBehavior="restConfig" 
          contract="WcfService.ServiceContracts.IRestPeopleService" 
          />

Dette endepunktet lander i en ny “Service”  i App.Config som alene definerer et REST endepunkt. Dersom du allerede har metoder i din service som kun tar imot tegnstrenger som parametre, så slipper du unna ved å bare legge til et ekstra endepunkt slik eksemplet over viser.

“restConfig” er en bindingskonfigurasjon som man må definere. Nøkkelen her er WebHttp konfigurasjonen som effektivt gjør om endepunktet til et REST endepunkt:

 <endpointBehaviors>
  <behavior name="restConfig">
    <webHttp helpEnabled="true" defaultOutgoingResponseFormat="Json"/>
  </behavior>
</endpointBehaviors>

Implementasjonen av IRestPeopleService er rett frem. Her er et utkast som gjenbruker koden i PeopleService ved å arve den:

 public class RestPeopleService : PeopleService, IRestPeopleService
{
    public async Task<Person> GetById(string id)
    {
        int realId;
        if (!int.TryParse(id, out realId))
            return null;

        return await base.GetById(realId);
    }

    public async Task<IEnumerable<Person>> GetAll(string limit)
    {
        int realLimit;
        if (!int.TryParse(limit, out realLimit))
            return null;

        return await base.GetAll(realLimit);
    }
}