July 2010
M T W T F S S
« Dec    
 1234
567891011
12131415161718
19202122232425
262728293031  

Pages

  • 29Dec

    While I am thoroughly enjoying MVC and autofac, I feel there is something missing when it comes to handling areas. I found areas an excellent idea for segregating larger web apps into manageable chunks when using MonoRail a few years ago. I was unsure of how to incorporate them into MVC until I found Phil Haack’s blog entryand subsequent followup by Steve Sanderson.

    This made for a great start. One large problem: controller names had to be unique across every area. At first I resigned myself to having *really* long class names. But then I came to my senses and started hunting through the code for autofac to figure out how to change this. After a few hours of trial and error I figured out what changes needed to be made.

    Create a new AreaAwareControllerFactory that extends the built-in factory:

        public class AreaAwareControllerFactory : AutofacControllerFactory
        {
            public AreaAwareControllerFactory(IContainerProvider containerProvider)
                : base(containerProvider)
            {
            }
    
            public AreaAwareControllerFactory(IContainerProvider containerProvider,
                                              IControllerIdentificationStrategy controllerIdentificationStrategy)
                : base(containerProvider, controllerIdentificationStrategy)
            {
            }
    
            public override IController CreateController(RequestContext context, string controllerName)
            {
                var area = (string)context.RouteData.Values["area"];
    
                if (area != null)
                {
                    controllerName = area + "." + controllerName;
                }
    
                return base.CreateController(context, controllerName);
            }
        }

    This version relies on a custom attribute to specify an area and it must match the area routing key:

        [AttributeUsage(AttributeTargets.Class)]
        public class AreaAttribute : Attribute
        {
            public string Name { get; set; }
    
            public AreaAttribute(string name)
            {
                Name = name;
            }
        }
    

    The next step is to create an area aware identification strategy:

        public class AreaAwareControllerIdentificationStrategy : IControllerIdentificationStrategy
        {
            private const string Prefix = "controller.";
            private const string TypeNameSuffix = "Controller";
    
            public Service ServiceForControllerName(string controllerName)
            {
                if (controllerName == null)
                {
                    throw new ArgumentNullException("controllerName");
                }
    
                if (controllerName == "")
                {
                    throw new ArgumentException("controllerName");
                }
    
                return new NamedService(Prefix + controllerName.ToLowerInvariant());
            }
    
            public Service ServiceForControllerType(Type controllerType)
            {
                // see if controller has Area attribute
                var attr = (from attribute in controllerType.GetCustomAttributes(typeof (AreaAttribute), true)
                            select attribute).Cast().FirstOrDefault();
    
                if (attr != null)
                {
                    return ServiceForControllerName(attr.Name + "." + controllerType.Name.Replace(TypeNameSuffix, ""));
                }
    
                return ServiceForControllerName(controllerType.Name.Replace(TypeNameSuffix, ""));
            }
        }

    The final step is to wire up the module and factory:

    private void RegisterContainer()
    {
        var builder = new ContainerBuilder();
    
        // register core modules
        builder.RegisterModule(new AutofacControllerModule(controllersAssembly)
           {
               IdentificationStrategy = new AreaAwareControllerIdentificationStrategy()
           });
    
        containerProvider = new ContainerProvider(builder.Build());
    
        ControllerBuilder.Current.SetControllerFactory(new AreaAwareControllerFactory(ContainerProvider));
    }
    

    I also made a minor change to where views are located. Replace the original functions in AreaViewEngine with the following:

        public class AreaAwareViewEngine : WebFormViewEngine
        {
            private static string _appBase;
    
            public AreaAwareViewEngine(string appBase)
            {
                _appBase = appBase.Trim('/', '~');
            }
    
            public AreaAwareViewEngine()
                : base()
            {
                _appBase = "~";
    
                ViewLocationFormats = new[] {
                                                _appBase + "/{0}.aspx",
                                                _appBase + "/{0}.ascx",
                                                _appBase + "/Views/{1}/{0}.aspx",
                                                _appBase + "/Views/{1}/{0}.ascx",
                                                _appBase + "/Views/Shared/{0}.aspx",
                                                _appBase + "/Views/Shared/{0}.ascx",
                                            };
    
                MasterLocationFormats = new[] {
                                                  _appBase + "/{0}.master",
                                                  _appBase + "/Shared/{0}.master",
                                                  _appBase + "/Views/{1}/{0}.master",
                                                  _appBase + "/Views/Shared/{0}.master",
                                              };
    
                PartialViewLocationFormats = ViewLocationFormats;
            }
    
            public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
            {
                ViewEngineResult areaResult = null;
    
                if (controllerContext.RouteData.Values.ContainsKey("area"))
                {
                    string areaPartialName = FormatViewName(controllerContext, partialViewName);
                    areaResult = base.FindPartialView(controllerContext, areaPartialName, useCache);
                    if (areaResult != null && areaResult.View != null)
                    {
                        return areaResult;
                    }
    
                    string sharedAreaPartialName = FormatAreaSharedViewName(controllerContext, partialViewName);
                    areaResult = base.FindPartialView(controllerContext, sharedAreaPartialName, useCache);
                    if (areaResult != null && areaResult.View != null)
                    {
                        return areaResult;
                    }
    
                    sharedAreaPartialName = FormatSharedViewName(controllerContext, partialViewName);
                    areaResult = base.FindPartialView(controllerContext, sharedAreaPartialName, useCache);
                    if (areaResult != null && areaResult.View != null)
                    {
                        return areaResult;
                    }
                }
    
                return base.FindPartialView(controllerContext, partialViewName, useCache);
            }
    
            public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
            {
                ViewEngineResult areaResult = null;
    
                if (controllerContext.RouteData.Values.ContainsKey("area"))
                {
                    string areaViewName = FormatViewName(controllerContext, viewName);
                    areaResult = base.FindView(controllerContext, areaViewName, masterName, useCache);
                    if (areaResult != null && areaResult.View != null)
                    {
                        return areaResult;
                    }
    
                    string sharedAreaViewName = FormatSharedViewName(controllerContext, viewName);
                    areaResult = base.FindView(controllerContext, sharedAreaViewName, masterName, useCache);
                    if (areaResult != null && areaResult.View != null)
                    {
                        return areaResult;
                    }
                }
    
                return base.FindView(controllerContext, viewName, masterName, useCache);
            }
    
            private static string FormatViewName(ControllerContext controllerContext, string viewName)
            {
                string controllerName = controllerContext.RouteData.GetRequiredString("controller");
    
                string area = controllerContext.RouteData.Values["area"].ToString();
                return "Views/" + area + "/" + controllerName + "/" + viewName;
            }
    
            private static string FormatSharedViewName(ControllerContext controllerContext, string viewName)
            {
                string area = controllerContext.RouteData.Values["area"].ToString();
                return "Views/Shared/" + area + "/" + viewName;
            }
    
            private static string FormatAreaSharedViewName(ControllerContext controllerContext, string viewName)
            {
                string area = controllerContext.RouteData.Values["area"].ToString();
                return "Views/" + area + "/Shared/" + viewName;
            }
    
        }
    

    You may be wondering why I don’t pass in the new identifying strategy to the factory and that’s because of a limitation in the way IControllerIdentificationStrategy works. This interface doesn’t allow you to consider RouteData when generating the service names. This leave us with having to subclass the factory. In the future it would be nice to see a more configurable way to discover controller names.

    ASP.NET MVC and autofac amaze me at every turn with their extensibility.

  • 28Dec

    http://www.intowindows.com/how-to-enable-hibernate-option-in-windows-7/

  • 01Dec

    http://concurrentdevelopment.wordpress.com/2009/04/09/visual-studio-hangs-on-debug/

  • 04Aug

    http://www.scriptasylum.com/rc_speed/_oil_mixer.html

  • 13Jul

    http://progressiverc.com/LiFePO4.html

  • 17Jun

    dseditgroup -o edit -p -a admin -t group _lpadmin

  • 13May

    While I am thoroughly enjoying MVC and autofac, I feel there is something missing when it comes to handling areas.  I found areas an excellent idea for segregating larger web apps into manageable chunks when using MonoRail a few years ago.  I was unsure of how to incorporate them into MVC until I found Phil Haack’s blog entryand subsequent followup by Steve Sanderson.

    This made for a great start.  One large problem: controller names had to be unique across every area.  At first I resigned myself to having *really* long class names.  But then I came to my senses and started hunting through the code for autofac to figure out how to change this.  After a few hours of trial and error I figured out what changes needed to be made.

    Create a new AreaAwareControllerFactory that extends the built-in factory:

    public class AreaAwareControllerFactory : AutofacControllerFactory
    {
    	public AreaAwareControllerFactory(IContainerProvider containerProvider)
    	    : base(containerProvider)
    	{
    	}
    
    	public AreaAwareControllerFactory(IContainerProvider containerProvider,
    	                                  IControllerIdentificationStrategy controllerIdentificationStrategy)
    	    : base(containerProvider, controllerIdentificationStrategy)
    	{
    	}
    
    	public override IController CreateController(RequestContext context, string controllerName)
    	{
    	    var area = (string)context.RouteData.Values["area"];
    
    	    if (area != null)
    	    {
    	        controllerName = area + "." + controllerName;
    	    }
    
    	    return base.CreateController(context, controllerName);
    	}
    }

    The next step is to create an area aware identification strategy:

    public class AreaAwareControllerIdentificationStrategy : IControllerIdentificationStrategy
    {
    	private IList areaRoots;
    
    	private const string Prefix = "controller.";
    	private const string TypeNameSuffix = "Controller";
    
    	public AreaAwareControllerIdentificationStrategy(params string[] areaRoots)
    	{
    	    this.areaRoots = new List();
    	    foreach (string area in areaRoots)
    	    {
    	        if (!area.EndsWith("."))
    	        {
    	            this.areaRoots.Add(area + ".");
    	        }
    	        else
    	        {
    	            this.areaRoots.Add(area);
    	        }
    	    }
    	}
    
    	public Service ServiceForControllerName(string controllerName)
    	{
    	    if (controllerName == null)
    	    {
    	        throw new ArgumentNullException("controllerName");
    	    }
    
    	    if (controllerName == "")
    	    {
    	        throw new ArgumentException("controllerName");
    	    }
    
    	    return new NamedService(Prefix + controllerName.ToLowerInvariant());
    	}
    
    	public Service ServiceForControllerType(Type controllerType)
    	{
    	    string serviceName = controllerType.FullName;
    
    	    foreach(string root in areaRoots)
    	    {
    	        if (serviceName.Contains(root))
    	        {
    	            serviceName = controllerType.FullName.Replace(root, "").Replace(TypeNameSuffix, "");
    	            return ServiceForControllerName(serviceName);
    	        }
    	    }
    
    	    return ServiceForControllerName(controllerType.Name.Replace(TypeNameSuffix, ""));
    	}
    }

    The final step is to wire up the module and factory:

    private void RegisterContainer()
    {
        var builder = new ContainerBuilder();
        builder.RegisterModule(new AutofacControllerModule(Assembly.GetExecutingAssembly())
                                   {
                                       IdentificationStrategy =
                                           new AreaAwareControllerIdentificationStrategy("ThirdFamily.Web.Controllers")
                                   });
    
        containerProvider = new ContainerProvider(builder.Build());
    
        ControllerBuilder.Current.SetControllerFactory(new AreaAwareControllerFactory(ContainerProvider));
    }
    

    I also made a minor change to where views are located. Replace the original functions in AreaViewEngine with the following:

    private static string FormatViewName(ControllerContext controllerContext, string viewName)
    {
        string controllerName = controllerContext.RouteData.GetRequiredString("controller");
    
        string area = controllerContext.RouteData.Values["area"].ToString();
        return "Views/" + area + "/" + controllerName + "/" + viewName;
    }
    
    private static string FormatSharedViewName(ControllerContext controllerContext, string viewName)
    {
        string area = controllerContext.RouteData.Values["area"].ToString();
        return "Views/Shared/" + area + "/" + viewName;
    }
    

    You may be wondering why I don’t pass in the new identifying strategy to the factory and that’s because of a limitation in the way IControllerIdentificationStrategy works. This interface doesn’t allow you to consider RouteData when generating the service names. This leave us with having to subclass the factory. In the future it would be nice to see a more configurable way to discover controller names.

    ASP.NET MVC and autofac amaze me at every turn with their extensibility.

    Tags:

  • 26Apr

    To check which needle is in your motor remove the air filter and look down the carb throat while slowly opening the throttle slide. If you have the old short needle the LSN needle will pull out of the spray bar before or at half throttle.
    If you have the new intermediate needle (Gen5 motors only) the needle will only pull out of the spray bar towards full throttle.
    If you have the long LSN (most likely in your case) the LSN remains in the spray bar right through the throttle range and is still in the spray bar at full throttle.

    OK – for the long LSN set:

    HSN to half a turn in from flush (doesn’t seem much but this is correct. It’s to do with the needle staying in the spray bar at full throttle).
    LSN to 2.5 – 3 turns in from flush
    I have the long LSN in my 5 Port and have HSN at .5 in from flush and the LSN at 2.75 turns in from flush. Perfect for my set up.

    For short LSN set:

    HSN 2 – 2.5 turns in from flush
    LSN 2.5 – turns in from flush

    For the intermediate needle:

    HSN 1.25 – 1.5 turns in from flush
    LSN 2.5 – 3 + turns in from flush
    I have the newer intermediate needle in my 7 Port, and have HSN at 1.25 turns in and LSN at 4.25 turns in with the fuel and pipe I am running, and motor is performing real strong.

  • 26Apr

    http://www.horizonhobby.com/Products/Default.aspx?ProdID=RRP9402

  • 20Apr

    base setting for the 3 port sport per the maual. (should be conservative) HSN 3.25 turns out from fully turned in, and the LSN 1 turn in from flush.

« Previous Entries