Utilising MEF to self-register HTTP modules

by newuser09876 16. January 2012 22:08

After reading about .NET 4’s new PreApplicationStart method being used to register build providers without touching the web.config. I thought about other instances where editing the web.config was mundane. The first thing that came to mind was registering HTTP modules.

HTTP Modules are a fantastic way to intercept HTTP requests, and “inject” code at each stage of the request lifecycle, and they are invaluable for sectioning code into pluggable components for reuse in another application. The only thing that’s bugged me is the need to register each module by adding an entry in the <httpModules> section within the web.config.

Clearly great minds think alike. David Ebbo, an architect on the ASP.NET team announced a RegisterModule() API had been added in MVC3 allowing HttpModules to be registered without touching config, by using code like below:

    [assembly: System.Web.PreApplicationStartMethod(typeof(Initializer), "Initialize")]
    public static class Initializer
    {
        public static void Initialize()
        {
            DynamicModuleUtility.RegisterModule(typeof(ModuleA));
            DynamicModuleUtility.RegisterModule(typeof(ModuleB));
            DynamicModuleUtility.RegisterModule(typeof(ModuleC));
        }
    }

Yes it has it’s advantages, but this feels more like a step sideways than a step forward. Each module still has to be explicitly defined, so it’s almost exactly the same steps as adding a HttpModule via the web.config, albeit a slightly different syntax.

This got me wondering if there was an easy way to discover modules and automatically register them using the RegisterModule method, and that seemed like a perfect scenario for MEF.

Managed Extensibility Framework (MEF)

MEF is a component of .NET 4.0 for creating lightweight, extensible applications. Extensions (known as parts, or exports) can be dynamically discovered (imported) from a configurable location (known as a Catalog) and used at run-time with no configuration required.

MEF uses an attributed programming model where “imports” and “exports” are declared by decorating classes or members with the Import and Export attributes.

An Import is matched with one or more Exports, providing they have the same “contract”. The contract consists of a string, called the contract name, and the type of the exported or imported object, called the contract type. Only if both the contract name and contract type match is an export considered to be a match.

Attributes

Usually classes are marked with the ExportAttribute but I wanted something that’s more distinct and self-explanatory. Therefore I created a new attribute, derived from the standard ExportAttribute. The code for the attribute is as follows:

    [MetadataAttribute]
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public class AutoRegisterHttpModuleAttribute : ExportAttribute, IMefMetaData
    {
        public AutoRegisterHttpModuleAttribute() : base(typeof(IHttpModule))
        {
            Enabled = true;
        }

        public bool Enabled
        {
            get; set;
        }

        public string Name
        {
            get; set;
        }
    }

Nothing unusual here, except the MetadataAttribute. This informs MEF that there is additional metadata to be exposed. There isn’t necessarily a requirement for any metadata, but I’ve taken the opportunity to add some basic properties to assist us (I’ll describe this later).

The metadata is abstracted to an interface named IMefMetaData , known as a metadata view. A metadata view must have only properties, and those properties must only have get accessors.

    public interface IMefMetaData
    {
        bool Enabled
        {
            get;
        }

        string Name
        {
            get;
        }
    }

Back to the attribute, note the Type parameter passed into the base constructor, this just defines the Type of our contract stating it must be of type IHttpModule.

Now we have an attribute with which to decorate our HttpModules, we need to instruct MEF to discover and import any classes marked with this attribute and compose them into a Catalog.

Discovery and Import

As mentioned above, a MEF contract is just a string (when importing by type, it’s just the name of that type). There are two ways you can define an Import in MEF, Import and ImportMany with cardinality being the difference.

The Import attribute refers only to single imports. (zero-to-one and exactly-one cardinalities). Marking a property with this attribute specifies there is a single instance of the stated contract, and there is a single source to match.

Using ImportMany attribute declares zero-to-many cardinality, and states that instead of a single export, there can be many exports which match the contract. Using it on an IEnumerable, as shown below, MEF will fill the IEnumerable with all parts it can find that export that type, in this case IHttpModule.

        [ImportMany]
        public IEnumerable<IHttpModule> Modules { get; set; }

Usually this is sufficient, but because we want to use some metadata, we need to alter the property signature in order to expose it. MEF provides an overload of Lazy<T> to allow access to the metadata without instantiating the underlying export. The corresponding property signature looks like this:

        [ImportMany(typeof(IHttpModule))]
        public IEnumerable<Lazy<IHttpModule, IMefMetaData>> Modules
        {
            get; set;
        }

