Castle IOC in MVC

Source: Internet
Author: User

In suteki. Shop, Microsoft's own Unity Framework is not used to implement IOC, but the famous castle Windsor is used.

It is necessary to give a brief introduction to the reference of Windsor. In my understanding, this IOC container (container) includes the following important concepts:

Container: Windsor is a reverse control container. It is created on the basis of a micro-kernel, which can scan classes and try to find the object references and object dependencies used by these classes, and then provide the dependency information to the class for use.

Component: This is what we usually call a business logic unit and corresponding function implementation. A component is a reusable code unit. It should be implemented and exposed as a service. A component is a class that implements a service or interface.

Service: a service is a service logical interface composed of the corresponding component interfaces or N components based on the business logic.

An interface is a service specification. It creates an abstraction layer, and you can easily replace the Service implementation.

Expansion unit plug-in (Facilities): provides (expandable) containers to manage components.

 

You can directly use components (as mentioned in the following content) or convert them into corresponding service interfaces.

Do you still remember the service mentioned in the previous article? To put it bluntly, it is a service. Suteki. Shop is more exaggerated. As long as it is a functional code with business logic, it can be regarded as a component or service, such as the filter and modelbinder mentioned in previous articles. Even the auxiliary class (windsorservicelocator) initialized by the service component is also won.

For ease of understanding, let's take a look at suteki. Shop to see how it works :)

First, let's take a look at the whole suteki. Shop project startup portal, which is also the starting point for the Windsor IOC container initialization. This functional code is implemented in the application_start method in global. asax (suteki. Shop/global. asax). The following is the declaration of this method:

protected void Application_Start(object sender, EventArgs e)
{
    RouteManager.RegisterRoutes(RouteTable.Routes);
    InitializeWindsor();
}

In the code, routemanager. registerroutes is used to bind a route rule, and the content of the rule is hardcoded into routemanager. There are a lot of information about route on the Internet, and many friends in the garden have written it. I will not explain it here.

The above method will run initializewindsor (). This is the method used to initialize the Windsor container:

/// <summary>
/// This web application uses the Castle Project's IoC container, Windsor see:
/// http://www.castleproject.org/container/index.html
/// </summary>
protected virtual void InitializeWindsor()
{
    if (container == null)
    {
        // create a new Windsor Container
        container = ContainerBuilder.Build("Configuration//Windsor.config");

        WcfConfiguration.ConfigureContainer(container);

        ServiceLocator.SetLocatorProvider(() => container.Resolve<IServiceLocator>());
        // set the controller factory to the Windsor controller factory (in MVC Contrib)
        System.Web.Mvc.ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container));
    }
}

Note: The content in "configuration // Windsor. config" is long, mainly for some xml configuration nodes. You can take the time to read it.

This method is the main content explained today. The following describes the code.

First, determine whether the container (iwindsorcontainer type) is empty. If the container is empty, create and initialize the container. That is, call the build method of the containerbuilder (suteki. Shop/containerbuilder) class to load the default information from the external config file. Let's take a look at the implementation of the build method:

public static IWindsorContainer Build(string configPath)
{
        var container = new WindsorContainer(new XmlInterpreter(configPath));

        // register handler selectors
        container.Kernel.AddHandlerSelector(new UrlBasedComponentSelector(
            typeof(IBaseControllerService),
            typeof(IImageFileService),
            typeof(IConnectionStringProvider)
            ));

        // automatically register controllers
        container.Register(AllTypes
            .Of<Controller>()
            .FromAssembly(Assembly.GetExecutingAssembly())
            .Configure(c => c.LifeStyle.Transient.Named(c.Implementation.Name.ToLower())));

        container.Register(
            Component.For<IUnitOfWorkManager>().ImplementedBy<LinqToSqlUnitOfWorkManager>().LifeStyle.Transient,
            Component.For<IFormsAuthentication>().ImplementedBy<FormsAuthenticationWrapper>(),
            Component.For<IServiceLocator>().Instance(new WindsorServiceLocator(container)),
            Component.For<AuthenticateFilter>().LifeStyle.Transient,
            Component.For<UnitOfWorkFilter>().LifeStyle.Transient,
            Component.For<DataBinder>().LifeStyle.Transient,
            Component.For<LoadUsingFilter>().LifeStyle.Transient,
            Component.For<CurrentBasketBinder>().LifeStyle.Transient,
            Component.For<ProductBinder>().LifeStyle.Transient,
            Component.For<OrderBinder>().LifeStyle.Transient,
            Component.For<IOrderSearchService>().ImplementedBy<OrderSearchService>().LifeStyle.Transient,
            Component.For<IEmailBuilder>().ImplementedBy<EmailBuilder>().LifeStyle.Singleton
        );

        return container;
}

