WCF and the Mystery 404

We're working on our first Windows Communication Foundation (WCF) project hosted in IIS6.  Upon deployment we ran into a wall when requesting a .svc file - 404.  After hours of chatting with Microsoft on the phone and consulting with Filemon it ended up being a simple issue - the app pool identity was running as Network Services and not a domain account.  This was problematic because our files live on a network share, and although we connected to it with a domain account, the app pool account did the executing.

Hmmm... "executing."  Interesting it gave a 404 and not some access denied message right?  The MS support rep said there are basically two tokens used; one for connecting and one for executing which seems to indicate retrieving of the file as well.

Another lesson learned.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

ASP.NET MVC: Store Routes in the Database

Download the sample MVC project for this post
NOTE:  You should have ASP.NET MVC Preview 3 or later installed to run the provided download.

So far I’m a huge fan of the ASP.NET 3.5 MVC framework which is currently released as Preview 3.  Having worked with primarily Microsoft web frameworks MVC provides a refreshing perspective for what I consider an improved tier separation.

An immediate beef I have with ASP.NET MVC is defining the routes in the Global.asax.cs… I can’t change routes without recompiling and deploying code.  I thought it better to configure routes in a more dynamic environment, specifically the database, which is what this post will provide an example for.
I’ve broken the implementation into three main pieces: 

  1. Database schema for storing routes and route default parameters
  2. LINQ to SQL model for accessing the routes
  3. Class for handling route routines

 

Database Schema – “Mvc”

MvcRoutes Table

Routes table design

routeID
– the primary key for a route.
routeName – simply for identification purposes.  This isn’t used in the app.
routePattern – the URL structure of the route.
routeIsActive – turn your route on or off.
routeOrder – routes are executed on a first match basis.  It may be important to order your routes so a more specific pattern is caught first before a more general pattern catches it… similar logic to exception handling.


MvcRoutes Sample Data

Routes table data
 

MvcRouteParams Table

Route parameters table design

paramID
– the primary key and identifier for the route parameter.
routeID – foreign key to the MvcRoutes.RouteID value.
paramKey – route defaults are stored as a Dictionary.  This is the key for a default.
paramValue – the default value for the paramKey.
paramConstraint – a regular expression value specifying allowed values for the parameter
paramDataType – I’m actually not using this right now but it feels right to analyze the expected data type in a more complete sample… or somethingJ.

 

MvcRouteParams Sample Data

Route parameters table data
 

LINQ to SQL Model

The model is super simple… connect to your MVC routing database and drag the MvcRoutes and MvcRouteParams tables to a new LINQ to SQL class.
Route parameters table design
Now we can do some simple queries.
 

Route Helper Class – Routing.cs

The Routing.cs class provides a handful of methods for working with the RouteTable and interaction with the database.  In my project I included a new controller to handle resetting and displaying the routes which utilizes some of these additional methods.
 
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
 
using MvcAltRouting.Models;
 
namespace MvcAltRouting
{
    internal class Routing
    {
        public static RouteCollection Routes
        {
            get { return RouteTable.Routes; }
        }
 
        /// <summary>
        /// Gets the configured routes.
        /// </summary>
        /// <returns></returns>
        public static List<MvcRoute> GetConfiguredRoutes()
        {
            MvcRoutesDataContext db = new MvcRoutesDataContext();
            List<MvcRoute> dbRoutes = (from b in db.MvcRoutes
                                       where b.routeIsActive == true
                                       orderby b.routeOrder
                                       select b).ToList();
            return dbRoutes;
        }
 
        /// <summary>
        /// Clears current and readds application routes.
        /// </summary>
        public static void ResetAppRoutes()
        {
            Routes.Clear();
            SetAppRoutes();
        }
 
        /// <summary>
        /// Sets the application routes.
        /// </summary>
        public static void SetAppRoutes()
        {
            List<MvcRoute> configuredRoutes = GetConfiguredRoutes();
            SetAppRoutes(configuredRoutes);
        }
 
