Convert Office Add-In Web to MVC

Using Visual Studio to create a new Office Add-In results in two projects:  One for your Office Add-In (basically, the manifest) and another for the web project where you do the bulk of your work to implement functionality. The web project that is created is a basic HTML/JS/CSS application…nothing fancy like ASP.NET. For most situations, a lightweight client-side web application is ideal and it makes sense for that to be the default of the VS project template. How about those other situations where you need something to run on the server, like an ASP.NET MVC application? There are a couple choices:

  1. Add a new MVC project to your solution and pull in the Office “stuff” and trim it down so it can be used as the web project for your Add-In
  2. Convert the existing web project to MVC

I’ll show you how to do the second option in this post.

MVC Plumbing

  1. Using NuGet Package Manager, add Microsoft.AspNet.Mvc to your web project
  2. Add the following folders to your project:  App_Start, Controllers, Views
  3. Right-click the Views folder and add a new Web Configuration File and name it Web.config
  4. Add the following code to this new Web.config, replacing [[YourNamespace]] with the namespace of your project
       1: <?xml version="1.0"?>


       3: <configuration>

       4:   <configSections>

       5:     <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=, Culture=neutral, PublicKeyToken=31BF3856AD364E35">

       6:       <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />

       7:       <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />

       8:     </sectionGroup>

       9:   </configSections>


      11:   <system.web.webPages.razor>

      12:     <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

      13:     <pages pageBaseType="System.Web.Mvc.WebViewPage">

      14:       <namespaces>

      15:         <add namespace="System.Web.Mvc" />

      16:         <add namespace="System.Web.Mvc.Ajax" />

      17:         <add namespace="System.Web.Mvc.Html" />

      18:         <add namespace="System.Web.Routing" />

      19:         <add namespace="[[YourNamespace]]" />

      20:       </namespaces>

      21:     </pages>

      22:   </system.web.webPages.razor>


      24:   <appSettings>

      25:     <add key="webpages:Enabled" value="false" />

      26:   </appSettings>


      28:   <system.webServer>

      29:     <handlers>

      30:       <remove name="BlockViewHandler"/>

      31:       <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />

      32:     </handlers>

      33:   </system.webServer>


      35:   <system.web>

      36:     <compilation>

      37:       <assemblies>

      38:         <add assembly="System.Web.Mvc, Version=, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

      39:       </assemblies>

      40:     </compilation>

      41:   </system.web>

      42: </configuration>


I chose to use the Site.css stylesheet that the NuGet package created for me. To do that, I took all of the CSS from the app.css and the home.css file and put it in the Site.css file.


Copy the App.js and Home.js files to the Scripts directory.


I’ll assume your existing web project has the standard files from the VS template:  app.js, app.css, home.html, home.css and home.js. This section shows how to pull that content into a new view.

  1. Right-click the Controllers folder and add a new Controller named HomeController. This should add a file that looks like the following:
       1: using System;

       2: using System.Collections.Generic;

       3: using System.Linq;

       4: using System.Web;

       5: using System.Web.Mvc;


       7: namespace [[YourNamespace]].Controllers

       8: {

       9:     public class HomeController : Controller

      10:     {

      11:         // GET: Home

      12:         public ActionResult Index()

      13:         {

      14:             return View();

      15:         }

      16:     }

      17: }

  2. Add a Home and Shared folder to the Views folder
  3. Right-click the Shared folder and add a new View called _Layout using the “Empty (without model)” template and checking the box for “Create as a partial view”
  4. Replace the <head> content with the following (note the reference to the Office UI Fabric, that’s optional if you aren’t using it…but you should be):
       1: <meta charset="utf-8" />

       2: <meta name="viewport" content="width=device-width, initial-scale=1.0">

       3: <meta http-equiv="X-UA-Compatible" content="IE=Edge" />

       4: <title>@ViewBag.Title - My ASP.NET Application</title>

       5: <script src="~/Scripts/modernizr-2.6.2.js"></script>


       3: <link href="~/Content/Office.css" rel="stylesheet" />

       4: <script src="" type="text/javascript">

       1: </script>

       2: <script src="~/Scripts/jquery-1.10.2.min.js">

       1: </script>


       3: <!-- Office UI Fabric -->

       4: <link rel="stylesheet" href="//" />

       5: <link rel="stylesheet" href="//" />


       7: <link href="~/Content/Site.css" rel="stylesheet" type="text/css" />

       8: <script src="~/Scripts/App.js">

       1: </script>

       2: <script src="~/Scripts/Home.js">


  5. Replace the <body> content with the following:
       1: <div id="content-header">

       2:     <div class="padding">

       3:         <h1>[[Your application name]]</h1>

       4:     </div>

       5: </div>


       7: <div id="content-main">


       9:     @RenderBody()

      10:     <hr />

      11:     <footer>

      12:         <p>&copy; @DateTime.Now.Year - Content Mixr</p>

      13:     </footer>

      14: </div>

  6. If you have anything like a top nav or other content that is consistent across multiple pages in your app, paste it in there as appropriate
  7. Right-click the Home folder and add a new View called Index (or whatever you want it to be called, the rest of this post assumes Index) using the “Empty (without model)” template and checking the box for “Create as a partial view”
  8. Replace the contents of index.cshtml with the HTML from the <body> section of your home.html file (keep the ViewBag.Title at the top of the file if you’re going to use it)

