Logo

Maarten Balliauw {blog}

ASP.NET, ASP.NET MVC, Windows Azure, PHP, ...

About the author

Maarten Balliauw is currently employed as .NET Technical Consultant at RealDolmen. His interests are mainly web applications developed in ASP.NET (C#) or PHP and the Windows Azure cloud platform.
More about me More about me
Send mail E-mail me


ASP.NET MVC Quickly Pro NuGet Subscribe to my RSS feed Follow me on Twitter! View Maarten Balliauw's profile on LinkedIn
Maarten Balliauw - MVP - Most Valuable Professional
Maarten Balliauw - ASPInsider

Search

Latest Twitter

    Follow me on Twitter...

    Archive

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

    © Copyright Maarten Balliauw 2012


    Community Day 2011 - Fun with ASP.NET MVC, MEF and NuGet

    To start the blog post: AWESOME! That’s what I have to say about the latest edition of Community Day 2011. I had the privilege of doing a session on ASP.NET MVC 3, MEF and NuGet, and as promised to the audience: here are the slides. For those who want to see the session, the recording can be found on Channel 9 from a previous event.

    “Fun with ASP.NET MVC3, MEF and NuGet”
    Community Day 2011, Mechelen, Belgium, 23/06/2011

    Abstract: “So you have a team of developers… And a nice architecture to build on… How about making that architecture easy for everyone and getting developers up to speed quickly? Learn all about integrating the managed extensibility framework (MEF) and ASP.NET MVC with some NuGet sauce for creating loosely coupled, easy to use architectures that anyone can grasp.

    Here’s the slides:

    Here’s the example code: Fun with ASP.NET MVC 3 MEF - CommunityDay 2011.zip (6.79 mb)

    Some resources:


    Categories: ASP.NET | C# | General | ICT | MEF | Presentations

    Comments (7) -

    Jan Belgium |

    Tuesday, July 19, 2011 4:13 PM

    Jan

    Hi,

    Ik heb wat gespeeld met je demo applicatie. Maar er is iets zeer bizar, iets wat ik niet kan vatten. In het project Initech.Components.Web.Mvc.Authentication zitten de views voor de Account controller. Als ik de account views gewoon uit het project haal blijft alles mooi werken. Als ik dan een nieuwe view maak en deze probeer aan te roepen vanuit de controller, dan komt er steeds de error dat de view niet is te vinden. Kan jij mij hier verder mee helpen wat hier het probleem is of hoe dit alles werkt ?

    Bedankt

    maartenba Belgium |

    Thursday, July 28, 2011 7:30 AM

    maartenba

    Mail me anders even

    Dadv France |

    Wednesday, July 27, 2011 4:47 PM

    Dadv

    Bonjour,

    J'ai suivi avec attention votre intervention au MIX 11 et j'ai voulu essayer certaines choses avec les sources fournies.

    En premier lieu je cherchais à faire en sorte que MefContrib puisse charger une dll autre part que dans bin, j'ai donc modifié le fichier AppStart_MefContribMVC3.cs comme suit :

    public static class AppStart_MefContribMVC3
        {
            public static void Start()
            {
                // Register the CompositionContainerLifetimeHttpModule HttpModule.
                // This makes sure everything is cleaned up correctly after each request.
                CompositionContainerLifetimeHttpModule.Register();

                // Create MEF catalog based on the contents of ~/bin.
                //
                // Note that any class in the referenced assemblies implementing in "IController"
                // is automatically exported to MEF. There is no need for explicit [Export] attributes
                // on ASP.NET MVC controllers. When implementing multiple constructors ensure that
                // there is one constructor marked with the [ImportingConstructor] attribute.
                var catalog = new AggregateCatalog(
                    new DirectoryCatalog(System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Plugins")),
                    new DirectoryCatalog("bin"),
                    new ConventionCatalog(new MvcApplicationRegistry())); // Note: add your own (convention)catalogs here if needed.


                // Tell MVC3 to use MEF as its dependency resolver.
                var dependencyResolver = new CompositionDependencyResolver(catalog);
                DependencyResolver.SetResolver(dependencyResolver);

                // Tell MVC3 to resolve dependencies in controllers
                ControllerBuilder.Current.SetControllerFactory(
                    new DefaultControllerFactory(
                        new CompositionControllerActivator(dependencyResolver)));

                // Tell MVC3 to resolve dependencies in filters
                FilterProviders.Providers.Remove(FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider));
                FilterProviders.Providers.Add(new CompositionFilterAttributeFilterProvider(dependencyResolver));

                // Tell MVC3 to resolve dependencies in model validators
                ModelValidatorProviders.Providers.Remove(ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().Single());
                ModelValidatorProviders.Providers.Add(
                    new CompositionDataAnnotationsModelValidatorProvider(dependencyResolver));

                // Tell MVC3 to resolve model binders through MEF. Note that a model binder should be decorated
                // with [ModelBinderExport].
                ModelBinderProviders.BinderProviders.Add(
                    new CompositionModelBinderProvider(dependencyResolver));
            }
        }

    Sans avoir le succès escompté.

    Je me suis donc orienté vers une implémentation de PartRegistry :

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Web;
    using MefContrib.Hosting.Conventions.Configuration;
    using MefContrib.Hosting.Conventions;
    using System.Web.Mvc;
    using MefContrib.Web.Mvc;

    namespace MefLocalTests.Codes
    {
        public class PluginMvcApplicationRegistry : PartRegistry
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="MvcApplicationRegistry"/> class.
            /// </summary>
            public PluginMvcApplicationRegistry()
            {
                Scan(x =>
                {
                    x.Assembly(Assembly.GetExecutingAssembly());
                    x.Directory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins"));
                    x.Directory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"));
                });

                Part()
                    .ForTypesAssignableFrom<IController>()
                    .MakeNonShared()
                    .AddMetadata(new PartCreationScopeAttribute(PartCreationScope.Default))
                    .ExportAs<IController>()
                    .Export()
                    .Imports(x =>
                    {
                        x.Import().Members(
                            m => new[] { m.GetConstructors().FirstOrDefault(c => c.GetCustomAttributes(typeof(ImportingConstructorAttribute), false).Length > 0) ?? m.GetGreediestConstructor() });
                        x.Import().Members(
                            m => m.GetMembers().Where(mbr => mbr.GetCustomAttributes(typeof(ImportAttribute), false).Length > 0).ToArray());
                    });
            }
        }
    }

    et


    public static class AppStart_MefContribMVC3
        {
            public static void Start()
            {
                // Register the CompositionContainerLifetimeHttpModule HttpModule.
                // This makes sure everything is cleaned up correctly after each request.
                CompositionContainerLifetimeHttpModule.Register();

                // Create MEF catalog based on the contents of ~/bin.
                //
                // Note that any class in the referenced assemblies implementing in "IController"
                // is automatically exported to MEF. There is no need for explicit [Export] attributes
                // on ASP.NET MVC controllers. When implementing multiple constructors ensure that
                // there is one constructor marked with the [ImportingConstructor] attribute.
                var catalog = new AggregateCatalog(
                    new DirectoryCatalog("bin"),
                    new ConventionCatalog(new PluginMvcApplicationRegistry())); // Note: add your own (convention)catalogs here if needed.


                // Tell MVC3 to use MEF as its dependency resolver.
                var dependencyResolver = new CompositionDependencyResolver(catalog);
                DependencyResolver.SetResolver(dependencyResolver);

                // Tell MVC3 to resolve dependencies in controllers
                ControllerBuilder.Current.SetControllerFactory(
                    new DefaultControllerFactory(
                        new CompositionControllerActivator(dependencyResolver)));

                // Tell MVC3 to resolve dependencies in filters
                FilterProviders.Providers.Remove(FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider));
                FilterProviders.Providers.Add(new CompositionFilterAttributeFilterProvider(dependencyResolver));

                // Tell MVC3 to resolve dependencies in model validators
                ModelValidatorProviders.Providers.Remove(ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().Single());
                ModelValidatorProviders.Providers.Add(
                    new CompositionDataAnnotationsModelValidatorProvider(dependencyResolver));

                // Tell MVC3 to resolve model binders through MEF. Note that a model binder should be decorated
                // with [ModelBinderExport].
                ModelBinderProviders.BinderProviders.Add(
                    new CompositionModelBinderProvider(dependencyResolver));
            }
        }

    Mais là encore, aucun succès.

    Par contre si je met ma dll dans le bin, tout fonctionne parfaitement.

    Pouvez vous m'indiquer la marche à suivre pour externaliser le dossier contenant les dll d'export svp ?

    D'avance merci,

    Dadv


    ----

    Hi,

    I want to make MefContrib load a external Dll in an other directory than bin, so i changed the AppStart_MefContribMVC3.cs file :

    public static class AppStart_MefContribMVC3
        {
            public static void Start()
            {
                // Register the CompositionContainerLifetimeHttpModule HttpModule.
                // This makes sure everything is cleaned up correctly after each request.
                CompositionContainerLifetimeHttpModule.Register();

                // Create MEF catalog based on the contents of ~/bin.
                //
                // Note that any class in the referenced assemblies implementing in "IController"
                // is automatically exported to MEF. There is no need for explicit [Export] attributes
                // on ASP.NET MVC controllers. When implementing multiple constructors ensure that
                // there is one constructor marked with the [ImportingConstructor] attribute.
                var catalog = new AggregateCatalog(
                   new DirectoryCatalog(System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Plugins")),
                    new DirectoryCatalog("bin"),
                    new ConventionCatalog(new MvcApplicationRegistry())); // Note: add your own (convention)catalogs here if needed.


                // Tell MVC3 to use MEF as its dependency resolver.
                var dependencyResolver = new CompositionDependencyResolver(catalog);
                DependencyResolver.SetResolver(dependencyResolver);

                // Tell MVC3 to resolve dependencies in controllers
                ControllerBuilder.Current.SetControllerFactory(
                    new DefaultControllerFactory(
                        new CompositionControllerActivator(dependencyResolver)));

                // Tell MVC3 to resolve dependencies in filters
                FilterProviders.Providers.Remove(FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider));
                FilterProviders.Providers.Add(new CompositionFilterAttributeFilterProvider(dependencyResolver));

                // Tell MVC3 to resolve dependencies in model validators
                ModelValidatorProviders.Providers.Remove(ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().Single());
                ModelValidatorProviders.Providers.Add(
                    new CompositionDataAnnotationsModelValidatorProvider(dependencyResolver));

                // Tell MVC3 to resolve model binders through MEF. Note that a model binder should be decorated
                // with [ModelBinderExport].
                ModelBinderProviders.BinderProviders.Add(
                    new CompositionModelBinderProvider(dependencyResolver));
            }
        }

    No success

    So i try to implement a PartRegistry :

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Web;
    using MefContrib.Hosting.Conventions.Configuration;
    using MefContrib.Hosting.Conventions;
    using System.Web.Mvc;
    using MefContrib.Web.Mvc;

    namespace MefLocalTests.Codes
    {
        public class PluginMvcApplicationRegistry : PartRegistry
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="MvcApplicationRegistry"/> class.
            /// </summary>
            public PluginMvcApplicationRegistry()
            {
                Scan(x =>
                {
                    x.Assembly(Assembly.GetExecutingAssembly());
                    x.Directory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins"));
                    x.Directory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"));
                });

                Part()
                    .ForTypesAssignableFrom<IController>()
                    .MakeNonShared()
                    .AddMetadata(new PartCreationScopeAttribute(PartCreationScope.Default))
                    .ExportAs<IController>()
                    .Export()
                    .Imports(x =>
                    {
                        x.Import().Members(
                            m => new[] { m.GetConstructors().FirstOrDefault(c => c.GetCustomAttributes(typeof(ImportingConstructorAttribute), false).Length > 0) ?? m.GetGreediestConstructor() });
                        x.Import().Members(
                            m => m.GetMembers().Where(mbr => mbr.GetCustomAttributes(typeof(ImportAttribute), false).Length > 0).ToArray());
                    });
            }
        }
    }

    And


    public static class AppStart_MefContribMVC3
        {
            public static void Start()
            {
                // Register the CompositionContainerLifetimeHttpModule HttpModule.
                // This makes sure everything is cleaned up correctly after each request.
                CompositionContainerLifetimeHttpModule.Register();

                // Create MEF catalog based on the contents of ~/bin.
                //
                // Note that any class in the referenced assemblies implementing in "IController"
                // is automatically exported to MEF. There is no need for explicit [Export] attributes
                // on ASP.NET MVC controllers. When implementing multiple constructors ensure that
                // there is one constructor marked with the [ImportingConstructor] attribute.
                var catalog = new AggregateCatalog(
                    new DirectoryCatalog("bin"),
                    new ConventionCatalog(new PluginMvcApplicationRegistry())); // Note: add your own (convention)catalogs here if needed.


                // Tell MVC3 to use MEF as its dependency resolver.
                var dependencyResolver = new CompositionDependencyResolver(catalog);
                DependencyResolver.SetResolver(dependencyResolver);

                // Tell MVC3 to resolve dependencies in controllers
                ControllerBuilder.Current.SetControllerFactory(
                    new DefaultControllerFactory(
                        new CompositionControllerActivator(dependencyResolver)));

                // Tell MVC3 to resolve dependencies in filters
                FilterProviders.Providers.Remove(FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider));
                FilterProviders.Providers.Add(new CompositionFilterAttributeFilterProvider(dependencyResolver));

                // Tell MVC3 to resolve dependencies in model validators
                ModelValidatorProviders.Providers.Remove(ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().Single());
                ModelValidatorProviders.Providers.Add(
                    new CompositionDataAnnotationsModelValidatorProvider(dependencyResolver));

                // Tell MVC3 to resolve model binders through MEF. Note that a model binder should be decorated
                // with [ModelBinderExport].
                ModelBinderProviders.BinderProviders.Add(
                    new CompositionModelBinderProvider(dependencyResolver));
            }
        }

    No more success

    But if i put the Dll in the bin folder, everything ok

    Could you tell me where is my mistake?

    Thx a lot,

    Dadv


    maartenba Belgium |

    Thursday, July 28, 2011 7:28 AM

    maartenba

    Can you try this one:

                var catalog = new AggregateCatalog(
                    new DirectoryCatalog("Plugins"),
                     new DirectoryCatalog("bin"),
                    new ConventionCatalog(new MvcApplicationRegistry())); // Note: add your own (convention)catalogs here if needed.

    Dadv France |

    Thursday, July 28, 2011 9:26 AM

    Dadv

    thx for the answers,

    but it don't work any more Frown

    If i break point i can see that catalog contain my external controller, but it's look like it don't load it...

    I can send you a test project if need.

    Dadv

    Dadv France |

    Friday, July 29, 2011 4:12 PM

    Dadv

    Hi again,

    I just look in the MefContrib.Mvc3 source code... everywhere you fond bin directory hard-coded :


    public MvcApplicationRegistry()
    {
      base.Scan(delegate(ITypeScannerConfigurator x)
      {
        x.Assembly(Assembly.GetExecutingAssembly());
        x.Directory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"));
      }
      );
      base.Part().ForTypesAssignableFrom<IController>().MakeNonShared().AddMetadata(new PartCreationScopeAttribute(PartCreationScope.Default)).ExportAs<IController>().Export().Imports(delegate(IImportRegistry x)
      {
        x.Import().Members(delegate(Type m)
        {
          ConstructorInfo[] array = new ConstructorInfo[1];
          array[0] = (m.GetConstructors().FirstOrDefault((ConstructorInfo c) => c.GetCustomAttributes(typeof(ImportingConstructorAttribute), false).Length > 0) ?? m.GetGreediestConstructor());
          return array;
        }
        );
        x.Import().Members((Type m) => (
          from mbr in m.GetMembers()
          where mbr.GetCustomAttributes(typeof(ImportAttribute), false).Length > 0
          select mbr).ToArray<MemberInfo>());
      }
      );
    }


    ///

    public static void Bootstrap()
        {
          AggregateCatalog catalog = new AggregateCatalog(new ComposablePartCatalog[]
          {
            new DirectoryCatalog("bin"),
            new ConventionCatalog(new IPartRegistry<IContractService>[]
            {
              new MvcApplicationRegistry()
            })
          });
          CompositionDependencyResolver compositionDependencyResolver = new CompositionDependencyResolver(catalog);
          DependencyResolver.SetResolver(compositionDependencyResolver);
          ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory(new CompositionControllerActivator(compositionDependencyResolver)));
          FilterProviders.Providers.Remove(FilterProviders.Providers.Single((IFilterProvider f) => f is FilterAttributeFilterProvider));
          FilterProviders.Providers.Add(new CompositionFilterAttributeFilterProvider(compositionDependencyResolver));
          ModelValidatorProviders.Providers.Remove(ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().Single<DataAnnotationsModelValidatorProvider>());
          ModelValidatorProviders.Providers.Add(new CompositionDataAnnotationsModelValidatorProvider(compositionDependencyResolver));
          ModelBinderProviders.BinderProviders.Add(new CompositionModelBinderProvider(compositionDependencyResolver));
        }

    ///

    So i try to remove the bin declaration in AppStart_MefContribMVC3

    var catalog = new AggregateCatalog(
                   //new DirectoryCatalog("bin"),
                    new ConventionCatalog(new MvcApplicationRegistry())); // Note: add your own (convention)catalogs here if needed.


    And... nothing append ... all work like previously.

    So what the use of this "new DirectoryCatalog("bin")" here?
    And why any other DirectoryCatalog are ignore ?


    My goal is simple, i want to have in a "Plugins" directory a Plugin.dll File and a Views Directory

    My Plugin.dll contain a DemoController.

    My main mvc application contain a HomeController.

    Now if i type /Home, i should see the Home View (/Views/Home/Index.cshtml)
    If i type /Demo, i should see the Demo View (/Plugins/Views/Demo/Index.cshtml)

    I know you blog about this, but your previous project where not using MefContrib.MVC3

    If you could not help me about this, can you give me a link where i can find some help  please?

    Thx a lot,

    Dadv

    ps: you can email me if necessary.

    maartenba Belgium |

    Tuesday, August 02, 2011 4:22 PM

    maartenba

    Can you send me an email on this? (note Ill be on vacation the next weeks and may be slow to respond)

    Comments are closed