Debugging Remote Event Receivers with Visual Studio

Editor’s update (3/21/2013) : The RTM version of the Office Developer Tools for Visual Studio 2012 include tools for debugging remote event receivers. You no longer have to follow the procedure described in this post. Chakkaradeep just published a post about the new tools for debugging remote event receivers. For more information, see Update to debugging SharePoint 2013 remote events using Visual Studio 2012.

Introduction

One of the new features introduced for SharePoint development in the Microsoft Office Developer Tools for Visual Studio 2012 – Preview 2 is the ability to use a remote development environment to build apps for SharePoint. With previous versions of the SharePoint tools in Visual Studio, developers had to install SharePoint Foundation or SharePoint Server locally before they could build SharePoint solutions in Visual Studio. With SharePoint 2013, you can build apps for SharePoint targeting a remote SharePoint 2013 site (installed in a remote server) or SharePoint 2013 Online (Office 365). You don’t have to install SharePoint locally to build apps for SharePoint.

clip_image001

Figure 1. SharePoint 2013 remote development

Remote development allows you to deploy and debug an app for SharePoint on a remote SharePoint website. When there is a web project involved, as in the case of autohosted or provider-hosted apps, debugging is achieved by running the web project locally on Internet Information Services (IIS) Express.

clip_image002

Figure 2. Apps for SharePoint debugging experience

During remote app development, you create remote event receivers and app event receivers to handle events such as list events, list item events, and app events. If you are new to remote event receivers, get a quick overview in Handling events in apps for SharePoint.

However, debugging a remote event receiver locally is challenging because the locally running IIS Express would typically not be reachable from the remote SharePoint server. When the remote SharePoint server cannot reach the local development machine due to network boundaries, some extra work is required to invoke the remote event receiver.

clip_image004

Figure 3. Debugging remote event receivers

This blog post describes how to use the Windows Azure Service Bus to work around the network boundary issue so as to enable remote event receiver debugging when using a remote development for building apps for SharePoint with the Preview 2 release.

Sample project

Add a remote event receiver

Windows Azure Service Bus to the rescue

Add Service Bus extensions to the web project

Update the app manifest

Debug the remote event receiver

Publish your app to the marketplace

Download the sample app

Remote event debugging FAQ

Sample project

I have a simple autohosted app that adds items to a contacts list.

Here’s how it looks:

clip_image006

Figure 4. Autohosted app that adds items to a contacts list

Add Contact will add the contact with the given first name and last name. However, as you can see, it does do not set the full name of the contact. The full name can be as simple as (First Name + “ “ + Last Name).

Here is the snapshot of Solution Explorer:

clip_image007

Figure 5. Project in Solution Explorer

Add a remote event receiver

Let’s use a remote event receiver to set the FullName property of a contact.

You can add a new remote event receiver by right-clicking the app for SharePoint project and choosing Add,New Item,Remote Event Receiver.

Let’s name the remote event receiver ContactsListRER.

clip_image009

Figure 6. Adding a remote event receiver

When you click Add, a wizard starts. For this example, we will handle the following event: An item was added.

clip_image010

Figure 7. SharePoint Customization Wizard

This adds the ContactsListRER.svc— a remote event receiver service—to the web project:

clip_image011

Figure 8. Remote event receiver service added

At the same time, a remote event receiver item is added to the app for SharePoint project:

clip_image012

Figure 9. Remote event receiver item added

Open ContactsListRER.svc.cs and replace the ProcessOneWayEvent code with the following code:

 public void ProcessOneWayEvent(SPRemoteEventProperties properties)
{
    using (ClientContext clientContext =
        TokenHelper.CreateRemoteEventReceiverClientContext(properties))
    {
        if (clientContext != null)
        {
            string firstName =
                properties.ItemEventProperties.AfterProperties[
                    "FirstName"
                    ].ToString();

            string lastName =
                properties.ItemEventProperties.AfterProperties[
                    "LastNamePhonetic"
                    ].ToString();

            List lstContacts =
                clientContext.Web.Lists.GetByTitle(
                    properties.ItemEventProperties.ListTitle
                );

            ListItem itemContact =
                lstContacts.GetItemById(
                    properties.ItemEventProperties.ListItemId
                );

            itemContact["FullName"] =
                String.Format("{0} {1}", firstName, lastName);
            itemContact.Update();

            clientContext.ExecuteQuery();
        }
    }
}