First, read the XML node information of the specified configuration file, construct a windsorcontainer implementation, and add the "container processing component" method (addhandlerselector) to its microkernel ), note that this processing method is handled as defined in the business logic.

The Controller is registered with the container, and the lifestyle of the Configuration Attribute is specified as the transient type. It is necessary to introduce the component life cycle of the castle container, including the following:

Singleton: only one instance in the container will be created

Transient: each request creates a new instance

Perthread: only one instance exists in each thread.

Perwebrequest: each time a Web Request creates a new instance

Pooled: You can use the "pooled" method to manage components. You can use the pooledwithsize method to set related attributes of the pool.

In this project, the life cycle of the component is basically designated as the transient type, that is, when a request is created, it is destroyed after processing.

Next, let's take a look at the remaining code of this method, that is, register the components of the business logic such as modelbinder, filter, and service. At the same time, we can see that some group classes are bound to the default implementation classes while performing interface registration. This hard encoding method is an "optional" method.

Before completing the build method, return to the initializewindsor method in the global. asax file and check the remaining code. We can see this line:

     WcfConfiguration.ConfigureContainer(container);

The configurecontainer method of wcfconfiguration class is to add components to the currently created container. The component to be added this time is the imetaweblog interface implementation class of Windows Live writer, as follows:

public static class WcfConfiguration
{
    public static void ConfigureContainer(IWindsorContainer container)
    {
        var returnFaults = new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true };

        container.AddFacility<WcfFacility>(f =>
        {
            f.Services.AspNetCompatibility = AspNetCompatibilityRequirementsMode.Required;
            f.DefaultBinding = new XmlRpcHttpBinding();
        })
            .Register(
                Component.For<IServiceBehavior>().Instance(returnFaults),
                Component.For<XmlRpcEndpointBehavior>(),
                Component.For<IMetaWeblog>().ImplementedBy<MetaWeblogWcf>().Named("metaWebLog").LifeStyle.Transient
                );

    }
}

As mentioned above, the expansion unit plug-in (Facilities) can inject the function code you need without changing the original components, the addfacility method is used to add extension units to register and manage our Windows Live writer components.

Next we will analyze the remaining code in the initializewindsor method, read the configurecontainer method, and then we will see the following line of code:

    ServiceLocator.SetLocatorProvider(() => container.Resolve<IServiceLocator>());

I was familiar with seeing this line. I remember reading this line of code similar to this in oxite's global. asax.

     ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container)); 

But that project uses unity instead of Castle Windsor. However, the actual functions are the same. Resolve and bind the service address in the container. With this feature, you can use the methods defined in Microsoft. Practices. servicelocation. servicelocatorimplbase, such as dogetinstance or dogetallinstances, to obtain instances of the corresponding service components (sets.

For example, the implementation code of dogetinstance and dogetallinstances () in this project is as follows:

(The file is located at: suteki. Common/Windsor/windsorservicelocator. CS ):

protected override object DoGetInstance(Type serviceType, string key)
{
    if (key != null)
        return container.Resolve(key, serviceType);
    return container.Resolve(serviceType);
}

/// <summary>
/// When implemented by inheriting classes, this method will do the actual work of
/// resolving all the requested service instances.
/// </summary>
/// <param name="serviceType">Type of service requested.</param>
/// <returns>
/// Sequence of service instance objects.
/// </returns>
protected override IEnumerable<object> DoGetAllInstances(Type serviceType)
{
    return (object[])container.ResolveAll(serviceType);
}

Note: The IOC of the windsorservicelocator class is bound to containerbuilder. Build as follows:

  container.Register(
       Component.For<IUnitOfWorkManager>().ImplementedBy<LinqToSqlUnitOfWorkManager>().LifeStyle.Transient,
       Component.For<IFormsAuthentication>().ImplementedBy<FormsAuthenticationWrapper>(),
       Component.For<IServiceLocator>().Instance(new WindsorServiceLocator(container)),

The last line of code in the initializewindsor method is as follows:

     System.Web.Mvc.ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container));

The windsorcontrollerfactory class is provided in the mvccontrib project to construct a controller factory of the castle project type.

Well, today's content may be a bit complicated, mainly Castle, because there are some concepts that need to be understood before you can understand the code in the project. However, the IOC mechanism of suteki. Shop is still very clear, and there is nothing too ugly to code.

Today, we will be here first.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.