ASP.Net Web Forms Templates – Part 1

Normal “templates” with ASP.Net web forms uses the App_Themes folder and then places skin and css files so that different templates can be used. The problem with this, as I outlined in the introduction, if you set up a master page, there isn’t much you can do to change the complete layout of the site unless you modify that master page. When you have to maintain a single code base for an entire project, modifying this per customer is virtually impossible.

A solution to this problem is to move that master page out somewhere that a web designer can easily change but not have it affect the main site. For this part, there are a few simple steps:

  1. Create a folder for the templates
  2. Create a configuration setting for a current template
  3. Create a base page that will set the proper template

First we will create a folder to store the templates and move our master page there. Keep in mind that this can be pretty flexible. You can have multiple master pages. To keep this simple, however we are just going to use one.

You cannot use the App_Themes folder as you are not allowed to put a master page in there. Also, my recommendation for these master pages is to not have any code behind files. Keep it simple and only have the page.Master and nothing else. Code can be added to the markup if needed and in the next part of this series, I will outline how to build out a template API so that designers can get to your site functionality pretty easy. For now, just keep in mind that once you get rid of the code behind file, you will need to create a base master page class that these master pages inherit from. See below:

namespace ASPNetTemplates.CMS
{
  public class BaseMasterPage : System.Web.UI.MasterPage
  {
  }
}

And in the master page:

<%@ Master Language="C#" AutoEventWireup="true" Inherits="ASPNetTemplates.CMS.BaseMasterPage" %>

Once the folder for the templates have been added (I called it Themes), create another folder called Default and move your master page there. This will be our default theme. You should also place any CSS and image files into this default folder. Feel free to organize, but make sure you update the paths to these files. If you happen to need to use any of the images within your main content pages, make sure to set a standard (and document it) path. That way every template has the same path to the image files. It’s also a good idea to standardize the names of these files unless you build out a a full template setup where there is a theme settings file that specifies which image is for what component of the site. Additionally, get rid of any code behind. If you already have a complicated master page that has lots of code behind (like I dealt with) you will need to start on an API to bring the functionality you need back to the page.

Just so that we can see success when we are done, create a second template folder and make a copy of your master, css, and images into this folder. Change the master page in this template so that you will know it’s using a different master page when we switch templates.

For the next step, we need to set up a configuration of some sort so that the template can be switched. Ideally this will include a admin page to change the template. For now, we will just create a simple settings class that will hold our current template setting. Then we have this class save and load our settings. See below:

Settings.cs –

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.Serialization;
using System.Xml;

namespace ASPNetTemplates.CMS.SiteSettings
{
  public class Settings
  {
    public string CurrentTemplate { get; set; }

    public static Settings CurrentSettings
    {
      get
      {
        Settings siteSettings = LoadSettings();
        if (siteSettings == null)
          siteSettings = new Settings();

        return (siteSettings);
      }
    }

    public static Settings LoadSettings()
    {
      Settings siteSettings = null;

      using (var file = System.IO.File.Open(string.Format("{0}{1}//{2}", HttpContext.Current.Request.PhysicalApplicationPath, "App_Data", "Settings.xml"), System.IO.FileMode.OpenOrCreate))
      {
        var xmlSer = new XmlSerializer(typeof(Settings));
        try
        {
          siteSettings = (Settings)xmlSer.Deserialize(file);
        }
        catch (InvalidOperationException)
        {
          // An invalid operation exception is thrown if the settings.xml file doesn't exist or is blank.
        }
      }

      return (siteSettings);
    }

    public static void SaveSettings(Settings siteSettings)
    {
      using (var file = System.IO.File.Open(string.Format("{0}{1}//{2}", HttpContext.Current.Request.PhysicalApplicationPath, "App_Data", "Settings.xml"), System.IO.FileMode.OpenOrCreate))
      {
        var xmlSer = new XmlSerializer(typeof(Settings));
        xmlSer.Serialize(file, siteSettings);
      }
    }
  }
}

Settings.xml –



  Default

Now the final step is where the magic happens. To make things easy, so we don’t have to add code in each of our pages, we will make a base class that each of our pages will inherit from. This is the place where we will be setting the master page to use. This is pretty easy to do. See below:

namespace ASPNetTemplates.CMS
{
  public class BasePage : System.Web.UI.Page
  {
    protected override void OnPreInit(EventArgs e)
    {
      base.OnPreInit(e);

      this.MasterPageFile = string.Format("\\Themes\\{0}\\Site.Master", CMS.SiteSettings.Settings.CurrentSettings.CurrentTemplate);
    }
  }
}

Then in our pages we just inherit from this class –

namespace ASPNetTemplates
{
  public partial class _Default : CMS.BasePage
  {
    protected void Page_Load(object sender, EventArgs e)
    {
    }
  }
}

