If you work in a team of varied levels of skill, you might find the need to make some of the more complex aspects of your application easier to consume. While you could create a series of wrapper classes, factories, and repositories, junior developers might find their lives to be easier if they had a single point of entry to your application. It is surprisingly easy to create a super wrapper for all the functionality of your application and then expose it throughout the presentation layer of your website. Creating such an API is the topic of this recipe.
BaseController.cs
in the Models
folder, which inherits from Controller
.Models/BaseController.cs:
public class BaseController : Controller { }
public class BaseViewPage : ViewPage { } public class BaseViewPage<T> : ViewPage<T> { }
BaseHttpApplication, BaseViewMasterPage
, and BaseViewUserControl
to provide further points of extensibility. These classes will go into the Models
directory also.//BaseHttpApplication.cs public class BaseHttpApplication : HttpApplication { } //BaseViewMasterPage.cs public class BaseViewMasterPage : ViewMasterPage { } public class BaseViewMasterPage<T> : ViewMasterPage<T> { } //BaseViewUserControl.cs public class BaseViewUserControl : ViewUserControl { } public class BaseViewUserControl<T> : ViewUserControl<T> { }
Base
in front of the MVC framework pieces. An example of this would be in our Site.Master
page, which originally inherited from ViewMasterPage
. We will make our master page inherit from BaseViewMasterPage
. Do this with all the view pages, controllers, and user controls in the application.Views/Shared/Site.Master:
<%@ Master Language="C#" Inherits=" StateExamples.Models.BaseViewMasterPage" %> ...
app.config
. We will create values such as ContactEmail, ContactPhone, RootUrl
, and SiteName
in the Web.config
.Web.config:
<configuration> <appSettings> <add key="ContactEmail" value="[email protected]" /> <add key="ContactPhone" value="(661) 123-4567" /> <add key="RootUrl" value="http://localhost:50981"/> <add key="SiteName" value="www.MvcCookbook.com"/> </appSettings> ...
Configuration
. This class will keep all the aspects of the ConfigurationManager
class hidden away from our application by exposing these values as properties of the Configuration
class. Also, as this class will expose the same data to all users of our site, we will make this class using the singleton pattern.Models/Configuration.cs:
public sealed class Configuration public sealed class Configuration { #region Singleton private static volatile Configuration instance; private static object syncRoot = new object(); private Configuration() { } public static Configuration Instance { get { if (instance == null) { lock (syncRoot) { if (instance == null) instance = new Configuration(); } } return instance; } } #endregion public string RootUrl { get { return GetString("RootUrl"); } } public string ContactEmail { get { return GetString("ContactEmail"); } } public string ContactPhone { get { return GetString("ContactPhone"); } } public string SiteName { get { return GetString("SiteName"); } } private string GetString(string key) { if (ConfigurationManager.AppSettings[key] != null) return ConfigurationManager.AppSettings[key].ToString(); throw new ConfigurationErrorsException(key + " was not found in the configuration"); } private int GetInt(string key) { if (ConfigurationManager.AppSettings[key] != null) return Convert.ToInt32( ConfigurationManager.AppSettings[key]); throw new ConfigurationErrorsException(key + " was not found in the configuration"); } }
Website
and will be placed in the Models
directory. We will also use the singleton pattern when creating this class. This class will have a property on it called Configuration
and will return an instance of the Configuration
class.Models/WebSite.cs:
public sealed class Website { #region Singleton private static volatile Website instance; private static object syncRoot = new Object(); private Website() { } public static Website Instance { get { if (instance == null) { lock (syncRoot) { if (instance == null) instance = new Website(); } } return instance; } } #endregion public Configuration Configuration { get { return Configuration.Instance; } } }
Website
class created, we are technically ready to consume its values from anywhere in our site. As the Instance
property on the Website
class is static, we can easily use this class as we wish and where we wish. For example, on the home page, we can easily display the e-mail address at which we can be contacted.Views/Home/Index.aspx:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2><%: ViewData["Message"] %></h2>
<p>To learn more about ASP.NET MVC visit
<a href="http://asp.net/mvc" title="ASP.NET MVC Website"> http://asp.net/mvc</a>.
</p>
<p>Please feel free to contact us at
<%= StateExamples.Models.Website.Instance.Configuration. ContactEmail %>
.</p>
</asp:Content>
Website
property in all of our base classes.Models/BaseViewMasterPage.cs:
public class BaseViewMasterPage : ViewMasterPage { public Website Website { get { return Website.Instance; } } } public class BaseViewMasterPage<T> : ViewMasterPage<T> { public Website Website { get { return Website.Instance; } } }
Site.Master
page to use the API. All that this means is that we can remove the Instance
property from our call. But this tends to make our code easier to read.Views/Shared/Site.Master:
<p>Please feel free to contact us at <%= Website.Configuration.ContactEmail %> .</p>
web.config
file, through the configuration class, and out of the Website
instance and on to our web page. This one line of code hides away a great deal of complexity (albeit simple complexity in this case).All that we have done in this recipe is created a very high level set of objects that wrap a level of complexity, which in turn wraps another level of complexity. Each set of classes that we put deeper behind our API serves to hide a level of complexity. This brings a certain degree of uniformity to our application. It also simplifies our presentation layer code by quite a bit!