ASP.NET MVC

  • Using ASP.NET MVC and Shibboleth Authentication

    If you’re using Shibboleth as your resource authentication method, there’s a few things you need to do in order to use it effectively with ASP.NET MVC.

    The first thing to do is to configure routing correctly.  Shibboleth uses a special route against your website that is intercepted by the ISAPI filter that is part of the Shibboleth install on your web server.  However, in integrated pipeline mode, your application will receive these Shibboleth requests and won’t know what to do with them and issue a 404 not found.  The solution is to ignore the routes that Shibboleth uses and let them pass through to the Shibboleth system:

    routes.IgnoreRoute("Shibboleth.sso/{*pathInfo}");
    

     

    The ‘routes’ variable is a RouteCollection type passed to your RegisterRoutes() method in the RouteConfig.cs file of an MVC 4 project.  This ensures that the Shibboleth routes are never processed by your application.

    The second thing is to turn off all authentication for your web site.  Since Shibboleth’s single sign-on is going to handle protecting your resources, you will not need to configure any authentication in your web.config or in IIS.  Instead, you will configure it with your shibboleth2.xml file.

    Categories: ASP.NET MVC

  • Creating a Type Safe AppSettings Accessor for ASP.NET

    Many times I place settings in the <appSettings> section of the web.config file for an ASP.NET application.  These settings could be things like the title of the application, a URL for support, or maybe e-mail settings if your application sends out email.  Retrieving this information involves the use of the ConfigurationManager class in the System.Configuration namespace.

    One technique that I like to use is to wrap each of the settings into a type-safe read-only property accessor that is a static member on a static helper class.  The type of the property is the correct type that we expect in order to use it in code.  For example, if you have a on/off switch in your settings you probably want the value of the setting to be a bool.  Many times your settings are just strings, which are the easiest to parse but maybe you also want to ensure that the string is actually there and not null.

    The following code snippet shows an implementation of a static helper class that does all these things:

    public static class AppSettings
    {
        /// <summary>
        /// Gets the application's title.
        /// </summary>
        public static string ApplicationTitle
        {
            get { return Retrieve("Application.Title"); }
        }
    
        private static string Retrieve(string key, bool required = true)
        {
            string value = ConfigurationManager.AppSettings[key];
            if (required && string.IsNullOrEmpty(value))
                throw new InvalidOperationException(
                    string.Format("{0} is missing but is required to be defined in appSettings.", key));
            return value;
        }
    
        private static bool RetrieveBool(string key)
        {
            string s = Retrieve(key);
            bool result = false;
            if (!bool.TryParse(s, out result))
                throw new InvalidOperationException(
                    string.Format("{0} is missing or has an invalid setting. " +
                                                 "'true' or 'false' are acceptable values for this setting.", key));
            return result;
        }
    
        private static int RetrieveInt(string key)
        {
            string s = Retrieve(key);
            int result = 0;
            if (!int.TryParse(s, out result))
                throw new InvalidOperationException(
                    string.Format("{0} is missing or has an invalid setting. " +
                                    "An integer value was expected.", key));
    
            return result;
        }
    
        private static DateTime RetrieveDateTime(string key)
        {
            string s = Retrieve(key);
            DateTime result;
            if (!DateTime.TryParse(s, out result))
            {
                throw new InvalidOperationException(
                    string.Format("{0} is missing or has an invalid setting.  A valid date/time format was expected.", key));
            }
    
            return result;
        }
    
        private static T RetrieveEnum<T>(string key) where T : struct
        {
            T result = default(T);
            if (!Enum.TryParse<T>(Retrieve(key), out result))
                throw new InvalidOperationException(string.Format("{0} is not a valid enumeration value.", key));
            return result;
        }
    }
    


    You can see that there are several private helpers that all Retrieve a particular data type given a key name.  There’s one for strings, bools, ints, date/times, and even enums.  If the wrong data type or a missing value is detected, an exception is thrown so you can catch mis-configured apps easily.

    To use this class, you’d simply place in your code like so (in a Razor view, but it could be anywhere):

    <h1 class='title'>@AppSettings.ApplicationTitle</h1>

    Categories: ASP.NET MVC

  • ASP.NET MVC Action Filter Example: Ensuring an Entity Exists

    Many times in ASP.NET MVC action methods, you are passing in a key (such as an id parameter) that you will use to lookup an entity in your database with.  Typically this lookup is done with an ORM such as NHibernate or Entity Framework or it could be RavenDB or something else.  The point is, you spend a lot of time taking the key parameter and looking it up in your database and checking to see if the database returned the correct object.

    Since this is such a common task, we should make an ActionFilter that can do the check for us and ensure that the entity really exists in the database.  This example uses RavenDB to access the database, but it could be replaced with any code that you use for your particular implementation.  It uses a domain existing of an Order type that represents a customer’s order at a store:

    public class OrderExistsAttribute : ActionFilterAttribute
        {
            protected string parameterName = "id";
            protected Order order;
    
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                base.OnActionExecuting(filterContext);
                if (!filterContext.ActionParameters.ContainsKey(ParameterName))
                {
                    throw new InvalidOperationException("Missing parameter: " + ParameterName);
                }
    
                string id = filterContext.ActionParameters[ParameterName] as string;
                if (id == null)
                {
                    throw new ArgumentNullException("id is required.");
                }
    
                order = RavenDb.CurrentSession.Load<Order>(id);
                if (order == null)
                {
                    throw new Exception("Specified Order does not exist.");
                }
            }
    
            /// <summary>
            /// Gets/sets the parameter name that is used to identify the parameter that will act 
            /// as an order key.  Default is 'id'.
            /// </summary>
            public string ParameterName
            {
                get { return parameterName; }
                set { parameterName = value; }
            }
        }

    The RavenDb class is just a helper that I use that puts the current request’s IDocumentSession in a static accessor called CurrentSession (this in turn reads it out of the HttpContext.Items collection to get a thread-local session for that particular request). 

    You can set the ParameterName property to the name of the parameter in your action method.  Typically this is just ‘id’ so that is the default that is used. 

    Here’s how to use this attribute on an action method:

    [OrderExists]
    public ActionResult Index(string id)
    {
      // you are guaranteed at this point that the
      // order specified by id actually exists
    
    }

    If you were using NHibernate or RavenDB for this (as I was), you can call the Load() method of the database session to retrieve the Order instance by that id and since it was already loaded by the action filter, it will be instantly returned by the session cache.

    You could also derive from this class to create new scenarios such as not only checking for the existence of the Order but also that it is in a particular status/state.  For example, if we have a Save() action method, we probably don’t want to allow saving an order that has already completed.  Once the Order is loaded, you can do any logic you wish on it.  Security or access to the Order could be enforced in this attribute too.

    The bottom line here is that the attribute can be used on any action method and saves us a lot of effort by not having to repeat ourselves.

    Categories: ASP.NET MVC

  • 1