The code retrieves the item properties FirstName and LastName and generates the full name. It then updates the FullName property with the full name value.

The remote event receiver’s Elements.xml file provides the information to SharePoint as to where the remote event receiver service is hosted. If you look through the file’s contents, you will see the Url property:

 <?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="https://schemas.microsoft.com/sharepoint/">
  <Receivers ListTemplateId="10000">
      <Receiver>
        <Name>ContactsListRER.svcItemAdded</Name>
        <Type>ItemAdded</Type>
        <SequenceNumber>10000</SequenceNumber>
        <Url>~remoteAppUrl/ContactsListRER.svc.svc</Url>
      </Receiver>
  </Receivers>
</Elements>

Notice that the following token is used to resolve the remote App Url: ~remoteAppUrl

  • ~remoteAppUrl will be replaced with https://localhost:[port-number] when you are debugging locally in your development environment as the web project is hosted in IIS Express.
  • ~remoteAppUrl will be replaced with the Windows Azure instance when the app is deployed to the SharePoint Online site.
  • For provider-hosted apps, you can replace this value with the actual service Url

During F5 (debugging), if you are building a high trust app, you may not have any issues calling the remote event receiver service as long as your local SharePoint instance can reach the service. However, if SharePoint is not able to reach the service, the remote event receiver will fail to work in debugging mode.

Windows Azure Service Bus to the rescue

Windows Azure Service Bus provides a hosted, secure connectivity options for Windows Communication Foundation (WCF) and other service endpoints, including REST (Representational State Transfer) endpoints that would otherwise be difficult or impossible to reach. Most importantly, Service Bus endpoints can be located behind network address translation (NAT) boundaries or dynamically assigned IP addresses. This means that the Service Bus Relay can expose select WCF services that reside within your internal network to the public cloud, without having to open a firewall connection or requiring any changes to your network infrastructure.

We will use the Service Bus to create and host the remote event receiver service in a Service Bus endpoint, and update the remote App Url to be the Service Bus endpoint. This will then enable SharePoint to directly talk to the Service Bus endpoint, which will then call back to your service running in IIS Express.

To use Windows Azure Service Bus, the following things are required:

  • Register a Windows Azure account and then a Service Bus namespace. See Managing Service Bus Service Namespaces for more information about managing namespaces.
  • If you are behind a firewall, a proxy client (such as TMG proxy client) may be required depending on your network topology.

Add Service Bus extensions to the web project

In order to work with the Service Bus, we will need to reference Service Bus assemblies in the web project.

We can make use of the Service Bus NuGet package to reference the assemblies:

  1. Right-click the web project, and select Manage NuGet Packages .
  2. Search for the following package online: windowsazure.servicebus.
  3. Select Windows Azure Service Bus and then select Install .

This will install the NuGet package

The next step is to update the web.config file to create and host the Service Bus endpoint. Replace the entire code within the <system.servicemodel> with the following:

 <system.serviceModel>
    <bindings>
        <basicHttpBinding>

            <!--Used by app for SharePoint-->
            <binding name="secureBinding">
                <security mode="Transport" />
            </binding>
        </basicHttpBinding>

        <!-- Service Bus Binding -->
        <basicHttpRelayBinding>
            <binding name="BasicHttpRelayBindingConfig">
                <security relayClientAuthenticationType="None" />
            </binding>
        </basicHttpRelayBinding>

        <!-- Service Bus Binding -->
    </bindings>
    <protocolMapping>
        <add 
            binding="basicHttpBinding" 
            scheme="https" 
            bindingConfiguration="secureBinding" />
    </protocolMapping>
    <extensions>

        <!-- In this extension section we are introducing all known service 
        bus extensions. Users can remove the ones they don't need. -->
        <behaviorExtensions>
            <add 
                name="transportClientEndpointBehavior" 
