Export (0) Print
Expand All

How to: Create a handler for the update event in app for SharePoint 2013

apps for SharePoint

Learn how to create and use a handler for the update event of an app for SharePoint.

Last modified: March 09, 2015

Applies to: SharePoint Add-ins | SharePoint Server 2013

Note Note

The name "apps for SharePoint" is changing to "SharePoint Add-ins". During the transition, the documentation and the UI of some SharePoint products and Visual Studio tools might still use the term "apps for SharePoint".

Be thoroughly familiar with both Handling app events and How to: Update apps for SharePoint and the prerequisites and core concepts listed in them.

Note Note

Version numbering system: For consistency, this topic assumes that the app version numbers are 1.0.0.0, 2.0.0.0, 3.0.0.0, and so on. However, the logic and guidance applies no matter what your numbering system is.

For custom update logic, you can create a SharePoint remote event receiver that handles the app updated event. You should be conservative in using this technique. Use it only for updating steps that can’t be done any other way. Also, the guidance found in Handling app events applies for the app updated event as much as the app installed and app uninstalling events. This includes:

  • Your handler has to complete and return either a cancel or a continue status to SharePoint in 30 seconds. If it does not, SharePoint will re-call the handler, up to three more times.

  • If your handler returns a cancel status, SharePoint will retry up to three more times.

  • You usually need to include rollback and "already done" logic in your handler.

One scenario in which an UpgradedEventEndpoint handler is useful is when a computed field is added to a remote database. Suppose a City column is added, and its value is computed from an already existing Postal Code column. Your code in an UpgradedEventEndpoint handler could iterate through existing items in the database and fill in the value for the new City field based on the value of the Postal Code field and some external data source that maps postal codes onto cities. The change to the database schema itself is best done outside the UpgradedEventEndpoint handler by using the best practices of the database platform.

For more details about how to create a handler for the app event, see Handle events in apps for SharePoint and Create an app event receiver in SharePoint 2013. The following procedure assumes that you have added the app event receiver item to your app for SharePoint project in Visual Studio.

To handle the app updated event the first time

  1. Open the AppEventReceiver.svc.cs file and add a conditional structure to the ProcessEvent method that tests whether the event that invoked the handler is the updated event. Your updating code goes inside this structure. If your code needs to access SharePoint, you can use the SharePoint managed code client object model (CSOM) or Representational State Transfer (REST) interface. Where the conditional structure is located in the method depends on how you have structured the other code in the method. Typically, it is a peer of similar conditional structures that test for the app installed and app uninstalling events. It may be within a conditional structure that tests certain properties or subproperties of the SPRemoteEventProperties object that is passed to ProcessEvent for null values or other invalid values. It may also be within a try block. The following is an example of the structure. The properties object is an SPRemoteEventProperties object.

    if (properties.EventType == SPRemoteEventType.AppUpgraded)
    {
    }
    
    
  2. To use CSOM in the handler, add (within the conditional block) a using block that gets a ClientContext object by calling the TokenHelper.CreateAppEventClientContext method. Specify true for the second parameter to access the app web. Specify false to access the host web. If you need to access both, you will need two different client context objects.

  3. If your handler needs to access non-SharePoint components, put that code outside any client context blocks. Your code should be structured similarly to the following:

    if (properties.EventType == SPRemoteEventType.AppUpgraded)
    {
        using (ClientContext cc = TokenHelper.CreateAppEventClientContext(properties, true))
        {
            // CSOM code that accesses the app web
        }
        using (ClientContext cc = TokenHelper.CreateAppEventClientContext(properties, false))
        {
            // CSOM code that accesses the host web
        }
        // Other update code
    }
    
    
  4. To use the REST interface, your code uses other methods in the TokenHelper class to get an access token, which is then included in the requests it makes to SharePoint. For more information, see How to: Complete basic operations using SharePoint 2013 REST endpoints. Your code should be structured similarly to the following.

    if (properties.EventType == SPRemoteEventType.AppUpgraded)
    {
        string contextTokenString = TokenHelper.GetContextTokenFromRequest(Request);
        if (contextTokenString != null)
        {
            contextToken = TokenHelper.ReadAndValidateContextToken(contextTokenString, 
                                                                                                                      Request.Url.Authority);
            accessToken = TokenHelper.GetAccessToken(contextToken, sharepointUrl.Authority)
                                       .AccessToken;
    
           // REST code that accesses SharePoint
        }  
        // Other update code
    }
    
    
  5. To access SharePoint, your REST code also needs to know the URL of the host web or app web or both. These URLs are both subproperties of the SPRemoteEventProperties object that is passed to the ProcessEvent method. The following code shows how to get them.

    Uri hostWebURL = properties.AppEventProperties.HostWebFullUrl;
    Uri appWebURL = properties.AppEventProperties.AppWebFullUrl;
    

When you update an app for the second (or third, and so on) time, you may need to ensure that some update logic does not run multiple times on the same app instance. The following procedure shows you how.

