Exposing an application API to your presentation layer

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.

How to do it...

  1. Create a new default ASP.NET MVC 2 application.
  2. Then we will create several base classes, which we will use to insert an extension point between our views, partial views, master pages, and controllers. We will start by creating a base class for our controllers. Create a new class called BaseController.cs in the Models folder, which inherits from Controller.

    Models/BaseController.cs:

    public class BaseController : Controller {
    }
    
  3. Next, we will create a base class for our view pages. This base class will be a bit different from the controller base class—in that we have two different types of view pages to inherit from.
    public class BaseViewPage : ViewPage {
    }
    public class BaseViewPage<T> : ViewPage<T> {
    }
    
  4. We can create a BaseHttpApplication, BaseViewMasterPage, and BaseViewUserControl to provide further points of extensibility. These classes will go into the Models directory also.

    Models/...:

    //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> {
    }
    
  5. Once we have all these base classes created, we can start to weave them into our application. They will provide us with a place to easily slip in extended functionality as we need to. All that we need to do is add the word 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" %>
    ...
    
  6. Now we can create some application bits for our demonstration. In this case, we will create some configuration values in our 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>
    ...
    
  7. Now we will create a wrapper class for accessing these config values. This will be a new class called 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");
    }
    }
    
  8. Now we are ready to create our wrapper class, which we will use to expose our site's API to the developers of our application. This class will be called 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; } }
    }
    
  9. With our 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>
    
  10. However, this class would be a touch easier to use if it were exposed as a property from the various locations that we work in, such as controllers, views, partial views, and master pages. If only we have an easy way to expose such a property. Oh wait...our base classes. We can easily expose a 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; } }
    }
    
  11. With this, we can update our 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>
    
  12. You can now run the application and you will see that the data is brought up and out of the 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).
    How to do it...

How it works...

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!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset