Umbraco y Structure Map

Inyección de dependencias (DI) o inversión de Control (IoC) se ha convertido en un facto estándar para muchos desarrolladores. Solía ser un asimiento hacia fuera. Yo solía ser uno de los desarrolladores que dice interfaces de uso cuando se necesitan no sólo por el hecho de utilizar interfaces. Sin embargo, con los métodos de desarrollo, tales como, Test Driven Development, me encontré cada vez más siguiendo el patrón de DI para mi desarrollo. Ahora, no me imagino desarrollando sin DI.

Así que cuando empecé la codificación con Umbraco, una de las primeras preguntas a resolver era cómo utilizar DI con Umbraco. Umbraco es una aplicación de código abierto grande. Como tal, algunas del código sigue un patrón de inyección de dependencia, mientras algunos sigue los métodos más tradicionales.

Yo había estado utilizando Structure Map, así fuera de comodidad decidí utilizar Structure Map con Umbraco. No era realmente necesario que no sea. Utilizando el Structure Map con Umbraco resultó para ser algo así como un ejercicio de solución de problemas. Encontré varios artículos sobre el tema, pero ninguno parecía funcionar completamente para mí.

El arranque inicial

Para Umbraco, el global asax hereda de UmbracoApplication en lugar de System.Web.HttpApplicaion. Como la mayoría DI frameworkds, la creación y configuración del contenedor se produce aquí

public class MvcApplication : UmbracoApplication
    {
        public static IContainer Container { get; set; }
        public static StructureMapDependencyResolver StructureMapResolver { get; set; }

        protected override void OnApplicationStarting(object sender, EventArgs e)
        {
            base.OnApplicationStarting(sender, e);
            Container = StructureMapConfiguration.Configure();
            GlobalConfiguration.Configuration.DependencyResolver = new StructureMapWebApiResolver(Container);
            StructureMapResolver = new StructureMapDependencyResolver(Container);
            DependencyResolver.SetResolver(StructureMapResolver);  
            FilteredControllerFactoriesResolver.Current.InsertType<StructureMapFilteredControllerFactory>(0);

 

Así, la primera configuración (StructureMapConfiguration.Configure()) es una configuración estándar para inyección de dependencias. La segunda sección se refiere al Structure Map para trabajar con controladores de API. La tercera sección configura DI para MVC.

StructureMapConfiguration.Configure


El método de configurar primero agrega el Umbraco Registy, que sigue el Structure Map estándar. Entonces el método de configuración proporciona métodos específicos para devolver una instancia para cuatro clases de Umbraco. Estas cuatro configuraciones fueron identificadas por una combinación de excepciones (encontrada ninguna instancia predeterminada) y la revisión de código de Umbraco.

        public static IContainer Configure()
        {
            var container = new Container(x => x.AddRegistry(new UmbracoRegistry()));

            container.Configure(x => x.For<LegacyTreeController>().Use(() => new LegacyTreeController()));
            container.Configure(x => x.For<UmbracoContext>().Use(() => UmbracoContext.Current));
            container.Configure(x => x.For<IHttpControllerActivator>().Use<UmbracoWebApiHttpControllerActivator>());
            container.Configure(x => x.For<ApplicationContext>().Use(ApplicationContext.Current));

            return container;
        }

 

El método UmbracoRegistry es simplemente estándar código de StructureMap:

       public UmbracoRegistry()
        {
            Scan(
                assemblyScanner =>
                {
                    assemblyScanner.AssembliesFromApplicationBaseDirectory(
                         x => x.FullName.StartsWith("GD")

                   assemblyScanner.AddAllTypesOf<Controller>();
                    assemblyScanner.WithDefaultConventions();
                });
        }

 

La StructureMapWebApiResolver

Estoy incluyendo en el código siguiente como no puedo encontrar la fuente original; mis disculpas al escritor original. Aunque es posible que modifiqué un AutofacWebApiResolver, no recuerdo en este momento. Necesitaba la StructureMapWebApiResolver para ser capaz de mango hecha a la medida, así como la Umbraco web llamadas a la api. Este había enchufada y resuelto mis problemas de la api de web:

    public class StructureMapWebApiResolver : IDependencyResolver
    {
        private readonly IContainer _container;
        private readonly bool _isContainerOwner;

        public StructureMapWebApiResolver(IContainer container) : this(container, false)
        {
        }

        public StructureMapWebApiResolver(IContainer container, bool isContainerOwner)
        {
            _container = container;
            _isContainerOwner = isContainerOwner;
        }

        public IDependencyScope BeginScope()
        {
            return new StructureMapWebApiResolver(_container.GetNestedContainer(), true);
        }

        public object GetService(Type serviceType)
        {
            if (serviceType == null)
            {
                return null;
            }

            if (serviceType.IsAbstract || serviceType.IsInterface)
            {
                return _container.TryGetInstance(serviceType);
            }

            return _container.GetInstance(serviceType);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return _container.GetAllInstances(serviceType).Cast<object>();
        }

        public void Dispose()
        {
            if (_isContainerOwner)
            {
                _container.Dispose();
            }
        }
    }

 

La fábrica de controlador filtrado y MVC dependencia resolución

Finalmente, la fábrica de controlador de filtrado y MVC dependencia resolución trabajan juntos para proporcionar instancias de controlador de la fábrica de controlador correcto. Usted puede encontrar un ejemplo de la resolución de dependencia aquí:

http://www.webadvanced.com/blog/ASP.NET-MVC-4-Web-API-and-structuremap

Una vez este en su lugar, necesitábamos la fábrica controlador filtrado a la aplicación cuando Umbraco debe proporcionar el controlador versus cuando StructureMap debe proporcionar el controlador. Este simplemente se hereda de StructureMapControllerFactory y luego implementa el método CanHandle de la interfaz IFilteredControllerFactory. Esta fábrica de controlador de filtro se inserta en la primera posición, lo que permite determinar si puede proporcionar una instancia del controlador. De lo contrario, el proceso pasa la solicitud a la fábrica de controlador de Umbraco.

public class StructureMapFilteredControllerFactory : StructureMapControllerFactory, IFilteredControllerFactory
    {
        public bool CanHandle(RequestContext request)
        {
            var controllerType = GetControllerType(request, request.RouteData.Values["controller"].ToString());
            if (controllerType.FullName.StartsWith("Umbraco.Web"))
                return false;
            return MvcApplication.Container.Model.HasImplementationsFor(controllerType);
        }
    }

 

Conclusiones

Esto fue un ejercicio de solución de problemas. Quisiera arreglar una pieza y creo que todo estaba funcionando correctamente, pero luego encontró errores (generalmente relacionado con no se puede crear instancia por defecto). Esto resultó para ser algo lentos, pero todavía vale la pena el esfuerzo. No estaba a punto de reescribir un montón de bibliotecas base que sin DI. En el futuro, ojala, Umbraco puede pasar a un modelo completamente DI código agnóstico.

 

 

 

 

 

 

 

 

 

 



Sobre El Autor

Avatar
Jonathan Folland

Jonathan Folland es técnico con más de 20 años de experiencia en una variedad de capacidades. Ocupó el cargo de vicepresidente de operaciones de una de las compañías de más rápido crecimiento en el mundo. Ha dirigido las operaciones de comercio electrónico de gran volumen y es un experto en la tecnología y las finanzas de mezcla para producir resultados de alta rentabilidad.


Artículos Relacionados