To handle the app updated event on subsequent updates

  1. Open the AppEventReceiver.svc.cs file, and find the code that implemented update actions in the first update (from 1.0.0.0. to 2.0.0.0). Let's call this the previous update code. (This code is generally located after the authorization code that gets client context or access tokens.) Now that you are updating again (from 2.0.0.0 to 3.0.0.0), there will typically be actions in the previous update code here that you don't want to run again on the same app instance, but you do want it to run on a app instance that was never updated to 2.0.0.0 (in which case, the instance is now being updated all the way from 1.0.0.0. to 3.0.0.0).

  2. Wrap the previous update code in a conditional structure that tests for the previous version of the app instance and executes only if the code in the structure has not run before on this app instance. The previous version of the instance is stored in the PreviousVersion subproperty of the SPRemoteEventProperties object.

  3. Add your new update logic (for the update from 2.0.0.0 to 3.0.0.0) below this structure. The following is an example.

    Version ver2OOO = new Version("2.0.0.0");
    if (properties.AppEventProperties.PreviousVersion < ver2OOO)
    {
        // Code to update from 1.0.0.0 to 2.0.0.0 (previous update code) is here.
    }
    // Code to update from 2.0.0.0 to 3.0.0.0 is here.
    
    
  4. For each subsequent update, repeat these steps. For the update from 3.0.0.0 to 4.0.0.0, your code should have the following structure.

    Version ver2OOO = new Version("2.0.0.0");
    if (properties.AppEventProperties.PreviousVersion < ver2OOO)
    {
        // Code to update from 1.0.0.0 to 2.0.0.0 is here.
    }
    
    Version ver3OOO = new Version("3.0.0.0");
    if (properties.AppEventProperties.PreviousVersion < ver3OOO)
    {
        // Code to update from 2.0.0.0 to 3.0.0.0 (previous update code) is here.
    }
    // Code to update from 3.0.0.0 to 4.0.0.0 is here.
    
    
Important note Important
  • If you add a component to an app in an UpgradedEventEndpoint handler, be sure to add the same code to an InstalledEventEndpoint handler because you want that component included in the app on a brand new installation as well. Also, you should add an UninstallingEventEndpoint (or revise it) for the app to remove the component. For the most part, anything that was added or changed by the InstalledEventEndpoint should be reversed or deleted by the UninstallingEventEndpoint. One exception is that data that will remain useful after the app is removed from the second-stage recycle bin should not be deleted. (Websites, other than the app web, that are created by the app should be considered data.)

If an error occurs when an app is being updated, the SharePoint 2013 infrastructure stops the update process and rolls back the app instance and all its components to the previous version of the app instance. But the infrastructure has no way of knowing what your UpgradedEventEndpoint handler logic does, so it can't always undo it. An unhandled exception thrown while your UpgradedEventEndpoint handler is executing almost certainly indicates that the entire app update process should be rolled back, but it won't be because the infrastructure doesn't know how to undo some things your UpgradedEventEndpoint code might have done. For this reason, the UpgradedEventEndpoint code must:

  1. Catch all exceptions.

  2. Branch to custom rollback code to undo what it has been done to that point.

  3. Signal to the SharePoint 2013 infrastructure that the entire app update should be rolled back.

  4. Pass on an error message to the infrastructure.

Not everything your UpgradedEventEndpoint does needs to be explicitly reversed inside the handler. The app web is going to be rolled back by the infrastructure, so your code does not have to undo changes to the app web. But the UpgradedEventEndpoint handler usually does have to reverse changes it has made to the host web or other components that are external to the app for SharePoint.

On the second (or third, and so on) update, your exception handing logic has to take account of the fact that the app instance that is being updated is not necessarily the immediately previous version. If it isn't, there may be two or more blocks of update code that need to be reversed. For this reason, you need conditional logic that is based on the number of the previous version. The following is an example of the rollback logic for an update to version 4.0.0.0.

catch (Exception e)
{ 
    // Rollback of the 3.0.0.0 to 4.0.0.0 update logic goes here.

    Version ver3OOO = new Version("3.0.0.0");
    if (properties.AppEventProperties.PreviousVersion < ver3OOO)
    {
        // Rollback of the 2.0.0.0 to 3.0.0.0 update logic goes here.
    }

    Version ver2OOO = new Version("2.0.0.0");
    if (properties.AppEventProperties.PreviousVersion < ver2OOO)
    {
        // Rollback of the 1.0.0.0 to 2.0.0.0 update logic goes here.
    }
}

The last things your error handling should do is assign an error message and a cancel status to the SPRemoteEventResult object that the ProcessEvent method returns to the SharePoint 2013 update infrastructure. The following is an example. In this code, result is an SPRemoteEventResult object that has been declared earlier in the ProcessEvent method.

catch (Exception e)
{     
    result.ErrorMessage = "custom message " + e.Message;
    result.Status = SPRemoteEventServiceStatus.CancelWithError;

     // Rollback logic from the preceding code snippet  is here. 

}
Important noteImportant

Assigning SPRemoteEventServiceStatus.CancelWithError (or SPRemoteEventServiceStatus.CancelNoError) to the Status property is crucial. This property is what signals the infrastructure to roll back the update. But SharePoint will retry your handler three times before it rolls back the update.

Use the handler delegation strategy

The handler delegation strategy that is described in Handling app events can be used in an UpdatedEventHandler too. Not only is your rollback and "already done" logic bundled and run on the remote component, but your versioning logic is too. The limitations of the strategy apply here too: you usually can't use it to update more than one remote system.

Return to Major steps in updating an app, or go directly to one of the following articles to learn how to update the next major component of your app for SharePoint.

Show:
© 2015 Microsoft