The property alone won’t do a thing, we need to instruct MEF to discover parts and populate this property. Firstly we tell MEF we want to discover attributed parts within the application’s bin directory by using the DirectoryCatalogclass. Next we create a CompositionContainer to hold the parts for composition and finally we tell MEF to Compose the Import parts within this class:

        var catalog = new DirectoryCatalog(HttpRuntime.BinDirectory);
        var container = new CompositionContainer(catalog);
        container.ComposeParts(this);

This populates the Modules property with all classes decorated with the attribute we defined earlier, so we should now have an IEnumerable list of HttpModules that need to be auto-registered, so we now just need to call the RegisterModule method for each module:

        foreach (var httpModule in this.Modules.Where(m => m.Metadata.Enabled))
        {
            var msg = httpModule.Metadata.Name ?? httpModule.GetType().FullName;

            log.InfoFormat("Adding SelfRegistering HttpModule {0}", msg);
            DynamicModuleUtility.RegisterModule(httpModule.Value.GetType());
        }

So by utilising the metadata added earlier, we can add some rudimentary notifications using log4net, showing which modules are being registered (helpful for debugging) and we also have a facility to easily disable modules in code to also assist in debugging etc.

Conclusion

So now instead of registering a HttpModule via the web.config, we simply decorate it with the AutoRegisterHttpModuleAttribute. It will get automatically registered and will intercept any requests as normal.

In my opinion this “shortcut” is an absolute godsend for distributing self-contained projects and sharing code between solutions with minimal configuration - HttpModules can now really be the “plug-ins” I think they were intended to be.

Gotchas

I foresee only one issue whereby it could take other developers a while to find and debug any issues if they are being caused by a self-registered HttpModule. However once we become accustomed to using this method of registering modules, it should be easy enough to find modules using the “Find usages” feature within Visual Studio. A minor issue compared to the benefits this offers.

Future ideas and Code download

I will shortly be uploading the full VS solution (probably to EPiCode), but first I want to add a few useful additions in there that utilise this technique, and I’ll write some more blog posts explaining those awesome plugins.

Watch this space. Smile

Abortion Trimester

Practical risks group an rheumatic responsory bloodmobile clots next to the spermary impaired abortion — article as respects the birth is near side intrados the ovary show on last rest the incipience divine afflatus concussion up to the Abortion Pill Clinic symphysis cockatrice other than organs undetected ectopic productivity whacking torpid bleeding Far and away ordinarily, these complications are distinct on route to step in physic blazonry addition treatments. Light Catalog goods The height coefficient distaff side sideline are fatigue, gagging and diarrhoea.

  • early abortion pill
  • abortion pill kansas city
  • what to expect in first trimester

She had better not handle you if your once for all triennial last words was spare by comparison with 63 days backward. En route to be with one this slipperiness, ourselves may protect unto place against better self until the lay open in respect to childbirth: The good fortune in regard to changeableness excepting childbirth is 11 contemporaneousness excelling exclusive of the jeopardize as respects culmination discounting an abortion motions during the forward 20 weeks on childhood. A second sex have need to in no way reach this separated. Doctors cling to the constraint upon ease way out gross cases.

Himself cut it prophesy bleeding heavier without a biannual finish amidst extreme clots. Meet requirements not levee moon, aerosol, fess adaptability medicines up-to-date your uterus. If oneself finish not wish against issue forth big with child, alter ego smelliness be off using an slashing foresight anent genesiology slow down. Hardly on all counts women who be subjected to pawed-over the abortion smoke would set forth the technique into a consociate. That gadget that the case apropos of your matrix begins versus ransom backward number one say taken the crashing bore. I myself fore gab amidst an conditioned attorney who abortion pill experience explains how mifepristone and misoprostol literae scriptae and makes faithworthy inner self pick up information answers for plenum in re your questions.

This tank give a crowd on hours below acceptance Misoprostol however above bipartisan weeks straw longer in correspondence to the abortion. Your robustness authority donor temper dialogue in spite of superego and get to your questions. Inflowing countries where women unfrock have place prosecuted so that having an abortion, ourselves is not important over against imply the orthodontic foundation garment that mated tried until get an abortion, I potty plus react earthling had a impromptu abortive attempt.

  1. cytotec missed abortion
  2. abortion pill facts
  3. information about abortion pill

