Remote Event Handlers in O365 & Azure Part 5: Setup the ...



Provider Hosted App for Windows AzureCreate Windows Azure Service BusRemote Event Handlers in O365 & Azure Part 5: Setup the Windows Azure Service Bus (Post-August 2014)The overall objective is to create a Remote Event Receiver (RER) for SharePoint Online so that when list items are added to a list, an event is triggered that allows us as developers to react to this. We must be able to debug this so we can understand how it works. So this?blog post?has been split in to the following sections:Setup Windows Azure – this involves?creating a new subscription with a?trial license to remotely host our code.Setup the Windows Azure Website – we need this as a location to deploy our code to, so?that SharePoint Online can access.Setup the Windows Azure Service Bus (Pre-August 2014) – this is via the Azure interface, which is now considered the wrong way as it doesn’t create the ACS connection string. Skip this?section and do section 5 instead if you want to get?this up and running quickly.Setup the RER Project – Visual Studio 2013 will be used to install and debug our code, using a reference to the Azure Service Bus created in the previous stage.Setup the Windows Azure Service Bus (Post-August 2014) – this is via PowerShell, which is now considered the correct way (or the only way that works!) due to changes in Azure and should work on all Post-August 2014 projects… Read more belowPart 5: Setup the Windows Azure Service Bus (Post-August 2014)If like me, you notice the code still doesn’t hit your breakpoints. When pressing F5 to debug I noticed the following error in the Output window of Visual Studio:“Cannot register Services/AppEventReceiver.svc on Microsoft Azure Service Bus: The remote server returned an error: (500) Internal Server Error.”“Cannot register Services/RemoteEventReceiver1.svc on Microsoft Azure Service Bus: The remote server returned an error: (500) Internal Server Error.”Dammit! Ok so after a quick message to Microsoft complaining that the Azure Service Bus was broken, Charls Tom Jacob from MS informed me of this breaking change to the Service Bus Authentication from Microsoft. So thankfully I was able to recreate my Service Bus the right way in the following steps:Launch “Microsoft Azure PowerShell”. If you don’t have it installed, open the “Web Platform Installer” and download it to your machine:Run the following PowerShell to begin downloading the publish settings file: “Get-AzurePublishSettingsFile”This then launches the following window in your browser:Click “Save” to save this to your downloads folder:Now let’s import that file into our PowerShell session so we can create that Service Bus. Run the following script: “Import-AzurePublishSettingsFile -PublishSettingsFile C:\Users\svc_eu_dspfarmadmin\Downloads\Free Trial-10-28-2014-credentials.publishsettings”You should then be presented with basic info about your Azure tenant:Now Charls’ article states we need to use the following script to create the Service Bus: “New-AzureSBNamespace myServiceBusName ‘West Europe’ -CreateACSNamespace 1”Within a minute or so the Service Bus is created and the following connection information is displayed:Now if we head back to and click on “SERVICE BUS” we can see our new service bus:If you click on “CONNECTION INFORMATION” at the bottom of the page, we should now see the “ACS CONNECTION STRING” which is what we can use for Visual Studio:So copy that “ACS CONNECTION STRING” to the SharePoint tab of your App project properties, remember where it is still?Then hit “F5”, watch the output window and you should see the services registered successfully:And then boooom!References:- HYPERLINK "" Provider Hosted App Step1:- go to VS2012, select App for SharePoint 2013 under App Tab then give name of the Project and click OK. See as in below screenStep2:- click OK then it will give another window for fill site url for where this app deployed, and check Provider Hosted App.Step3:- next another window appear for which type of web application. Select “ Web Forms Application” and click next.Step4:- Next need to fill Configuration Authentication setting by using below screen. Click on Finish.Step5:- the project is created.it have 2 projects, one is deployed on Office 365 and other is Azure.Step6:- Before going to publish this solution, import your Azure publish profile using from windows azure site url (your reference site URL) and client Id and secret using office365 dev site url.Open Azure site and download the Publish Profile using “Download Publish Profile” link.Create Client Id and client Secret from office365 online site using the following url< site>/_layouts/15/appregnew.aspx.Ex:- completion of the above process, go to visual studio and right click on solution then select Publish. As shown in below .Step8:- it shows another window for select publishing profile through browsing. Click on arrow button, it gives <New> from Dropdown and click on that then another window is appear. In that select Import publishing profile using browse button. Select file path from your local system. Next need to provide client id and client secret. These values created in above. Click on FinishCame back to VS2012,right click on solution and select Publish. after select current profile then click on “Deployed your web app”. See the below screenNext click on PublishOpen web.config file, change the AppSettings, see the below screen. Open AppManifest.xml file changed the start page and RemotewebApplication client ID.see the below screen.Then click on Deploy Solution. After deploy the solution check in your developer site under Apps in Testing.Click on your web app, then click on Trust it button. Your site is opened in Azure site.Solution:-RER.svc.cs file:-using System;using System.Collections.Generic;using System.Linq;using ;using System.Text;using Microsoft.SharePoint.Client;using Microsoft.SharePoint.Client.EventReceivers;namespace RERAzureWeb.Services{ public class rajugsRER : IRemoteEventService { public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties) { SPRemoteEventResult result = new SPRemoteEventResult(); using (ClientContext clientContext = TokenHelper.CreateRemoteEventReceiverClientContext(properties)) { if (clientContext != null) { clientContext.Load(clientContext.Web); clientContext.ExecuteQuery(); } } return result; } public void ProcessOneWayEvent(SPRemoteEventProperties properties) { // obtain web URL somehow - line below is fine for a list item RER, but you'll need another approach elsewhere.. string webUrl = properties.ItemEventProperties.WebUrl; Uri webUri = new Uri(webUrl); string realm = TokenHelper.GetRealmFromTargetUrl(webUri); string accessToken = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, webUri.Authority, realm).AccessToken; using (var clientContext = TokenHelper.GetClientContextWithAccessToken(webUrl, accessToken)) { // do CSOM stuff here.. // On Item Added event, the list item creation executes if (clientContext != null) { try { clientContext.Load(clientContext.Web); clientContext.ExecuteQuery(); List imageLibrary = clientContext.Web.Lists.GetByTitle("Employee"); ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation(); ListItem oListItem = imageLibrary.AddItem(itemCreateInfo); oListItem["Title"] = "TITLE CHANGED BY RER"; oListItem.Update(); clientContext.ExecuteQuery(); } catch (Exception ex) { } } } } }}Elements.xml:-<?xml version="1.0" encoding="utf-8"?><Elements xmlns=""> <Receivers ListUrl="Lists/Employee"> <Receiver> <Name>rajugsRERItemAdding</Name> <Type>ItemAdded</Type> <SequenceNumber>10000</SequenceNumber> <!--<Url>; <Url>~remoteAppUrl/Services/rajugsRER.svc</Url> </Receiver> </Receivers></Elements>Create list on App page:-<%@ Page language="C#" MasterPageFile="~masterurl/default.master" Inherits="Microsoft.SharePoint.WebPartPages.WebPartPage, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %><%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %><%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %><%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %><asp:Content ContentPlaceHolderId="PlaceHolderAdditionalPageHead" runat="server"> <SharePoint:ScriptLink name="sp.js" runat="server" OnDemand="true" LoadAfterUI="true" Localizable="false" /></asp:Content><asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server"> <WebPartPages:WebPartZone runat="server" FrameType="TitleBarOnly" ID="full" Title="loc:full" /> <WebPartPages:WebPartZone runat="server"FrameType="TitleBarOnly" ID="WebPartZone1" Title="loc:full" ><WebPartPages:XsltListViewWebPart ID="XsltListViewWebPart2"runat="server" ListUrl="Lists/Employee" IsIncluded="True"NoDefaultStyle="TRUE" Title="Slideshow Images"PageType="PAGE_NORMALVIEW" Default="False"ViewContentTypeId="0x"></WebPartPages:XsltListViewWebPart></WebPartPages:WebPartZone></asp:Content>Extra Activities:-Remote Event Receivers on host web gotcha – no context token/ClientContextI’ve spent quite a bit of time working with Remote Event Receivers in SharePoint 2013/Office 365, and in the early days I hit an issue that initially made me think they didn’t work properly at all. Now with some help, I realize that mainly the code just has to be written a certain way - but it’s also true to say that there is a limitation which can affect some things you might want to do. In any case, this is a gotcha that I’m starting to see other people hit so I think it’s worth talking about it.Specifically the issue occurs when:The event receiver is on the host web (rather than the app web)The event receiver uses CSOM code to talk to SharePoint (rather than just using NON-SharePoint code)Issue symptomsWhen you’re trying to use RERs on the host web, what you might see is that whilst your event receiver always fires (and your remote code?does?execute), your code fails to authenticate back to SharePoint. You’ll get a 401 error when trying to obtain or use a ClientContext object – this could manifest itself with one of these in your code:System.NullReferenceException: Object reference not set to an instance of an object..but if you look at the HTTP requests/responses, you’ll see the HTTP 401 (Access Denied).This means you effectively can’t do anything with SharePoint – and often, of course, the?whole point?of your event receiver is that it’s going to do something in SharePoint! Perhaps you need to create, update or delete an item somewhere, or perform some other action related to sites, users or data in SharePoint.Other info:No context tokenIf you do some debugging, you’ll find that the event receiver does NOT receive a valid context token from SharePoint/Office 365 - SPRemoteEventProperties.ContextToken is an empty string. This causes all the later code to fail. At this point, you probably think there’s a bug with SharePoint/Office 365 – even at the end of all this, I’m personally not sure whether there is a bug or it’s just a “by-design” limitation. Fortunately, as we will see there is a workaround which works for many (most?) scenarios of this type.The same code works on the app webIf you do some wider testing, perhaps to see if there is a code issue – you’ll find the very same code works fine in other contexts. For example, if you use the same code in a RER on the app web (e.g. “ItemAdded” on a list in the app web), everything works fine. The issue is purely related to RERs on the host web.No change if you use ProcessOneWayEvent (asynchronous events such as added, deleted etc.) or ProcessEvent (synchronous events such as adding, deleting etc.)Remote Event Receivers are similar to traditional full-trust event receivers, in that both async and sync events can be used. An example here would be the “added” and “adding” events respectively – these correspond to the ProcessOneWayEvent and ProcessEvent methods in a Remote Event Receiver class. For reference, the issue we’re discussing here manifests itself in both cases.So those are the symptoms. Before we dig into the “Why it happens” and “The workaround” sections, it’s worth reminding ourselves of some aspects of remote code and authentication in particular. Feel free to skip forward if you’re familiar with this territory.A reminder on authentication of remote codeFor those just starting out with Remote Event Receivers (or SharePoint apps/remote code in general), it’s worth noting that?an app is required for any form of remote code.?More correctly, we could expand this to say?any remote code which runs on the server-side and uses “app authentication” -?as opposed to “user authentication” where a username/password is specified. In any case, this can seem strange for some things like Remote Event Receivers, where there isn’t really an “app” (e.g. with some pages) that the user will enter/click around etc. All we have for a RER is a remote WCF service with no front-end! But, this is the way the trust model works for remote code – so the first thing to say is that if you don’t have an app registered and installed/trusted for your remote code, it will not work.If we were to summarize common authentication options for remote SharePoint code, we could break it down like this:User authenticationThe username/password of a “named user” is passed – usually a very poor approach that brings security risks. Effectively this led OAuth to be invented as an alternative.App authentication – this breaks down into:User + app authentication?– the default. Permissions of both the user *and* the app are checkedApp-only authentication?– the permissions of just the app are checked (thus allowing operations that the user themselves does not have permission to do)Why it happensIf you’re hitting the issue, your RER most likely has code which instantiates the ClientContext object in a certain way - specifically, you’ll be using “user + app” authentication. The vast majority of MSDN and blog samples use this approach.?This is ultimately the problem -? “user + app” authentication does not currently work for events related to the host web. My testing shows this is the case for both Office 365 and SharePoint 2013 on-premises installations.?Along the journey of realising this, I tried some different coding approaches – and I see other developers perhaps doing the same (e.g. in forum posts). Since there are various ways the CSOM ClientContext object can be obtained, you might try different code for this – but several cannot be used in a RER and will fail. The table below shows some of the “wrong” approaches.Code approaches which will NOT work:ApproachCode sampleWhy notUsing the typical RER approachClientContext clientContext = TokenHelper.CreateRemoteEventReceiverClientContext(properties)This is the approach that “should work” (and the approach that most samples use).However, it only works for events on the app web?– NOT events on the host web.Creating ClientContext using constructorClientContext clientContext = new ClientContext(properties.ItemEventProperties.WebUrl)The context is not obtained in a way which deals with authentication. This is what the TokenHelper methods are for.?Sidenote – it would be possible to authenticate with?user authenticationinstead of?app authentication, if the username/password of a named account was attached using the SharePointOnlineCredentials object.?But that’s lame, and a big security risk! Instead, we want to use OAuth (via app authentication) of course, to avoid storing/passing passwords.Using the “app event” approachClientContext clientContext = TokenHelper.CreateAppEventClientContext(properties, false)The context is obtained in a way which is only appropriate for?app?events (e.g. AppInstalled/AppUpgraded/AppUninstalled etc.) Since we are using an event on the host web, authentication does not work.As the table says, the one that *should* work is the first one (TokenHelper.CreateRemoteEventReceiverClientContext()) – but this relies on “user + app” authentication which appears to be the problem. So to work around this we need a different approach.?The workaroundInstead of “user + app” authentication we can use “app-only” authentication. This requires 2 things:The app permission policy to specify that app-only calls are allowed (something the person installing the app must agree to). This is enabled in the app manifest in Visual Studio:?The code in the app (i.e. in the Remote Event Receiver) to obtain ClientContext using an app-only access token. The expected way to do this in C# is to use the correct TokenHelper methods – big thanks to?Kirk Evans?for helping me with this. The code should look like this:?** N.B. There is a code sample here but it will not show in RSS Readers -?click here for full article?**1234567891011// obtain web URL somehow - line below is fine for a list item RER, but you'll need another approach elsewhere.. string webUrl = properties.ItemEventProperties.WebUrl;?Uri webUri = new Uri(webUrl);?string realm = TokenHelper.GetRealmFromTargetUrl(webUri); string accessToken = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, webUri.Authority, realm).AccessToken; using (var clientContext = TokenHelper.GetClientContextWithAccessToken(webUrl, accessToken)) { // do CSOM stuff here..}If you ensure these two things are in place, your Remote Event Receiver will work fine.The limitation – when the workaround is no goodSo, that’s the answer then. However, you might hit occasions where the app-only approach isn’t really what you want. If your remote code writes any data to SharePoint (e.g. adds a list item), you’ll notice that the SharePoint user interface makes it clear that the list item was added/modified by an app. Specifically, the username will be in the following format:Last modified at [time] by [app name] on behalf of [username]This is a pretty useful feature for some business requirements, since it makes it clear that although the named user was involved, they didn't make the change in SharePoint "directly". Unfortunately, use of the app-only authentication route to solve our problem changes this – specifically, with app-only authonly the app name is recorded as the user who made the change. Effectively, we lose the information which tells us which actual person was involved in the change - in some circumstances, this could be a problem if some kind of audit trail is required. To make things clear, here are two screenshots which show the difference:List item added by "app + user" authentication:List item added by "app-only" authentication:Related sidenote (for the curious!):If you’re wondering how SharePoint/Office 365 deals with this under the covers, you’ll find that all lists now have 2 new hidden columns - “App Created By” and “App Modified By”. These store a reference to an entry in the User Information list in the current site (just like other Person/Group columns):So now you know ;)SummaryIt’s pretty easy to get things wrong with Remote Event Receivers, and the pitfall I’ve talked about concerning authentication and CSOM code is definitely a big gotcha – I certainly see other people hitting this. If you have remote code which modifies data in SharePoint somewhere, the way around the problem is to use app-only authentication - by ensuring the app’s permission policy allows this *and* also writing your CSOM code to authenticate in this way. This can be done by obtaining an access token using the?TokenHelper.GetAppOnlyAccessToken()?method, and then obtaining a ClientContext object using this token.However, with this approach comes a trade-off - the loss of user information (in “pseudo-audit” terms) related to the user behind the change. Developers should bear this in mind when working with Remote Event Receivers.App authorization policy types in SharePoint 2013apps for SharePointLearn about the different authorization policies for apps in SharePoint: app-only policy, user+app policy, and user-only policy. It also provides guidelines for using app-only policy.Get an overview of app authorization policies typesSharePoint provides three types of authorization policies:User-only policy— When the user-only policy is used, SharePoint checks only the permissions for the user. SharePoint uses his policy is enforced is when the user is accessing resources directly without using an app. (This policy was always used in SharePoint 2010.)?User+app policy—When the user+app policy is used, SharePoint checks the permissions of both the user and the app principal. Authorization checks succeed only if both the current user and the app have permissions to perform the action in question.An example of when this policy is used is when an app for SharePoint wants to get access to the user's resources on SharePoint. The code in the remote components of the app for SharePoint should be designed to make user+app calls to SharePoint.?App-only policy—When the app-only policy is used, SharePoint checks only the permissions of the app principal. Authorization check succeeds only if the current app has sufficient permissions to perform the action in question, regardless of the permissions of the current user (if any).An expense approval app is an example of when this policy is used. The app allows users who wouldn't otherwise be able to approve expenses to approve expenses below a certain amount. See the scenario below for details.?NoteCertain APIs require a user context and can't be executed with an app-only policy. These include many APIs for interacting with Project Server 2013 and for performing search queries.See an example scenario of an app that uses the app-only policyLet's says a sales manager at Contoso, Adam, buys an expense submission app that uses the app-only policy. When Adam chooses to buy the app, Adam is prompted to allow the app to elevate user permissions; that is, to allow the app to make app-only calls to SharePoint. Adam grants the app the requested permission. He then purchases enough licenses for all of the Contoso sales people to use the app, and he installs it in the sales team's central SharePoint site.Soon, the salespeople are submitting expense reports using the new expense submission app. Salespeople usually cannot approve their own expense reports, but they can do this when using the app because Adam granted it the ability to do this for expense submissions below $50 because he set the app to automatically approve reports below $50. The app is automatically assigns him a task to approve reports of $50 or more. This could be implemented by giving the app for SharePoint Write permission to a SharePoint list of approved expenses. But, among users, only human resources managers have Write permission to the list. The code in the app is designed to make an app-only call to SharePoint, if the expense is less than $50, to add the expense to the list. Since the user's permissions aren't checked, any user's submissions below $50 are automatically added to the approved expenses list, even if the user doesn't have Write permission to the list.Learn how apps get permission to use the app-only policyTo be able to make app-only calls to SharePoint, your app must request the ability to use the app-only policy in the app manifest. You do this by adding theAllowAppOnlyPolicy?attribute to the?AppPermissionRequests?element and setting it to?true?as shown in the following markup:XML<AppPermissionRequests AllowAppOnlyPolicy="true"> ...</AppPermissionRequests>A user installing the app will be prompted to approve this request. If the app asks for tenant-scoped permissions, then only a tenant administrator can grant use of the app-only policy, so only a tenant administrator can install the app. If the app does not ask for any permissions scoped higher than site collection, then a site collection administrator can install the app. For more information about permission scopes, see?App permissions in SharePoint 2013.Learn how apps make app-only callsThe difference between an app-only call to SharePoint and a user+app call is the tyoe of access token that is included in the call. The following code shows how to make obtain user+app and app-only access tokens in managed code. The detailed coding is done for you in the TokenHelper.cs (or .vb) file that the Office Developer Tools for Visual Studio automatically add to the project in Visual Studio.C#string contextTokenString = TokenHelper.GetContextTokenFromRequest(Request);if (contextTokenString != null){ //Get context token. SharePointContextToken contextToken = TokenHelper.ReadAndValidateContextToken(contextTokenString, Request.Url.Authority); Uri sharepointUrl = new Uri(Request.QueryString["SPHostUrl"]); //Get user+app access token. string accessToken = TokenHelper.GetAccessToken(contextToken, sharepointUrl.Authority).AccessToken; ClientContext clientContext = TokenHelper.GetClientContextWithAccessToken(sharepointUrl.ToString(), accessToken); //Do something. ... //Get app-only access token. string appOnlyAccessToken = TokenHelper.GetAppOnlyAccessToken(contextToken.TargetPrincipalName, sharepointUrl.Authority, contextToken.Realm).AccessToken; //Do something. ...}NoteApps that do not make OAuth authenticated calls (for example, apps that are only JavaScript running in the app web) cannot use the app-only policy. They can request the permission, but they will not be able to take advantage of it because doing so requires passing an app-only OAuth token. Only apps with web applications running outside of SharePoint can create and pass app-only tokens.In general, a current user is required to be present for a call to be made. In the case of app-only policy, SharePoint creates a SHAREPOINT\APP, similar to the existing SHAREPOINT\SYSTEM user. All app-only requests are made by SHAREPOINT\APP. There is no way to authenticate as SHAREPOINT\APP through user-based authentication.Get guidelines for using the app-only policySince app-only calls effectively elevate user privileges, you should be conservative in creating apps that ask for permission to make them. Calls should use the app-only policy only if:The app needs to elevate its permissions above the user for a specific call; for example, to approve an expense report under conditions evaluated by the app.The app is not acting on behalf of any user; for example, an app that performs nightly maintenance tasks on a SharePoint document library.Additional resourcesAuthorization and authentication of apps for SharePoint 2013App permissions in SharePoint 2013Context Token OAuth flow for apps in SharePoint 2013Apps for SharePointGet started creating provider-hosted apps for SharePoint ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download