type=
"Microsoft.ServiceBus.Configuration.TransportClientEndpointBehaviorElement, 
                    Microsoft.ServiceBus, 
                    Version=1.8.0.0, 
                    Culture=neutral, 
                    PublicKeyToken=31bf3856ad364e35" />
            <add 
                name="serviceRegistrySettings" 
type="Microsoft.ServiceBus.Configuration.ServiceRegistrySettingsElement, 
                    Microsoft.ServiceBus, 
                    Version=1.8.0.0, 
                    Culture=neutral, 
                    PublicKeyToken=31bf3856ad364e35" />
        </behaviorExtensions>
        <bindingExtensions>
            <add 
                name="basicHttpRelayBinding" 
type=
"Microsoft.ServiceBus.Configuration.BasicHttpRelayBindingCollectionElement, 
                    Microsoft.ServiceBus, 
                    Version=1.8.0.0, 
                    Culture=neutral, 
                    PublicKeyToken=31bf3856ad364e35" />
        </bindingExtensions>
    </extensions>

    <!-- Service Bus Binding -->
    <services>
        <clear />
        <service 
            name="[your RER service class name with namespace]" 
            behaviorConfiguration="default">
            <endpoint 
                address="[your IIS Express http address]" 
                binding="basicHttpBinding" 
contract="Microsoft.SharePoint.Client.EventReceivers.IRemoteEventService"/>
            <endpoint 
                address="[your IIS Express http address]/mex" 
                binding="mexHttpBinding" 
                contract="IMetadataExchange" />
            <endpoint 
                address="[your service bus namespace]/[your address]" 
contract="Microsoft.SharePoint.Client.EventReceivers.IRemoteEventService" 
                binding="basicHttpRelayBinding" 
                bindingConfiguration="BasicHttpRelayBindingConfig" 
                behaviorConfiguration="sharedCredentials" />
        </service>
    </services>
    <behaviors>
        <serviceBehaviors>
            <behavior name="default">

                <!-- 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="true" />
            </behavior>
        </serviceBehaviors>
        <endpointBehaviors>
            <behavior name="sharedCredentials">
                <transportClientEndpointBehavior 
                    credentialType="SharedSecret">
                    <clientCredentials>
                        <sharedSecret 
                            issuerName="[your service bus issuer name]" 
                            issuerSecret="[your service bus secret]" />
                    </clientCredentials>
                </transportClientEndpointBehavior>
                <serviceRegistrySettings discoveryMode="Public" />
            </behavior>
        </endpointBehaviors>
    </behaviors>

    <!-- Service Bus Binding -->
</system.serviceModel>

Replace the following with your own values:

Text to replace

Replace with

Comments

[your RER service class name with namespace]

Generated remote event receiver class in the web project

For example: SharePointAppREDWeb.ContactsListRER

Double-click the .svc in the web project to view the RER class name.

[your IIS Express http address]

IIS Express HTTP Port

You can get the IIS Express port numbers from the web project properties pane

[your service bus namespace]/[your address]

Windows Azure Service Bus Namespace and your choice of address

You will need to sign up for a Windows Azure Service Bus account and create a namespace.

You can use any name for the address name, and it denotes the service you are hosting in the Service Bus namespace. For example: https://spappdebug.servicebus.windows.net/hellospservice

[your service bus issuer name]

Service Bus Namespace Issuer Name

You can get this from your Service Bus Access Key properties.

[your service bus secret]

Service Bus Namespace Secret

You can get this from your Service Bus Access Key properties.

One last change to the web project is to set the ContactsListRER.svc as the start page. This will enable IIS Express to automatically host the service and create the Service Bus endpoint as specified in the web.config file:

  • Right-click ContactsListRER.svc.
  • Select Set as Start Page.

Update the remote app Url in the SharePoint project

In the app for SharePoint project:

  1. Open ContactsListRER | Elements.xml
  2. Replace the Url property for the event receiver with [your service bus namespace]/[your address].

Text to replace

Replace with

Comments

[your service bus namespace]/[your address]

Windows Azure Service Bus Namespace and your choice of address

The same values as the corresponding entries in web.config

