I have solved this problem in the past by using NuGet packages. They can be as complex or as simple as you need them to be. A basic master page layout can be achieved simply by manually creating a .nuspec file, building it using the command line tool and hosting it on the file system (local or network).
Add a config file to the root of your template project - call it template.nuspec and add the following:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>MyAppTemplate</id>
<version>1.0.0</version>
<description>A template web application</description>
<authors>Me or my company</authors>
</metadata>
<files>
<file src="Site.Master" target="content\Site.Master" />
<file src="Site.Master.cs" target="content\Site.Master.cs" />
<file src="Site.Master.designer.cs" target="content\Site.Master.designer.cs" />
</files>
</package>
Note the target is "content" - this will drop the master page in the project root wherever the NuGet package is installed. You may also wish to change the namespace of the master page to $rootnamespace$
as this will do a source code transformation that will make the master page part of the same namespace as the rest of your project.
From the command line, you can then just call nuget.exe pack path\to\nuspec\file
which will result in a .nupkg
file being created. For local development I usually drop it in C:\NuGet\Local
, although that could be a network share \\MyShare\InternalNuget
or there are solutions like ProGet or TeamCity if you want to take it further.
Then in Visual Studio you can add it as a package source:
Tools -> NuGet Package Manager -> Package Manager Settings -> Package Sources
Click on the plus sign and add your folder / unc path / url and then you can reuse it in any other project.
As a general rule it is better to allow NuGet to overwrite the existing Site.Master when you create the project, and then don't edit the files, as this allows you to manage changes centrally using NuGet package versioning. However if you do wish to make project specific changes you may do so, you just have to remember not to let the NuGet package overwrite the project version on subsequent updates.
You can include all types of file from your template project. This includes .ascx
user controls, css and javascript files as well compiled or uncompiled base pages (inheriting from System.Web.UI.Page
). The possibilities are endless. With a <asp:contentplaceholder/>
and appropriate CSS, you could use a generic menu in most projects via a user control, but still substitute it for a more complex menu in other projects without modifying the main template.
EDIT:
I guess it could be possible to achieve the desired effect (at least for relatively simple content) by splitting the wrapper into two parts. The first would be a NuGet package containing the master page. This master page could contain iframes for the header and footer in the diagram, content placeholders and css and script tags for the common styles and javascript.
The second part of the wrapper would be a separate application, hosting the content of the iframes and the .css and .js files. Major changes like adding a new javascript library would still require updating the Master Page, but minor changes like adding a new function or css class or changing a brand or logo could be accomplished by changing the wrapper files and republishing it. Sort of like hosting your own simple CDN.
Master page looks like this:
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="$rootnamespace$.SiteMaster" %>
<html>
<head runat="server">
<title><%: Page.Title %></title>
<link href="https://example.com/mywrapperapplication/styles/mywrapper.css" rel="stylesheet" />
</head>
<body>
<iframe src="https://example.com/mywrapperapplication/header.html" />
<form runat="server">
<asp:ContentPlaceHolder ID="MenuContent" runat="server"></asp:ContentPlaceHolder>
<asp:ContentPlaceHolder ID="BodyContent" runat="server"></asp:ContentPlaceHolder>
</form>
<iframe src="https://example.com/mywrapperapplication/footer.html" />
<script type="text/javascript" src="https://example.com/mywrapperapplication/scripts/mywrapper.js"></script>
</body>
</html>
Then you have static content or a simple application deployed at https://example.com/mywrapperapplication
with 4 (or more) files:
header.html --or aspx or whatever
footer.html
/scripts/mywrapper.js
/styles/mywrapper.css
Any change you make to any of these files, will automatically be propagated in the wrapped application as they are linked from the master page. You would only need to republish the wrapped application if you wanted to add an additional file for example
<link href="https://example.com/mywrapperapplication/styles/mynewstyles.css" rel="stylesheet" />