Expand Minimize

Calling a Cross Domain WCF Service from a SharePoint Online Solution

Summary:   Insert one-two sentences summarizing your topic.

Last modified: August 07, 2012

Applies to: Business Connectivity Services | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio

In this article
Introduction
Setting up the WCF service
Setting up the client
Sample scenario
Setting up the code sample
Testing the web parts
Conclusion
Additional Resources

Contents

Click to grab code   Download code

This article describes how to call an authenticated Windows Communications Foundation (WCF) service from the SharePoint online sandbox web part by using the jQuery Ajax method. The impetus for this article is that cross-domain authenticated WCF calls are not possible with the default web HTTP binding. This article details the steps required to create a working end-to-end solution by using JQuery.

Note Note

You can learn more about SharePoint sandboxed solutions here: Sandboxed solutions resource center.

Problem definition

Following is a list of issues that must be addressed in order to create the solution:

  • To avoid issues when calling across domains, the solution must use custom bindings that use JSON with padding (JSONP). JSONP allows you to request JSON data from a web service that is not in the same domain. (You can learn more about JSONP by reading JSON with Padding (AJAX).

  • The service must be secure with either message-level or transport-level security using Secure Sockets Layer (SSL). The solution uses SSL, otherwise, Internet Explorer will constantly display a warning about showing non-secure content on a secure site.

  • You must authenticate users on the domain where the service is running. The solution uses the Windows identity coming from the browser and configures the service to negotiate the identity to use either Windows Challenge/Response (NTLM) or Kerberos authentication.

  • Because the script manager is not available in Sandbox mode, it was not possible to use the update panel and, thus, needs to rely on the jQuery Ajax method.

Solution prerequisites

Following is a list of requirements and prerequisites for building and running the sample solution:

  • Subscription to Microsoft SharePoint Online

  • Windows Server 2008 R2

  • or

  • Microsoft Visual Studio 2010, SP1

  • Microsoft .NET Framework 3.5

  • Microsoft SQL Server 2008, R2

  • Visual Studio 2010 SharePoint Power Tools (available here)

  • Microsoft Contoso BI Demo Dataset for Retail Industry (available here)

  • jQuery 1.5.1

The following procedures allow you to set up the WCF service. Because you use the JSONP binding for the web service, you must first set up the JSONP binding library. Next, you set up the WCF Service Application project.

Set up the JSONP binding project

  1. Create an empty Visual Studio solution.

  2. Right-click the solution in Solution Explorer and then click Add new project.

  3. In the New Project pane, select Visual C#, and then select Class Library in the right pane.

  4. Choose .NET Framework 3.5 as the .NET Framework runtime version.

  5. Name the project Microsoft.JsonpBinding and click OK.

  6. Delete the default class (Class1.cs) that came with the template.

  7. Add four files that are available in the sample project

    • JSONPBehavior.cs

    • JSONPBindingElement.cs

    • JSONPBindingExtension.cs

    • JSONPEncoderFactory.cs

  8. Open the References folder and add any missing references to your project. Make sure the solution compiles. Your project structure should appear as shown Figure 1.

    Figure 1. JSONP binding solution structure

    JSONP binding solution structure

After you have your JSONP binding project set up, you are ready to create your WCF service application.

Create the WCF service application

  1. Right-click on the solution you created in the procedure above and click Add new project.

  2. In the New Project screen, select WCF, and then select WCF Service Application in the right pane as shown in Figure 2.

    Figure 2. WCF service application template

    WCF service application template
  3. Name the project Contoso.Service and then click OK.

Once you have created the new WCF service application project, templates are added for the service interface, as well as the SVC file and web configuration files. An SVC file is used by WCF to represent a service hosted by IIS.

In the next procedure, you implement an operation contract to support the scenario. Perform following steps to set up the service and operation contracts.

Create the service and the operation contract

  1. Open the file named IService1.cs file and rename it to IContosoDataService.cs.

  2. Add the following assembly references:

    Table 1. Assembly references

    Reference

    Description

    System.Collections.Generic

    Provides access to the .Net generic data structures.

    System.ServiceModel

    Provides access to the WCF service model.

    Contoso.BusinessEntities

    Specific to the sample project, provides access to the Customer entity class.

    Microsoft.Ajax.Samples

    Provides access to the custom binding classes.

    System.ServiceModel.Web

    Provides access to the web http programming model.

  3. Define the following operation contracts. You will find the attribute descriptions for the following code in Table 2.

    
    [ServiceContract]
        public interface IContosoDataService
        {
            [OperationContract]
            [JSONPBehavior(callback = "callback")]
            [WebGet(UriTemplate = "CreateCustomer?customer={customer}", BodyStyle = WebMessageBodyStyle.Wrapped, 
                ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
            string CreateCustomer(string customer);
    
            [OperationContract]
            [JSONPBehavior(callback = "callback")]
            [WebGet(UriTemplate = "GetCustomerByKey?key={key}", BodyStyle = WebMessageBodyStyle.Wrapped, 
                ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
            DimCustomer GetCustomerByKey(int key);
    
            [OperationContract]
            [JSONPBehavior(callback = "callback")]
            [WebGet(UriTemplate = "GetAllCustomers", BodyStyle = WebMessageBodyStyle.Wrapped, 
                ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
            List<DimCustomer> GetAllCustomers();
    
            [OperationContract]
            [JSONPBehavior(callback = "callback")]
            [WebGet(UriTemplate = "UpdateCustomer?customer={customer}", BodyStyle = WebMessageBodyStyle.Wrapped, 
                ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
            string UpdateCustomer(string customer);
    
            [OperationContract]
            [JSONPBehavior(callback = "callback")]
            [WebGet(UriTemplate = "DeleteCustomer?customer={customer}", BodyStyle = WebMessageBodyStyle.Wrapped, 
                ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
            string DeleteCustomer(string customer);
        }
    
    
    Table 2. Contract attribute descriptions

    Attribute

    Description

    [OperationContract]

    Specifies that the method is an operation as part of the service application.

    [JSONPBehavior(callback = "callback")]

    Indicates that any request for this operation should be dealt with using JSONP behavior.

    [WebGet(UriTemplate = "CreateCustomer?customer={customer}", BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]

    Enables the operation to be called with an HTTP GET call.

  4. Next, you must set up the service configuration. Do this by double-clicking to open the web.config file.

  5. In the web.config file, replace the system-generated configuration code with the following:

    
    <?xml version="1.0"?>
    <configuration>
      <connectionStrings>
        <add name="sqlCon" connectionString="Data Source=.;Initial Catalog=Contoso;Integrated Security=False;User ID=lsuser;Password=Microsoft~1"/>
      </connectionStrings>
      <system.web>
        <compilation debug="true" targetFramework="4.0"/>
        <authentication mode="Windows"/>
        <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/>
      </system.web>
      <system.serviceModel>
        <services>
          <service behaviorConfiguration="Contoso.ServiceBehavior" name="Contoso.Service.ContosoService">
            <endpoint address="" binding="customBinding" contract="Contoso.Service.IContosoDataService" behaviorConfiguration="ContosoServiceEndpointBehavior" bindingConfiguration="httpsJsonpBinding">
              <identity>
                <dns value="localhost"/>
              </identity>
            </endpoint>
            <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
          </service>
        </services>
        <bindings>
          <customBinding>
            <binding name="httpsJsonpBinding">
              <jsonpMessageEncoding/>
              <httpsTransport manualAddressing="true" authenticationScheme="Negotiate" unsafeConnectionNtlmAuthentication="true"/>
            </binding>
          </customBinding>
        </bindings>
        <extensions>
          <bindingElementExtensions>
            <add name="jsonpMessageEncoding" type="Microsoft.Ajax.Samples.JsonpBindingExtension, Microsoft.JsonpBinding, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
          </bindingElementExtensions>
        </extensions>
        <behaviors>
          <endpointBehaviors>
            <behavior name="ContosoServiceEndpointBehavior">
              <webHttp/>
            </behavior>
          </endpointBehaviors>
          <serviceBehaviors>
            <behavior name="Contoso.ServiceBehavior">
              <serviceMetadata httpsGetEnabled="true"/>
              <serviceDebug includeExceptionDetailInFaults="false"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
      </system.serviceModel>
      <system.webServer>
        <modules runAllManagedModulesForAllRequests="true"/>
      </system.webServer>
    </configuration>
    
    

We are now ready implement the service. Because we are using JSON as the format to transfer data between the service and the client, you use JavaScriptSerializer to deserialize data returned in the JSON string. You can see an example of how this is done in the following code snippet:

/// <summary>
        /// To get customer object from JSON string.
        /// </summary>
        /// <param name="customerJSon">JSON serialied string.</param>
        /// <returns>Customer entity.</returns>
        public static DimCustomer GetCustomerObject(string customerJSon)
        {
            JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
            DimCustomer customer = javaScriptSerializer.Deserialize<DimCustomer>(customerJSon);
            return customer;
        }

Serialization to a JSONP string is taken care by the JSONP binding.

ContosoService.svc.cs simply implements the method defined in the IContosoDataService.cs file as shown in the following code:

/// <summary>
    /// Implements IContosoDataService.
    /// </summary>
    public class ContosoService : IContosoDataService
    {
        public string CreateCustomer(string customer)
        {
            CustomerDataAccess custDataAccess = new CustomerDataAccess();
            bool result = custDataAccess.CreateCustomer(CommonFunctions.GetCustomerObject(customer));

            if (result)
            {
                return "Success";
            }
            else
            {
                return "False";
            }
        }

        public DimCustomer GetCustomerByKey(int key)
        {
            CustomerDataAccess custDataAccess = new CustomerDataAccess();
            return custDataAccess.GetCustomerByKey(key);
        }

        public List<DimCustomer> GetAllCustomers()
        {
            CustomerDataAccess custDataAccess = new CustomerDataAccess();
            return custDataAccess.GetAllCustomers();
        }

        public string UpdateCustomer(string customer)
        {
            CustomerDataAccess custDataAccess = new CustomerDataAccess();
            bool result = custDataAccess.UpdateCustomer(CommonFunctions.GetCustomerObject(customer));
            if (result)
            {
                return "Success";
            }
            else
            {
                return "False";
            }
        }

        public string DeleteCustomer(string customer)
        {
            CustomerDataAccess custDataAccess = new CustomerDataAccess();
            bool result = custDataAccess.DeleteCustomer(CommonFunctions.GetCustomerObject(customer));
            if (result)
            {
                return "Success";
            }
            else
            {
                return "False";
            }
        }
    }

The next step is to create a web application in IIS 7.0 to host the Contoso web service.

Create a web application to host the service

  1. Click Start, click Run, and then type "inetmg" to open the IIS Manager console.

  2. Right-click the Application Pools icon and then click Add Application Pool.

  3. Provide a name for the application pool, then select .Net Framework 4.

  4. Keep the Pipeline Mode set to Integrated and then click OK to create the application pool.

  5. Right-click the Sites folder, then click Add web site. Name the site ContosoDataService.

  6. Select the application pool that you just created.

  7. In Visual Studio, specify the physical path to publish the WCF binaries.

  8. In the binding section, set the Protocol to HTTPS and the port to 4431 (or any other free port).

  9. Select an available SSL certificate. If you do not have a SSL certificate, create a self-signed certificate from IIS or use cert.exe to generate the certificate.

  10. Click OK to create the web application.

Next, we must set up authentication.

Configure authentication

  1. Click the web application and in the feature view in the right pane, click the Authentication. Enable both Windows and Anonymous authentication. Enabling anonymous authentication at the IIS level does not mean that the WCF service will also use anonymous authentication.

  2. Select Windows Authentication and then click Providers to make sure that both Negotiate and NTLM have been selected.

If you need to create a self-signed certificate in IIS Manager, consult the following for guidance:

Once you have obtained the self-signed certificate, bind it to your web application by doing the following procedures. First, you must set up SSL for the service inside IIS and bind the service. Then you must publish the service to the web application.

Set up SSL and bind the certificate

  1. Click Start, click Run, and then type "inetmg" to open the IIS Manager console.

  2. Right-click on the web application that is hosting the service and click Edit Bindings.

  3. In the Site Binding dialog box, click Add, as shown in Figure 3.

    Figure 3. Site binding dialog box

    Site binding dialog boxes
  4. From the Type dropdown list, select HTTPS and in the Port box type the number for any unused port.

  5. In the SSL certificate dropdown list, select the certificate and then click OK to add the binding.

  6. Finally, navigate to the service in Internet Explorer with a fully qualified service URL using https as the protocol (for example, https://mymachine.redmond.corp.microsoft.com:4431/ContosoService/Service.svc).

To publish the service to the web application you just created, use the publishing features of Microsoft Visual Studio. Perform the following steps to publish the service.

Publish the service to the web application

  1. Right-click the WCF service application project and then click on Publish.

  2. Select File System as the publish method.

  3. In the target location, specify the path to the directory which you created while creating the web application, as shown in Figure 4.

    Figure 4. Publishing options

    Publishing options
  4. Click Publish to complete the process and close the dialog box.

If the service is properly published the system will push WCF service data to the directory and you can browse the service in Internet Explorer. You can test this by the following means:

Test the service

  1. Open Internet Explorer and enter the service URL in the address bas as follows: https://<mymachine>.<FQDN>:<port>/ContosoService/Service.svc. The browser will navigate to the default service page if the deployment was successful.

  2. In the browser address bar, add a WSDL query string parameter to retrieve the service metadata. The URL should now look like this: https://<mymachine>.<FQDN>:<port>/ContosoService/Service.svc?wsdl

    If you are able to browse both the service and the metadata, the service deployment was successful.

To set up the client you must create client web parts to consume the web service. The procedures following tell you how to create the visual web part (as a sandboxed solution), how to call the service, then deploy it, and finally how to test your solution.

Be sure to review the system prerequisites in Setting up the code sample before starting these procedures.

Create a sandboxed visual web part

  1. Right-click the solution and then click on Add New Item.

  2. In the Add New Item dialog box, select SharePoint 2010.

  3. In the right pane, select Visual Web Part (Sandboxed).

  4. Enter a name for the web part and click OK.

  5. In the solution file, add code to call any of the required CRUD operations (Create, Read, Update, Delete). Method calls are included in the attached sample.

    To illustrate, following is example code that uses the Create() method to provide a customer write operation:

    <script type="text/javascript" src="/Style Library/Contoso/JS/Custom.js"></script>
    <script type="text/javascript" src="/Style Library/Contoso/JS/json2.js"></script>
    <table>
        <tr>
            <td>
                <asp:Label ID="lblCustomerCrud" runat="server" Text="Create Customer"></asp:Label>
            </td>
        </tr>
        <tr>
            <td>
                <asp:Label ID = "lblFirstName" runat="server" Text="FirstName"></asp:Label>
            </td>
            <td>
                <asp:TextBox ID="txtFirstName" runat="server"></asp:TextBox>
            </td>
        </tr>
        <tr>
            <td>
                <asp:Label ID="lblLastName" runat="server" Text="LastName"></asp:Label>
            </td>
            <td>
                <asp:TextBox ID="txtLastName" runat="server"></asp:TextBox>
            </td>
        </tr>
        <tr>
            <td>
                <asp:Label ID="lblBirthDate" runat="server" Text="BirthDate"></asp:Label>
            </td>
            <td>
                <asp:TextBox ID="txtBirthDate" runat="server"></asp:TextBox>
            </td>
        </tr>
        <tr>
            <td>
                <asp:Label ID="lblMaritalStatus" runat="server" Text="MaritalStatus"></asp:Label>
            </td>
            <td>
                <asp:TextBox ID="txtMaritalStatus" runat="server"></asp:TextBox>
            </td>
        </tr>
        <tr>
            <td>
                <asp:Label ID="lblGender" runat="server" Text="Gender"></asp:Label>
            </td>
            <td>
                <asp:TextBox ID="txtGender" runat="server"></asp:TextBox>
            </td>
        </tr>
        <tr>
            <td>
                <asp:Label ID="lblEmailAddress" runat="server" Text="EmailAddress"></asp:Label>
            </td>
            <td>
                <asp:TextBox ID="txtEmailAddress" runat="server"></asp:TextBox>
            </td>
        </tr>
        <tr>
            <td>
                <asp:Label ID="lblYearlyIncome" runat="server" Text="YearlyIncome"></asp:Label>
            </td>
            <td>
                <asp:TextBox ID="txtYearlyIncome" runat="server"></asp:TextBox>
            </td>
        </tr>
        <tr>
            <td>
                <asp:Label ID="lblTotalChildren" runat="server" Text="TotalChildren"></asp:Label>
            </td>
            <td>
                <asp:TextBox ID="txtTotalChildren" runat="server"></asp:TextBox>
            </td>
        </tr>
        <tr>
            <td>
                <asp:Label ID="lblNumberChildrenAtHome" runat="server" Text="NumberChildrenAtHome"></asp:Label>
            </td>
            <td>
                <asp:TextBox ID="txtNumberChildrenAtHome" runat="server"></asp:TextBox>
            </td>
        </tr>
        <tr>
            <td>
                <asp:Label ID="lblEducation" runat="server" Text="Education"></asp:Label>
            </td>
            <td>
                <asp:TextBox ID="txtEducation" runat="server"></asp:TextBox>
            </td>
        </tr>
        <tr>
            <td>
                <asp:Label ID="lblOccupation" runat="server" Text="Occupation"></asp:Label>
            </td>
            <td>
                <asp:TextBox ID="txtOccupation" runat="server"></asp:TextBox>
            </td>
        </tr>
        <tr>
            <td>
                <asp:Label ID="lblAddressLine1" runat="server" Text="AddressLine1"></asp:Label>
            </td>
            <td>
                <asp:TextBox ID="txtAddressLine1" runat="server"></asp:TextBox>
            </td>
        </tr>
        <tr>
            <td>
                <asp:Label ID="lblPhone" runat="server" Text="Phone"></asp:Label>
            </td>
            <td>
                <asp:TextBox ID="txtPhone" runat="server"></asp:TextBox>
            </td>
        </tr>
        <tr>
            <td>
                <asp:Button ID="btnSave" Text="Save" runat="server" OnClientClick="return SaveCustomer()"/>
            </td>
        </tr>
    </table>
    

Call the service with the jQuery AJAX method

Use a JQuery AJAX method to call the WCF service that you created. Following is the syntax and documentation for the service call:

$.ajax({
        dataType: "jsonp",
        url: serviceUrl + "callback=ProcessResponse&$format=json&customer=" + JSON.stringify(queryParams),
        cache: false,
        jsonp: false,
        data: {},
        jsonpCallback: "ProcessResponse"
    });

JQuery syntax descriptions

Syntax

Description

Callback

The query string parameter that specifies which method to call when the service call returns.

$format

The query string parameter that is used by the JSONP binding to specify which data format to use.

Customer

The query string parameter that is used to send a stringified JSON object, which is de-serialized, into an intermediate language (IL) object with the help of JavaScriptSerializer. A stringified object is an object represented by JSON notation.

JSON.stringify

Converts a JSON object to a string representation.

jsonpCallback

Specifies which method jQuery should call when the service call returns.

Deploying the web part

Deploying the web part is straight-forward. To deploy the web part, just create a WSP package and upload it to the test site collection in SharePoint online. For more information, see How to: Create a SharePoint Solution Package in Visual Studio.

Test the solution

To test the web part simply create five web part pages and add each web part to a separate page. For more information, see the following:

In this section we provide a description of the sample that accompanies this article. The sample demonstrates CRUD operations as well as bulk GET operations on a customer entity in the sample Contoso database (Microsoft Contoso BI Demo Dataset for Retail Industry).

CRUD operations

The customer entity from the Contoso BI database appears as depicted in Figure 5.

Figure 5. Contos0 database retail customer entity

Contoso retail customer entity

Contoso WCF service

The Contoso WCF service as described in the previous sections implements CRUD and a bulk GET operation on customer entity in Contoso BI Retail database.

Contoso web parts

Following in Figures 6, 7, 8, and 9 are depictions of Contoso web parts representing the four CRUD operations:

Figure 6. Create Customer web part (CustomerCreateWebPart)

Create Customer web part
Figure 7. Edit Customer web part (CustomerUpdateWebPart)

Edit Customer web part
Figure 8. Read Customer web part (GEtCustomerByKey)

Read Customer web part
Figure 9. Delete Customer web part (DeleteCustomerWebPart)

Delete Customer web part

To set up the code sample, do the following:

How to: Set up the code sample

  1. Open the solution in Visual Studio.

  2. In the Contoso.Customer.UI project, expand the ContosoJS module.

  3. Open Custom.js file and change the service URL to the URL of your service.

  4. Download Contoso BI Retail database (Microsoft Contoso BI Demo Dataset for Retail Industry).

  5. Backup the BI database and then restore it with the name "Contoso".

  6. Create a SQL Server user and update the connection string in the web.config.

  7. Deploy the Contoso data service. For guidance, refer to the steps given in the prior section, Setting up the WCF service.

  8. Test the successful setup by opening Internet Explorer and browsing to the service.

  9. Create the WSP package of Contoso.Customer.UI project and deploy the package.

  10. Create the five web part pages; add each web part to a separate page.

To test the web parts we will deploy each one to a site in SharePoint online.

Test the Create Customer web part

  1. Open the page that contains the Create Customer web part.

  2. Fill in the form fields and click Save.

  3. Once the service call returns and if the customer create operation was successful you will see a JavaScript message, "Customer created successfully".

  4. Open SQL Server management studio and do a select operation on customer entity, you should see a new customer added in the table.

Test the Edit Customer web part

  1. Open the page that contains the Edit Customer web part.

  2. Enter the customer key in Customer Key text box to fetch the customer.

  3. Once the customer is fetched that means your get operation is working fine.

  4. Edit any customer field and click the Update button.

  5. If the operation was successful you will see a JavaScript message, "Customer updated successfully".

  6. Run a Select operation on the Contoso database and confirm the updated data in the modified field.

Test the Delete Customer web part

  1. Open the page that contains the Delete Customer web part.

  2. Enter the customer key in Customer Key text box to fetch a customer.

  3. Once the customer is fetched that means your get operation is working fine.

  4. Click the Delete button to delete the customer.

  5. If the operation was successful you will see a JavaScript message, "Customer deleted successfully".

  6. Run a Select operation on the Contoso database and confirm the deleted customer is not returned.

Test the Read Customer web part

  1. Open the page that contains the Get Customer web part.

  2. Enter the customer key in Customer Key text box to fetch a customer.

  3. Once the customer is fetched that means your get operation is working fine.

  4. You will be able to view customer details in the customer form fields.

Test the All Customer web part

  1. Open the page that contains the Get Customer web part.

  2. Click the Get Customers button.

  3. If the operation is successful then you should see the customers rendered in a grid form on the page.

For more information, see the following resources:

Show:
© 2014 Microsoft