If all goes well you should be able to run the site and be presented with your default template. Now, to see the magic happen, change the settings.xml file to reflect the other template you set up and rerun the application.

Using Master Pages as Templates in ASP.Net WebForms – Introduction

I maintain a fairly simple CMS that our customers use for their public facing web site. Most of the CMS is pretty straight forward. Create, publish, edit content, etc. I took over this project as it was originally designed by an outside contractor. For the most part, the meat of the application is the same, aside from some changes here and there to optimize code reuse, optimize performance, add features, etc.

Since this CMS was designed to be installed as public facing sites, it was built to have templates so that each site could maintain their own unique look and feel. This was done in a pretty standard way that most ASP.Net sites are created. The site is created with a master page that helps maintain the same look and feel through the whole site and then in the App_Themes folder, the CSS files change the way the site looks. Code was added so that the theme can be switched on the fly.

This worked excellent for many years, however recently we had been getting many requests on completely changing the layout and placing content in places that were not designed to have content. Others wanted their main content to look much different than what we could support.

So, I set out to devise a way of doing templates that would allow the web designer complete control over the site templates. This small series is going to show (in a simplified way, mind you) how I built the new templates to give the web designer more control over the overall design of the site.

As I add posts to the series, I will add them to the bottom of this post.

ASP.Net Web Forms Templates – Part 1

Wrap your ASP.Net session state into a more meaningful object.

I’ve tried to eliminate as much session state as possible as I know that it can cause some issues, especially in a server farm environment. However, there are quite a few times that I just need to have it, and I really doubt this small application is going to be hosted in a farm environment. This application is connected to a WCF service, and I really needed to eliminate round trips without using caching since some of this data is somewhat time sensitive, but it still needs to be available across a few page views. Instead of hitting the WCF service numerous times, I save the data in session state.

The way most people seem to have done session state (at least in just random searches on the internet and in sample code), you see this:

  HttpContext.Current.Session["SomeData"] = myData;

There is nothing wrong with this. It works. Is it maintainable? Sort. Is it a potential problem? YES! What happens if you do this somewhere:

  myData = HttpContext.Current.Session["SomData"];

Obviously you are going to get a null object back and possibly an error depending on other factors. You will probably find the problem during your automated tests (you do have automated tests right?) or at minimum find it during your own testing. The problem is, sometimes things like this will slip past if they are in infrequently used parts of a system that no one bothers to check for 3 or 4 versions that pass.

So in searching around I found various posts on how to wrap your session state into a more manageable object so that typos don’t creep up and bite you on the backside. Some of the examples went way over what I needed to do and some were way too simple to make sense for me.

So here is what I did (if I happened to have stolen your code, sorry, but it happens in software).

First I created my Current Session class to store everything and I made it static since Session itself is a static object.

  public static class CurrentSession
  {
    private static HttpSessionState LiveSession
    {
      get { return HttpContext.Current.Session; }
    }
  }

This simple gives me a class that has access to the current session through a private variable called LiveSession.

Inside this class, I created another class for the CurrentUser since I needed to track the current logged in user (this user has data from the web service, so I’m not using asp.net authentication methods).

    public static class CurrentUser
    {
      public static bool IsLoggedIn
      {
        get 
        { 
          bool? logIn = GetUserItem(UserData.LoginState);
          if (!logIn.HasValue) logIn = false;
          return (logIn.Value);
        }
        set { SetUserItem(UserData.LoginState, value); }
      }

      public static FamilyData CurrentFamily
      {
        get { return (GetUserItem(UserData.Family)); }
        set { SetUserItem(UserData.FamilyInfo, value); }
      }

      private static T GetUserItem(UserData key)
      {
        T data = (T)LiveSession[Enum.GetName(typeof(UserData), key)];
        return (data);
      }

      private static void SetUserItem(UserData key, T data)
      {
        if (data == null)
          LiveSession.Remove(Enum.GetName(typeof(UserData), key));
        else
          LiveSession[Enum.GetName(typeof(UserData), key)] = data;
      }

      public enum UserData
      {
        Family,
        LoginState
      }
    }

Now, some explanation and why I did it the way I did. I could have just made my public variable have the getter and setter access the Session object directly. My typo chances would have been minimized by the fact that it’s only in two spots that I need to type it, but there is still a chance. So I created myself an enum that I can use to specify which sets of data I am saving or retrieving. I use the enum’s string value as the session object name, so all I have to do is make sure my enums never use the same name. In my RLC (Real Life Code) I use much longer enums, like CalendarFilterMonth or CalendarFilterDay, for example. In the above example, I use LoggedInUserFamily in place of just Family. While it may be long, intellisense always gets it right for me with just a few keystrokes.