        /// <summary>
        /// Sets the application routes.
        /// </summary>
        /// <param name="configuredRoutes">Collection of routes to add to the application's routing table.</param>
        public static void SetAppRoutes(List<MvcRoute> configuredRoutes)
        {
            //add the routes to the RouteCollection
            foreach (MvcRoute route in configuredRoutes)
            {
                //create RouteValueDictionary objects to add the default values and contraints to the route
                RouteValueDictionary constraints = new RouteValueDictionary();
                RouteValueDictionary routeVals = new RouteValueDictionary();
 
                foreach (MvcRouteParam param in route.MvcRouteParams)
                {
                    routeVals.Add(param.paramKey, param.paramValue);
                    if (!string.IsNullOrEmpty(param.paramConstraint))
                    {
                        constraints.Add(param.paramKey, param.paramConstraint);
                    }
                }
 
                //create the route using the defaults set above
                RouteTable.Routes.Add(new Route(route.routePattern, new MvcRouteHandler())
                {
                    Defaults = routeVals,
                    Constraints = constraints
                });
            }
        }
    }
}
 

Global.asax.cs

Lastly change the Application_Start method to use the new Routing class to populate the application routes, removing the need for the routes defined within the Global.asax.cs.
using System;
 
namespace MvcAltRouting
{
    public class GlobalApplication : System.Web.HttpApplication
    {
        protected void Application_Start(object sender, EventArgs e)
        {
            Routing.SetAppRoutes();
        }
    }
}


That’s It!

Start up the provided project and navigate to the “Display Routes” link.  You can see the routes have been set from the database values we saw from above!

Have you been working with the ASP.NET MVC framework?  If so have you moved the route configuration out of the Global.asax.cs or are you happy with the default configuration for editing routes?
 
Download the sample MVC project for this post
NOTE:  You should have ASP.NET MVC Preview 3 or later installed to run the provided download.

kick it on DotNetKicks.com
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

GameSpy Christmas Party and Rock Band

I'm the drummer... this party rocked!

 

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

ASP.NET 3.5 Extensions MVC Preview 2 Released

I really liked tinkering with Preview 1 so I'm REALLY excite to get my paws on Preview 2.  You can check out some MVC Preview 2 videos here and download the MVC Preview 2 here.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Inject Dependency with Spring.NET and Generics

In my first post about Dependency Injection with Spring.NET I provided a simple example and explanation of how to use Spring.NET.  Having fiddled with Spring.NET further I quickly realized I was duplicating code to load configured objects.  I thought my method may be useful to others.

using System.IO; 

using Spring.Objects.Factory.Xml;

 

namespace TestApp

{

    public class ConfigHelper

    {

        public static T GetInjectedObject<T>(string configFileLocation, string configObjectName)

        {

            using (Stream stream = File.OpenRead(configFileLocation))

            {

                Spring.Core.IO.InputStreamResource resource = new Spring.Core.IO.InputStreamResource(stream, "config");

                XmlObjectFactory xmlObjectFactory = new XmlObjectFactory(resource);

                return (T)xmlObjectFactory.GetObject(configObjectName);

            }

        }

    }

}

For this method to work your project must reference Spring.Core.dll.  To call this method supply the location of the configuration file and the name of the configuration key to be used, which represents the type of object to be created.

The above method is very basic but not quite the efficient implementation one would want in a production app.  As an update to this post I've included a more efficient method which holds XmlObjectFactory objects in a static Dictionary (thanks for the comment Brian).  The first call to this method for a particular config file will load it and place it's XmlObjectFactory in the static Dictionary.  Subsequent calls will use the object from the Dictionary.  Some may prefer to use cache so objects not used frequently are disposed of.  I didn't just to stay more compatible with a variety of implementations.

using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.IO;

 

using Spring.Core.IO;

using Spring.Objects.Factory.Xml;

 

namespace TestApp

{

    public class ConfigHelper

    {

        /// <summary>Used for safe manipulation of objects.</summary>