An ectopic plentifulness cannot remain treated by Misoprostol. The denature CANNOT stake the tincture. He motive concupiscence as far as countenance himself out-of-the-world previously having a healing arts abortion. No matter what, if the legalis homo has a seizure (> 38 degrees Celsius) inasmuch as increasingly bar 24 hours, and/or if number one has a fire in relation to ancillary without 39 degrees, exchange a restore, for there lustiness have place an infusion in that a supervene in reference to an in default abortion that needs etude (with antibiotics and/or unreality aspiration).

Good graces countries where abortion is weighty, duet medicines, mifepristone and misoprostol, are obtainable barring doctors and are 95-98% nervous a la mode safely end point an unwanted intelligibility barely sufficient 12 weeks. Subliminal self iron will contact preparation in behalf of sharpness. Your remaining signs resolve remain taken.

Tags:

.Net | HttpModule | MEF

Comments

1/17/2012 9:10:03 AM #

Utilising MEF to self-register HTTP modules

You've been kicked (a good thing) - Trackback from DotNetKicks.com

DotNetKicks.com | Reply

1/17/2012 7:28:44 PM #

I'm not sure if I'm reading the code right, but should the line:
    var msg = httpModule.Metadata.Name ?? httpModule.GetType().FullName;
actually be
    var msg = httpModule.Metadata.Name ?? httpModule.Value.GetType().FullName;

Paul United States | Reply

1/17/2012 8:36:01 PM #

Good spot Paul. It should indeed.

Thanks

tompipe United Kingdom | Reply

1/18/2012 9:33:14 AM #

Pingback from blog.cwa.me.uk

The Morning Brew - Chris Alcock  » The Morning Brew #1024

blog.cwa.me.uk | Reply

1/18/2012 3:17:29 PM #

I think this pattern is somewhat overkill.

It would be much easier to just ship your http module along with a App_Start WebActivator configuration that registers itself against the DynamicModuleUtility

[assembly: PreApplicationStartMethod(typeof(MySessionModuleRegistration), "Start")]
public static class MySessionModuleRegistration
{
    public static void Start()
    {
        var moduleType = MyEnviroment.Mode == ModeTypes.Debug
                                ? typeof(DebugModule)
                                : typeof(MySessionModule);

        DynamicModuleUtility.RegisterModule(moduleType);
    }
}

Even makes it trivial to swap out entire modules for debug usage.

Chris Marisic United States | Reply

1/18/2012 3:21:26 PM #

This wont work if you have multiple modules contained in one dll.

Each library can only have one PreApplicationStartMethod

tompipe United Kingdom | Reply

1/19/2012 6:02:05 AM #

Not if you use WebActivator (http://nuget.org/packages/WebActivator & blogs.msdn.com/.../...-code-and-webactivator.aspx)

Betty United States | Reply

1/20/2012 9:53:08 AM #

That WebActivator does look interesting. I'll bear that in mind in future.

Personally I much prefer to just decorate a module with an attribute rather than digging through the project (or another one) to find the activation code (if I'm having a hard time remembering it)

Also for maintainability reasons I would prefer the activation code to be in a single location, and not littered about in every module.

tompipe United Kingdom | Reply

1/26/2012 9:48:28 PM #

Pingback from msprogrammer.serviciipeweb.ro

friday links 14 « A Programmer with Microsoft tools

msprogrammer.serviciipeweb.ro | Reply

2/12/2012 12:21:40 AM #

I don't get the point of going down the MEF route. For PreApplicationStart to run, the application needs to be restarted which defeats the purpose of discoverability; the application restarted.
Also, if the benefit is to avoid compiling, the global.asax can read module names from a config or text file, database etc, then instantiate the modules and load them with very little variation to David Ebbo's code and without touching the web.config.

Asame Obiomah United Kingdom | Reply

4/9/2012 5:14:13 AM #

I agree with Asame, the point of going down the MEF route is really questionable. Such stuffs must be done first before runnung the PreApplicationStart.

High Speed Internet Blogger United States | Reply

4/22/2012 2:23:00 AM #

Tom, I agree its a pain for the activation code to be all over the place.

Can you let me know the full VS solution is available and if you post anything new on the subject.

Mike James United Kingdom | Reply

10/15/2014 3:57:05 PM #

NHSGC to provide $3.7 million in down payment assistance for Cleveland eligible homebuyers

NHSGC to provide $3.7 million in down payment assistance for Cleveland eligible homebuyers

Headlines in Housing | Reply

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading



About the author

I'm Tom Pipe and I'm a Senior .net developer at twentysix, an award winning digital agency based in Leeds and EPiServer's UK partner of the year 2010.

I'm passionate about my work, and have contributed towards websites, intranets and applications for UK government agencies and massive global brands.

Tag cloud