Config and Cleanup

  1. Right-click the Views folder and add a new partial view called _ViewStart and add the following content:
       1: @{

       2:     Layout = "~/Views/Shared/_Layout.cshtml";

       3: }

  2. (This may already exist but create it if not) Right-click the App_Start folder and add a new class file called RouteConfig.cs and add the following content:
       1: using System;

       2: using System.Collections.Generic;

       3: using System.Linq;

       4: using System.Web;

       5: using System.Web.Mvc;

       6: using System.Web.Routing;


       8: namespace [[Your application namespace]]

       9: {

      10:     public class RouteConfig

      11:     {

      12:         public static void RegisterRoutes(RouteCollection routes)

      13:         {

      14:             routes.IgnoreRoute("{resource}.axd/{*pathInfo}");


      16:             routes.MapRoute(

      17:                 name: "Default",

      18:                 url: "{controller}/{action}/{id}",

      19:                 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

      20:             );

      21:         }

      22:     }

      23: }

  3. Open the Global.asax.cs file and edit the Application_Start() method to the following:
       1: protected void Application_Start()

       2: {

       3:     AreaRegistration.RegisterAllAreas();

       4:     RouteConfig.RegisterRoutes(RouteTable.Routes);

       5: }

  4. If your app doesn’t use Bootstrap, delete the Bootstrap CSS and JS files (if you are, go back to your _Layout.cshtml file and add the Bootstrap references as the above code doesn’t have it)
  5. You may have noticed the MVC package brought in a reference to a newer version of jQuery (1.10.2 as of the writing of this post.) There are now probably two jQuery versions in the Scripts folder so delete the version you don’t want.
  6. Open the App Manifest XML file (from the Office Add-In project) and set the DefaultValue for SourceLocation to ~remoteAppUrl since the default page of the app is now the web app default page
       1: <DefaultSettings>

       2:   <SourceLocation DefaultValue="~remoteAppUrl/" />

       3: </DefaultSettings>

That should do it. Please post a comment here or contact me directly if you hit any snags.

5 thoughts on “Convert Office Add-In Web to MVC”

  1. Your article helped me convert an existing Add-In to MVC format. The MVC project properly brings up my task pane with a series of dropdown lists and button. However, intermittently the dropdowns do not properly function in that you cannot change the selected value. Have you experienced this type of problem or have any ideas how to address it?

  2. Chris says:

    I’m trying to use MVC for a Word add-in I’m currently developing, but I can’t find a way to get it to work. I tried this guide, but some things were different from the way you explained. In example for me there wasn’t a Global.asax.cs file so I created it. Anyway in the end after having added everything from the guide, it doesn’t work. I can still open my old pages in the add-in that don’t use MVC, but the one I converted doesn’t work at all. Any idea what might be wrong?

  3. Denzel Washington says:

    I am not able to deploy the app.
    I am facing the following Error:
    Failed to deploy the manifest file to the Exchange server. This app can’t be installed. The value of the SourceLocation attribute, ‘http://localhost:******/’, contains an unsupported URL. You can only use https:// URLs.

    1. Suhan Shetty says:

      Try replacing the ~remoteAppUrl with localhost:

    2. mandeji says:

      you have to use HTTPS only , adding doesn’t support HTTP . google how to install https certificates

Leave a Reply

Your email address will not be published.