Tuesday, August 13, 2013

Creating a custom WCF REST service for SharePoint 2013 without a Visual Studio template

Overview

Recently a colleague asked me how I built REST services for SharePoint 2013, since there is no template for this in Visual Studio 2012. While I have worked with some of the community built templates in the past, they generally require installing additional things on your development server, which really isn't necessary. You can actually stand up a REST service in SharePoint 2013 rather quickly, with just Visual Studio 2012.

Let's start with a video walking you through the process. The video follows the process outlined further down the post. If you want to view the full resolution video, you can download it from Dropbox. You can also download the code built in the video from Dropbox.



Creating the REST service

The basic process for creating your REST service are the following steps, which were demonstrate in the video.

  1. Create a new SharePoint 2013 Empty Project as a Farm Solution
  2. Add a WCF Service Application project to your solution
  3. Add the ISAPI mapped folder to your SharePoint project
  4. Drag the Service1.svc and Service1.svc.cs files from the WCF project to the SharePoint project under the ISAPI mapped folder
  5. Drag the IService1.cs file from the WCF project to the SharePoint project
  6. Add the WCF references to your SharePoint project
    • System.Runtime.Serialization
    • System.ServiceModel
    • System.ServiceModel.Web
  7. Change the namespace from WcfService1 to your assembly's namespace (e.g., MyRestService) in Service1.svc.cs and IService1.cs
  8. Build your project
  9. Using the Visual Studio Command Prompt, go to the project output folder of the SharePoint project
  10. Get the PublicKeyToken for your assembly using the strong name utility
    • sn -T MyRestService.dll
  11. In Service1.svc, change the Service attribute on the ServiceHost directive to be in the following format:
  12. <%@ ServiceHost Language="C#" Debug="true" Service="{NameSpace}.{ServiceName}, {AssemblyName}, Version=1.0.0.0, Culture=Neutral, PublicKeyToken={PublicKeyToken}" CodeBehind="Service1.svc.cs" %>
    
    • Replace the tokens here, represented by {Token} with the appropriate values for your project. e.g., 
    <%@ ServiceHost Language="C#" Debug="true" Service="MyRestService.Service1, MyRestService, Version=1.0.0.0, Culture=Neutral, PublicKeyToken={PublicKeyToken}" CodeBehind="Service1.svc.cs" %>
  13. Deploy your solution
  14. Verify the service loads
    • Note: see below for troubleshooting a common error.
  15. Add a HelloWorld operation to your contract, IService1.cs that is set up for REST.
  16. [OperationContract]
    [WebGet(ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "HelloWorld")
    string HelloWorld();
    
  17. Implement the operation in Service1.svc.cs
  18. public string HelloWorld()
    {
        return "Hello World";
    }
    
  19. Update web.config with the appropriate info for your service
<behaviors>
    <serviceBehaviors>
        <behavior name="Service1ServiceBehavior">
            <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
            <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
    </serviceBehaviors>
    <endpointBehaviors>
        <behavior name="jsonBehavior">
            <webHttp />
        </behavior>
    </endpointBehaviors>
</behaviors>
<services>
    <service name="MyRestService.Service1" behaviorConfiguration="Service1ServiceBehavior">
        <endpoint address="" binding="webHttpBinding" behaviorConfiguration="jsonBehavior" contract="MyRestService.IService1" />
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    </service>
</services>
  1. Test your HelloWorld operation and you should see the following:


Troubleshooting

  • If you get an error that says "This collection already contains an address with scheme http.  There can be at most one address per scheme in this collection." this is due to having multiple bindings in IIS, which is common in SharePoint when you have multiple Alternate Access Mappings.
This collection already contains an address with scheme http.  There can be at most one address per scheme in this collection.
    • In web.config, add the multiplesitebindingsenabled attribute to the servicehostingenvironment element.
    • <servicehostingenvironment aspnetcompatibilityenabled="true" multiplesitebindingsenabled="true"%></servicehostingenvironment%>
      

2 comments:

  1. Hi Mike,

    Why didn't you use the buildin SP2010/SP2013 WCF factory like :

    <%@ ServiceHost Language="C#" Debug="true"
    Service="TimeEntry.Server.TimeEntryService, $SharePoint.Project.AssemblyFullName$"
    CodeBehind="TimeEntryService.svc.cs"
    Factory="Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory, Microsoft.SharePoint.Client.ServerRuntime, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

    I you do that, then is no need to modify web.config

    Ovidiu

    ReplyDelete
    Replies
    1. Great tip, Ovidiu. I had forgotten SharePoint had some magic for services. Definitely something I'll explore when I stand up my next service.

      Mike.

      Delete