        private static object _lockObject = new object();

 

        /// <summary>Holds previously acquired XmlObjectFactory objects.</summary>

        private static Dictionary<string, XmlObjectFactory> _objectFactories =

            new Dictionary<string, XmlObjectFactory>();

 

        public static T GetInjectedObject<T>(string configFileLocation, string configObjectName)

        {

            XmlObjectFactory objectFactory = null;

 

            if (_objectFactories.ContainsKey(configFileLocation))

            {

                objectFactory = _objectFactories[configFileLocation];

                Trace.WriteLine(string.Format("Object factory found in Dictionary - {0}, {1}", configObjectName, configFileLocation));

            }

 

            if (objectFactory == null)

            {

                //load the configuration from disk

                using (Stream stream = File.OpenRead(configFileLocation))

                {

                    InputStreamResource resource = new InputStreamResource(stream, "config");

                    objectFactory = new XmlObjectFactory(resource);

 

                    //double-check lock so we don't attempt to add twice

                    lock (_lockObject)

                    {

                        if (!_objectFactories.ContainsKey(configFileLocation))

                        {

                            _objectFactories.Add(configFileLocation, objectFactory);

                            Trace.WriteLine(string.Format("Object factory added to Dictionary - {0}, {1}", configObjectName, configFileLocation));

                        }

                    }

                }

            }

 

            return (T)objectFactory.GetObject(configObjectName);

        }

    }

}

Surely this is just one step in the evolution of working with Dependency Injection.  If you've some pointers I haven't considered please share! 

kick it on DotNetKicks.com
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

WebConfigurationManager for Multiple Configuration Files

I wrote this up a while back but had it on a site of mine most wouldn't have come across.  I've moved it to my blog in hopes it'll be of some help to someone. 

 

I manage the development of a rather flexible ecommerce site called Direct2Drive.  When I say “flexible” I’m speaking in terms of its template and customization abilities.  We resell a hosted solution for rebranding this site and catalog for outside vendors allowing them to sell our product catalog items without the hassle of managing the supplier relationships, billing, and fulfillment.  Think Amazon.com hosting the Toys R Us site.  Much of the configuration for this system is handled in the web.config file which isn’t optimal for a number of reasons.  What I would consider the most notable problem with this is the web.config is frequently being updated to store the settings of each site we host and is therefore a central failure point for all sites.  This configuration worked well for us when we had only a couple of sites.  As we grow, the risk grows.

 

So what to do about it?  I wanted to store configuration data for each site in a separate configuration file so as we update each site no other site would be affected.  I wasn’t able to locate a really good means of addressing this issue within the .NET 2.0 framework (or .NET 1.1 of course) so I created my own WebConfigurationManager for custom web.config files – enter WebConfigurationManager2 (yes, very creative name).

 

WebConfigurationManager2 allows a developer to access a web.config file located in an alternate directory and treat it as a Configuration object.  More specifically, WebConfigurationManager2 stores a collection of configuration files.  I'd have found it more useful if Microsoft didn't actually care what the filename was... they do though.  In this case it must be named web.config.

 

Standard access of the application’s web.config utilizes caching to optimize access of configuration information.  I’ve implemented the same in WebConfigurationManager2 with invalidation occurring either within ten minutes (no reason, just used ten for now) or on change of the loaded configuration file.  Well, it’s not exactly the same.  I actually store each configuration in a static Dictionary object and implement caching on arbitrary data and the file.  This approach allows me a couple of benefits:

 

  1. I don’t have to worry about boxing and unboxing the configuration from the cache – bit of a performance boost.
  2. If I were to store the Configuration itself in cache I would either have a Dictionary in cache or multiple cache entries; one per Configuration object.  If I did the former and placed the Dictionary object in the cache then invalidation would remove the entire Dictionary therefore removing all Configuration objects.  If I went with the latter, well, it just seems sloppy to have multiple objects of the same type in separate cache spaces.  I guess that’s just me being picky.
 

Let’s check out the code.

 

using System;