Below is the updated Elements.xml:

 <?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="https://schemas.microsoft.com/sharepoint/">
  <Receivers ListTemplateId="10000">
      <Receiver>
        <Name>ContactsListRER.svcItemAdded</Name>
        <Type>ItemAdded</Type>
        <SequenceNumber>10000</SequenceNumber>

        <!--<Url>~remoteAppUrl/ContactsListRER.svc</Url>-->
        <Url>https://spappdebug.servicebus.windows.net/rerdemo</Url>
      </Receiver>
  </Receivers>
</Elements>

Update the app manifest

In order for SharePoint to call back to the Service Bus endpoint address, we will need to update the DebugInfo in the app manifest. This will tell SharePoint that it is safe to make the external call (outside of SharePoint).

In the app for SharePoint project:

  • Right-click AppManifest.xml, and select View Code.
  • Replace <AutoDeployedWebApplication/> with the following code:
 <AutoDeployedWebApplication>
    <DebugInfo 
        ClientSecret="[your client secret from web.config]" 
AppUrl="[IIS Express https address];[service bus namespace]/[address];" />
</AutoDeployedWebApplication>

Text to replace

Replace with

Comments

[IIS Express https address]

IIS Express HTTPS Port

You can get the IIS Express port numbers from the web project properties pane

[service bus namespace]/[address]

Windows Azure Service Bus Namespace and your choice of address

The same values as the corresponding entries in web.config

Debug the remote event receiver

Now that we have updated the required project artifacts to use the Service Bus, we are ready to debug the app.

  1. Go ahead and set a breakpoint in the ProcessOneWayEvent method in the remote event receiver.

  2. Press F5 to debug the app.

  3. WCF Test Client will start.

    This will host your service in IIS Express and the Service Bus.

  4. Ignore any IMetadataExchange errors:

    clip_image013

    Figure 10. WCF Test Client error

  5. Once the services are hosted, you should see something similar (you can safely ignore the schema errors):

    clip_image015

    Figure 11. WCF Test Client

  6. Now let’s click Add Contact.

  7. After a few seconds, you should see the breakpoint hit:

    clip_image017

  8. Press F10 to continue to the next step or F5 to continue debugging.

  9. Now click Get Contacts in the app, and you should see the full name property set:

    clip_image019

    Figure 12. Clicking Get Contacts in the app to see the full name property set

Publish your app to the marketplace

Since we added the service bus assemblies and the modified web.config file, the changes will be persisted when you package the app to publish in the marketplace.

We highly recommend that you remove the Service Bus assemblies and revert the web.config changes before publishing to the marketplace.

This requires the following changes:

  • In the app for SharePoint project:
  1. Open the remote event receiver Elements.xml, and update the Url property with the ~remoteAppUrl token.

  2. Right-click AppManifest.xml, and choose View Code:

    § Replace the <AutoDeployedWebApplication> section with the following:

 <AutoDeployedWebApplication/>
  • In the web project:
  1. Replace the <system.servicemodel> section in the web.config file with the following:
 <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <!--Used by app for SharePoint-->
        <binding name="secureBinding">
          <security mode="Transport" />
        </binding>
      </basicHttpBinding>
    </bindings>
    <protocolMapping>
      <add 
        binding="basicHttpBinding" 
        scheme="https" 
        bindingConfiguration="secureBinding" />
    </protocolMapping>
</system.serviceModel>
  • Uninstall the Service Bus NuGet package.

Download the sample app

You can download the sample app here:

Download SharePointAppRED.zip.

Remote event debugging FAQ

  1. What about app events?

    This blog post only works for remote event receivers, and not app events.

  2. How do I know my service is hosted in the Service Bus?

    Once the WCF client has successfully hosted all your services, browse to your Service Bus namespace in your browser, and you should see your endpoint:

    clip_image021

    Figure 13. Browsing to the Service Bus namespace

  3. The remote event receiver does not hit the breakpoint, so what is wrong?

    Depending on the event, the remote event may be synchronous or asynchronous. It might take a few more seconds or more to hit your breakpoint if it is asynchronous.

    Events that are “* being *”—like “item is being added”, “item is being deleted”—are synchronous.

    Events that are “* was *”—like “item was added”, “item was deleted”—are asynchronous.

  4. Can I debug more than one remote event receiver?

    This blog post covers debugging only one remote event receiver at a time.