Walkthrough: Deploying a SignalR autohosted App to Office …



Walkthrough: Deploying a SignalR autohosted App to Office 365Written by Elliot Wood and Matt MenezesStep 1: Add an App for SharePoint 2013 project to your solutionNew project > SharePoint AppStep 2: Add proxy AutoDetect (if you are behind one)The following code should be manually added to the web.config file: <> <defaultProxy> <proxy autoDetect="True" /> </defaultProxy> </>Step 3: Configure your App to include an App Event ReceiverGoto your App’s properties window, Set Handle App Installed to TrueStep 4: Add a Remote Event Receiver to your AppAdd a New Item to the SharePoint app projectSelect Remote Event Receiver, and click AddChoose List Item Events, and Custom list (We can ignore this event source as we will register one manually later on). Choose to handle the following events: An item is being added, updated, deleted. Click Finish.Step 5: Configure the required permissions for your AppGive your app Full Control permissions to the Web and ListStep 6: Add a Global.asax file to your App Web projectIn your web project Add a Global Application Class called GlobalThen add the following codeusing Microsoft.AspNet.SignalR;using System;using System.Web.Routing;namespace SharePointRWeb{ public class Global : System.Web.HttpApplication { protected void Application_Start(object sender, EventArgs e) { var hubConfiguration = new HubConfiguration(); hubConfiguration.EnableCrossDomain = true; hubConfiguration.EnableDetailedErrors = true; RouteTable.Routes.MapHubs("/signalr", hubConfiguration); } }}Step 7: Add the SignalR Hub class to your App Web projectGo to your web project and Add a New ItemAdd a SignalR Hub ClassAlso add a new Class, we are going to call ours SharePointRAdd the following code to the new classusing Microsoft.AspNet.SignalR;using Microsoft.AspNet.SignalR.Hubs;using System;namespace SharePointRWeb{ public class SharePointR { // Singleton instance private readonly static Lazy<SharePointR> _instance = new Lazy<SharePointR>(() => new SharePointR(GlobalHost.ConnectionManager.GetHubContext<SharePointRHub>().Clients)); public SharePointR(IHubConnectionContext clients) { Clients = clients; } public static SharePointR Instance { get { return _instance.Value; } } private IHubConnectionContext Clients { get; set; } public void NotifyDataChanged(string ListName, string Event) { Clients.Group(ListName).dataChanged(Event); } }}Edit the hub class and add the following codeusing Microsoft.AspNet.SignalR;using Microsoft.AspNet.SignalR.Hubs;namespace SharePointRWeb{ [HubName("SharePointRHub")] public class SharePointRHub : Hub { private readonly SharePointR _sharePointR; public SharePointRHub() : this(SharePointR.Instance) { } public SharePointRHub(SharePointR sharePointR) { _sharePointR = sharePointR; } public void Subscribe(string ListName) { Groups.Add(Context.ConnectionId, ListName); } public void UnSubscribe(string ListName) { Groups.Remove(Context.ConnectionId, ListName); } public void NotifyDataChanged(string ListName, string Event) { _sharePointR.NotifyDataChanged(ListName, Event); } }}Step 8: Configure the App Event Receiver to manually bind the Item Event Receivers to a given ListOpen the App Event Receiver code behind. Add the code below which will manually hook up an item event receiver to a list in the host web (for the example we use the Announcements list). You can easily hook this up to more than one list here and because we implement a subscribe model above, the client will only receive the items they are subscribed to.using System.Collections.Generic;using System.Linq;using Microsoft.SharePoint.Client;using Microsoft.SharePoint.Client.EventReceivers;using System.ServiceModel;using System.Reflection;namespace SharePointRWeb.Services{ public class AppEventReceiver : IRemoteEventService { private string ReceiverName = "RemoteEventReceiver"; private List<EventReceiverType> EventType = new List<EventReceiverType>() { EventReceiverType.ItemAdding, EventReceiverType.ItemUpdating, EventReceiverType.ItemDeleting }; private string ListTitle = "Announcements"; public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties) { SPRemoteEventResult result = new SPRemoteEventResult(); using (ClientContext clientContext = TokenHelper.CreateAppEventClientContext(properties, false)) { Web hostWeb = clientContext.Web; clientContext.Load(hostWeb); List docLib = clientContext.Web.Lists.GetByTitle(ListTitle); string opContext = OperationContext.Current.Channel.LocalAddress.Uri.AbsoluteUri.Substring(0, OperationContext.Current.Channel.LocalAddress.Uri.AbsoluteUri.LastIndexOf("/")); string remoteUrl = string.Format("{0}/RemoteEventReceiver.svc", opContext); if (properties.EventType == SPRemoteEventType.AppInstalled) { foreach (var eventType in EventType) { EventReceiverDefinitionCreationInformation newEventReceiver = new EventReceiverDefinitionCreationInformation() { EventType = eventType, ReceiverAssembly = Assembly.GetExecutingAssembly().FullName, ReceiverClass = "SignalRProxyService.Services.RemoteEventReceiver", ReceiverName = ReceiverName + eventType.ToString(), ReceiverUrl = remoteUrl, SequenceNumber = 1000 }; docLib.EventReceivers.Add(newEventReceiver); } clientContext.ExecuteQuery(); } else if (properties.EventType == SPRemoteEventType.AppUninstalling) { IEnumerable<EventReceiverDefinition> receivers = clientContext.LoadQuery(docLib.EventReceivers .Where(e => e.ReceiverName == ReceiverName)); foreach (var rec in receivers) { rec.DeleteObject(); } clientContext.ExecuteQuery(); } } return result; } public void ProcessOneWayEvent(SPRemoteEventProperties properties) { // This method is not used by app events } }}Note: For synchronous “-ing” events (like ?adding, deleting, updating) ?you must use the?ProcessEvent?method. For?asynchronous ?”-ed” ?events (like ?added, updated, deleted),?use the?ProcessOneWayEvent?method.Step 9: Configure the Remote Event Receiver to communicate with the page via SignalROpen the Remote Event Receiver code behind, add the following code. This will notify the hub when events occur.using System;using System.Collections.Generic;using System.Linq;using System.Text;using Microsoft.SharePoint.Client;using Microsoft.SharePoint.Client.EventReceivers;namespace SharePointRWeb.Services{ public class RemoteEventReceiver : IRemoteEventService { private SharePointRHub client = new SharePointRHub(); public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties) { client.NotifyDataChanged(properties.ItemEventProperties.ListTitle, properties.EventType.ToString()); return new SPRemoteEventResult(); ; } public void ProcessOneWayEvent(SPRemoteEventProperties properties) { } }}Step 10: Create the page that will receive the SignalR messages (including slight branding to the page fits the site)Using Manage NuGet Packages add the json2 package.It will add json2 to the Scripts directoryAdd a new JavaScript File called chromeLoader.js, this will allow our app to be branded correctly.// Callback for the onCssLoaded event defined// in the options object of the chrome controlfunction chromeLoaded() { // When the page has loaded the required // resources for the chrome control, // display the page body. $("body").show();}//Function to prepare the options and render the controlfunction renderChrome() { // The Help, Account and Contact pages receive the // same query string parameters as the main page var options = { "appIconUrl": "/Images/AppIcon.png", "appTitle": "SignalR Sample Application", "appHelpPageUrl": "default.aspx?" + document.URL.split("?")[1], // The onCssLoaded event allows you to // specify a callback to execute when the // chrome resources have been loaded. "onCssLoaded": "chromeLoaded()", "settingsLinks": [ { "linkUrl": "Account.html?" + document.URL.split("?")[1], "displayName": "Account settings" }, { "linkUrl": "Contact.html?" + document.URL.split("?")[1], "displayName": "Contact us" } ] }; var nav = new SP.UI.Controls.Navigation( "chrome_ctrl_placeholder", options ); nav.setVisible(true);}// Function to retrieve a query string value.// For production purposes you may want to use// a library to handle the query string.function getQueryStringParameter(paramToRetrieve) { var params = document.URL.split("?")[1].split("&"); var strParams = ""; for (var i = 0; i < params.length; i = i + 1) { var singleParam = params[i].split("="); if (singleParam[0] == paramToRetrieve) return singleParam[1]; }}var hostweburl;//load the SharePoint resources$(document).ready(function () { //Get the URI decoded URL. hostweburl = decodeURIComponent( getQueryStringParameter("SPHostUrl") ); // The SharePoint js files URL are in the form: // web_url/_layouts/15/resource var scriptbase = hostweburl + "/_layouts/15/"; // Load the js file and continue to the // success handler $.getScript(scriptbase + "SP.UI.Controls.js", renderChrome)});In the web project go to the default.aspx.cs file under /pages, replace the code behind with the followingusing System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.UI;using System.Web.UI.WebControls;namespace SharePointRWeb.Pages{ public partial class Default : System.Web.UI.Page { public string SiteTitle = string.Empty; protected void Page_Load(object sender, EventArgs e) { // The following code gets the client context and Title property by using TokenHelper. // To access other properties, you may need to request permissions on the host web. var contextToken = TokenHelper.GetContextTokenFromRequest(Page.Request); var hostWeb = Page.Request["SPHostUrl"]; using (var clientContext = TokenHelper.GetClientContextWithContextToken(hostWeb, contextToken, Request.Url.Authority)) { clientContext.Load(clientContext.Web, web => web.Title); clientContext.ExecuteQuery(); SiteTitle = clientContext.Web.Title; } } }}In the web project go to the default.aspx file under /pages, replace the mark-up with the following:<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="SharePointRWeb.Pages.Default" %><!DOCTYPE html><html xmlns=""><head> <title>SignalR Sample</title></head><!-- The body is initally hidden. The onCssLoaded callback allows you to display the content after the required resources for the chrome control have been loaded. --><body style="display:none;"> <!-- Chrome control placeholder --> <div id="chrome_ctrl_placeholder"></div> <!-- The chrome control also makes the SharePoint Website stylesheet available to your page --> <h1 id="HostSiteTitle" class="ms-accentText"><%= this.SiteTitle %></h1> <div id="MainContent"></div> <!--Script references. --> <script src="//ajax.ajax/4.0/1/MicrosoftAjax.js"></script> <!--Reference the jQuery/JSON library. --> <script src="/Scripts/jquery-1.8.2.min.js"></script> <script src="/Scripts/json2.js"></script> <!--Reference the chromeLoader helper. --> <script src="/Scripts/chromeLoader.js"></script> <!--Reference the SignalR library. --> <script src="/Scripts/jquery.signalR-1.0.0.js"></script> <!--Reference the autogenerated SignalR hub script. --> <script src="/signalr/hubs"></script> <!--Add script to update the page and send messages.--> <script type="text/javascript"> $(function () { var connection = $.hubConnection('/signalr/hubs'); proxy = connection.createHubProxy('SharePointRHub') proxy.on('dataChanged', function (eventType) { $('#MainContent').append('<li>Data changed - ' + eventType + '</li>'); }); connection.start() .done(function () { //Subscribe to Announcements list proxy.invoke('Subscribe', "Announcements"); $('#MainContent').append('<span>Now connected, connection ID=' + connection.id + '</span>'); }) .fail(function () { $('#MainContent').append('<span>Could not Connect!</span>'); }); }); </script></body></html>Go to the app project and edit the appmanifest, goto the genral tab and add the following to the QueryString “{StandardTokens}&SPHostTitle={HostTitle}” required for branding.in the web project add an Images folderAdd and and image called “AppIcon.png” to the Images folder Step 11: Create the list in SharePoint that the event receiver will be bound toGo to your SharePoint site create a list called AnnouncementsStep 12: Deploy the App to Office 365Now press F6 or Build SolutionAnd click Deploynote: If you receive an error here see troubleshooting as the bottom.Trust the app and now it is ready for use (details below)Alternatively You may want to deploy the app to the app catalog (recommended for production). Publish the app.Now the app is published here is a step by step guide to how to deploy it.Go to your App Catalog Site (you may need to create one, tutorial not included here) in site contents go to apps for SharePointDrag your published app to the library to deploy itAdd an app > SharePointRTrust the appStep 13: Run the App!Open the announcements list side by side with the Page that will receive the SignalR messages. Add/Edit/Remove items from the list and watch the magic.Appendix: TroubleshootingWhen publishing a SharePoint hosted application to a development site on Office 365 Preview, running SharePoint 2013, you may receive the following error:“Error occurred in deployment step ‘Install App for SharePoint’: Sideloading of apps is not enabled on this site.Solution: You need to enable the Sideloading feature on the site.1.?Download and install the?SharePoint Online Management Shell?for PowerShell2.?Download the script?Sideload.ps1?and execute it within the SharePoint Online Management Shell.Note: This is not recommended for a production site.?Deploy applications using the App Catalog?on a production site.Source “”I used the following code to enable the feature on my host site using (var context = new ClientContext(Url)) { //Pass the Credentials to SharePoint Online context.Credentials = new SharePointOnlineCredentials(UserName, Password); var site = context.Site; context.Load(site); context.ExecuteQuery(); site.Features.Add(new Guid("E374875E-06B6-11E0-B0FA-57F5DFD72085"), true, FeatureDefinitionScope.Farm); context.ExecuteQuery();} ................
................

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

Google Online Preview   Download