Converting a VS.NET Web for a Provider Hosted SharePoint App to a Full Blown Web or Console Application

This post is yet another in my series of "how long of a post title I can come up with and still not convey the actual essence of the post" contest. I'm sure you've all been following along at home and are thrilled to see another entry, but it was either this or create a title with like 63 words in it. So...the point of this post is to take you through the typical development scenario for a SharePoint App - you open up Visual Studio 2012, you create a new SharePoint App project, and you configure it to be provider hosted using high trust (i.e. a certificate). Now you have this SharePoint App, which is great, but you also have this little application web that VS.NET created for you and that uses a local IIS Express instance. That's actually also great to get you started and running, but of course you are going to have to move away from that as you go into QA and production (and honestly many times even in dev - in fact I almost always do this even in dev). The process can be a little wonky to get down so I thought I'd document the steps for doing so. I'm also going to show you how to make it work with a console application as well, because that can be a super useful scenario for doing things like timer jobs, etc. (perhaps the source of another post in the future...we'll see, I've got kind of a cool solution going here).

So, how do we get from IIS Express to a SharePoint App as a full blown ASP.NET or console application? Well, here goes:

  1. Create your application using the Visual Studio wizard. It creates the SharePoint App as well as web application project that uses IIS Express. From this point forward this web application project that VS.NET creates shall be referred to as the "original web app". Verify that everything is working correctly.
  2. Create your new application you are going to use - a web project or a console project. Remember to use SSL if creating a web project.
  3. Copy the configuration information from the original web app; for:
  1. Web Project - copy the items in the <appSettings> of web.config to web.config of your new web project.
  2. Console App - Go into the Properties of the application, click on the Settings link on the left, then click on the link in the middle of the page that says "This project does not contain a default settings file. Click here to create one." Create properties for each of the appSetting properties - copy in both the key (as the setting Name) and value (as the setting Value). Make sure you make each setting an Application scope property (it is User by default).
  • Create an App_Code folder and copy into it the TokenHelper.cs file from the original web project. For a console application you can just create a new folder; for an ASP.NET application you should use the Add...Add ASP.NET Folder...App_Code menu option.
  • Remove the "namespace" declaration from the TokenHelper.cs file.
  • Add references so your application will compile; the exact ones will vary slighlty between an ASP.NET and console application, but here is a complete list so just make sure whichever application type you choose, you have all of these references:
  1. Microsoft.SharePoint.Client
  2. Microsoft.SharePoint.Client.Runtime
  3. Microsoft.IdentityModel
  4. Microsoft.IdentityModel.Extensions
  5. System.ServiceModel
  6. System.Web
  7. System.Web.Extensions
  8. System.IdentityModel

At this point, the steps diverge depending on what type of project you created. If you created a web project:

  1. Create a default.aspx page (if you did not already - this assumes you are using ASP.NET web forms by the way and not MVC).
  2. Copy and paste the code from the code-behind in default.aspx in the original web app to your default.aspx. You should not need to add a "using" statement for the App_Code folder.
  3. Open the AppManifest.xml file in your SharePoint App project and change the Start Page property to point to the default.aspx page you created in your new web project.
  4. In the IIS Manager, make sure that for your provider hosted site anonymous is disabled and Windows authentication is enabled.
  5. Press F5 to launch the Visual Studio .NET debugger, install the app and validate that the code works.

If you created a console app:

  1. Open the TokenHelper.cs file and edit it; find these lines of code:

        private static readonly string ClientId = string.IsNullOrEmpty(WebConfigurationManager.AppSettings.Get("ClientId")) ? WebConfigurationManager.AppSettings.Get("HostedAppName") : WebConfigurationManager.AppSettings.Get("ClientId");
        private static readonly string IssuerId = string.IsNullOrEmpty(WebConfigurationManager.AppSettings.Get("IssuerId")) ? ClientId : WebConfigurationManager.AppSettings.Get("IssuerId");

(and then a little below)

        private static readonly string ClientSigningCertificatePath = WebConfigurationManager.AppSettings.Get("ClientSigningCertificatePath");
        private static readonly string ClientSigningCertificatePassword = WebConfigurationManager.AppSettings.Get("ClientSigningCertificatePassword");

and replace them with these; note that you must replace "yourAppsNamespace" with the namespace for your application:

        private static readonly string ClientId = yourAppsNamespace.Properties.Settings.Default.ClientId;
        private static readonly string IssuerId = yourAppsNamespace.Properties.Settings.Default.IssuerId;

        private static readonly string ClientSigningCertificatePath = yourAppsNamespace.Properties.Settings.Default.ClientSigningCertificatePath;
        private static readonly string ClientSigningCertificatePassword = yourAppsNamespace.Properties.Settings.Default.ClientSigningCertificatePassword;

2. The code you run in the console app is slightly different from a web application. To simplify, I'm pasting here the code you get out of the box in default.aspx, and I've indicated with a comment above the lines of code that were changed to make this work in a console app. Sorry, only C# here folks, if you want VB though this stuff should be easy to convert.

                // - NOTE: You need to put the Url to the site collection you want to work with here
                Uri hostWeb = new Uri("https://mySharePointUrl");

                // - here we are using WindowsIdentity.GetCurrent instead of from an HttpRequest
                using (var clientContext = TokenHelper.GetS2SClientContextWithWindowsIdentity(hostWeb, WindowsIdentity.GetCurrent()))
                {
                    clientContext.Load(clientContext.Web, web => web.Title);
                    clientContext.ExecuteQuery();
                    // - here we are using Console.Write instead of Response.Write
                    Console.Write(clientContext.Web.Title);
                }

3. Add a using statement to the program.cs (or .vb) file for System.Security.Principal
4. Right-click on your console project and select the Set as Start Up Project option.
5. Press F5 to launch console app and validate that the code works.

You should be good to go at this point. I actually walked through this process with a console app while writing this post, so as every good developer says if you have problems..."well, it works on my machine!" :-) I've also used this method MANY times previously for web apps so this should be solid as well.