The GetUserItem and SetUserItem simple save and retrieve from the LiveSession object. I use Type generics to tell the functions what type I am saving and retrieving for ease of use. My type casting never has to be done now. I tell it what I want and that’s what I will get in return.

The best part about this, is to add more, all I need to do is copy and paste a property and change a few of the options, maybe add an enum, and now I’m done. I don’t have to worry about typo’s and I can organize my session object however I want.

To use it, I just do this anywhere in my application:

  if (!CurrentSession.CurrentUser.IsLoggedIn)
     RedirectToLogin();
  else
     if (CurrentSession.CurrentUser.CurrentFamily.NeedsProfileUpdate)
        RedirectToUpdate();

Since NeedsProfileUpdate is part of my FamilyData class, I can access that directly!

First usage of WCF and specified fields.

I hadn’t done much in the past with WCF. We had built our web service with the classes .Net 2.0 form of web services and it worked well. Then one day I realized that we had no built in security other than SSL. Since we had added a lot more things to it that could do some damage if a hacker found the service address, I decided to add some basic security. Needless to say, it’s not as easy as it looks with straight web services.

After doing some searching, I found a few examples of using WCF and implementing custom username authentication, which is exactly what I wanted to do.

Getting WCF set up and running was quite easy. Porting over our web service code just meant creating my ServiceContract and DataContracts and then recompiling. I also had to set my SQL to Linq datacontext serialization mode to Unidirectional. After coding up my custom username authentication and testing it, things were going along quite smoothly.

Everything I had experienced with Linq to SQL serialization still applied to WCF. Relationships had to have the parent set to internal access instead of public. I did also find that the relationships seemed to need a One-To-Many in order to work right. If it was a Many-To-One or a Many-To-Many, it wasn’t being sent from the WCF service to the client. Since I was in a hurry, I left that issue on the back burner and worked around it. If I five more into it, I will post about it here.

The one thing I had not counted on, was the fact that if you have any fields (properties) marked as being nullable, the Add Service wizard in Visual Studio 2008 will also add a boolean field called fieldSpecified. So if you have a nullable field for, say, PhoneNumber, you will have that and PhoneNumberSpecified. If you fill in the PhoneNumber field, but do not set PhoneNumberSpecified to true, the field will not be sent to the WCF service.

From my little bit of research, if that Specified field is set to false, the property will not be included in the XML document sent to the WCF service. If it is set to true, it will send it whether it’s null or not.

Since some of our classes have quite a few fields and we have quite a bit of code to set those fields, I did not want to go through and set every one of these stupid properties to true when I set a field. I’m actually quite surprised that we even need to do this.

In searching for an answer, I found the long way around of writing a program to parse your service.cs (or .vb) file and inserting this code:

  [System.Xml.Serialization.XmlElementAttribute(Order = 0)]
  public string PhoneNumber
  {
    get
    {
      return this.PhoneNumber;
    }
    set
    {
      this.PhoneNumber = value;
      PhoneNumberSpecified = true; // Line Added
    }
  }

So, we have to add one line to each property that has a corresponding Specified field. Now I know why people wrote a utility to do this. That file will get overwritten each time you update your service reference.

I wasn’t too pleased I had to do this so I tried to find a better way. I finally settled on using the PropertyChanged events and some reflection to go and fill that field in.

To make things simple, my Linq to SQL classes all have a base class called BaseBusiness where I do validation and hold some original values so we can use the disconnected nature of the web with Linq to SQL entities. Since I did this, I can only derive my classes on the client side from the same base class. So I created my BaseBusiness class and included my PropertyChange event in there like this:

  public partial class BaseBusiness
  {
    public void InternalPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
      if (!e.PropertyName.Contains("Specified"))
      {
        string prop = String.Format("{0}Specified", e.PropertyName);
        PropertyInfo target = this.GetType().GetProperty(prop);
        if (target != null)
        {
          PropertyInfo src = this.GetType().GetProperty(e.PropertyName);
          bool currentValue = (bool)target.GetValue(sender, null);
          bool hasValue = (src.GetValue(sender, null) == null ? false : true);
          if (currentValue != hasValue)
            target.SetValue(sender, hasValue, null);
        }
      }
    }
  }

This is pretty straight forward so far. I check to see if the field is already set to what it should be so I don’t make any unneccesary calls. Note that I use sender as the object I am using the GetValue and SetValue on. This is because the event is in a base class and wouldn’t be the right object to use for reflection since the properties would be one level up (or down, depending of where you stand).

Now the only step left is to write it up in the data classes. Which is nothing more than this:

public partial class MyDataClass : BaseBusiness
{
  public MyDataClass()
  {
    this.PropertyChanged += InternalPropertyChanged;
  }

  ~MyDataClass()
  {
    this.PropertyChanged -= InternalPropertyChanged;
  }
}

Next Page →