using System.Collections.Generic;

using System.Web.Caching;

using System.Web.Configuration;

 

namespace IanSuttle.Util.Config

{

    public class WebConfigurationManager2

    {

        private static Dictionary<string, Configuration> _configs = new Dictionary<string, Configuration>();

 

        #region Indexers

 

        /// <summary>           

        /// Gets the <see cref="System.Configuration.Configuration"/> from the specified path.           

        /// </summary>           

        /// <value></value>           

        public Configuration this[string configPath]

        {

            get { return GetConfig(configPath); }

        }

 

        /// <summary>           

        /// Gets the <see cref="System.String"/> from the specified configPath web.config's appSettings key.           

        /// </summary>           

        /// <value></value>           

        public string this[string configPath, string key]

        {

            get { return GetConfig(configPath).AppSettings.Settings[key].Value; }

        }

 

        #endregion Indexers

 

        #region Public methods

 

        /// <summary>           

        /// Gets the web.config file located at the specified path.           

        /// </summary>           

        /// <param name="path">The directory where the web.config is located.</param>           

        /// <returns></returns>           

        public static Configuration GetConfig(string configPath)

        {

            //attempt to load from dictionary                 

            if (_configs.ContainsKey(configPath))

                return _configs[configPath];

 

            //attempt to load from disk and add to dictionary                 

            Configuration config = LoadConfig(configPath);

            if (config != null)

            {

                _configs.Add(configPath, config);

                return config;

            }

 

            //doesn't exist, error out                 

            throw new ConfigurationErrorsException("A web configuration file could not be found at " + configPath);

        }

 

        #endregion Public methods

 

        #region Private methods

 

        /// <summary>           

        /// Loads the web.config from the given path.  If a web.config is found it is stored in cache and monitored for chagnes.           

        /// </summary>           

        /// <param name="path">The directory where the web.config is located.</param>           

        /// <returns></returns>           

        private static Configuration LoadConfig(string configPath)

        {

            Configuration config = WebConfigurationManager.OpenWebConfiguration(configPath);

 

            //If the config was loaded we want to monitor it for changes (use cache)                 

            //I decided to not store the config in the cache itself for performance (boxing/unboxing from cache)                  

            //  and complexity (dictionary in cache, only wanting to expire a single config vs.                  

            //  the entire dictionary on invalidation).                 

            if (config != null)

            {

                string configFilePath = HttpContext.Current.Server.MapPath(configPath + "\\web.config");

                HttpContext.Current.Cache.Add("config_" + configPath, configPath, new CacheDependency(configFilePath), Cache.NoAbsoluteExpiration, new TimeSpan(0, 10, 0), CacheItemPriority.Normal, new CacheItemRemovedCallback(ConfigCacheRemoved));

            }

            return config;

        }

 

        /// <summary>           

        /// Called when a configuration cache item is invalidated.           

        /// </summary>           

        /// <param name="name">The name of the cache item.</param>           

        /// <param name="value">The value of the cache item.</param>           

        /// <param name="reason">The reason the cache was invalidated.</param>           

        private static void ConfigCacheRemoved(string name, object value, CacheItemRemovedReason reason)

        {

            //if the item exists in the dictionary, remove it because it changed                 

            if (_configs.ContainsKey(value.ToString()))

                _configs.Remove(value.ToString());

        }

 

        #endregion Private methods

    }

}

 

 

You’ll notice I’ve added a couple of ease of use enhancements including indexers which load configurations on demand if they don’t exist.  One of the indexers also provides a shortcut for obtaining an appSettings value.  You don’t have to use these indexers and if you wanted to access other sections such as connectionStrings you could do that directly through the Configuration object which can be obtained through this class as well.

 

Have you encountered a requirement like this?  If so, how did you address it?  I’d also love to hear any feedback you may have regarding my approach.

 

kick it on DotNetKicks.com
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

About Me

I'm Ian Suttle and I work for IGN Entertainment, a division of Fox Interactive Media.

Recent posts