In this ASP. net mvc example: 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 includes the following important concepts:
Container iner INER ):Windsor is a reverse control container. It is created on the basis of a microkernel.
The core can scan the class and try to find the object references and object dependencies used by the class, and then provide the dependency information to the class.
Component ):This is what we usually call the business logic unit and the corresponding function implementation. The component is a repeatable
The unit of code used. It should be implemented and exposed as a service. A component is a class that implements a service or interface.
Service ):That is, the corresponding Component interface or the business logic interface composed of 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 Scalable) containers to manage components.
We can directly use the component as mentioned in the following content), or convert the component into a corresponding service interface for use.
Do you still remember the Service mentioned in the previous article? To put it bluntly, it is a service. Suteki. Shop is more exaggerated. If functional code with business logic can all be regarded as Component or service, such as Filter and ModelBinder mentioned in previous articles. Even the auxiliary class WindsorServiceLocator initialized by the service component is also won.
For ease of understanding, we will go to 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. asaxSuteki. Shop \ Global. asax). The following is the declaration of this method:
ASP. net mvc sample code
- 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:
ASP. net mvc sample code
- /// < 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 containerIWindsorContainer type is empty. If the container is empty, create and initialize the container. That is, call the Build method of the ContainerBuilderSuteki. 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:
Sample ASP. net mvc code:
- 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 in 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 the corresponding service component set.
For example, the implementation code of DoGetInstance and DoGetAllInstances () in this project is as follows:
Sample Code of ASP. net mvc: 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.
- ASP. NET shutdown code (Windows is the local machine)
- ASP. NET QueryString garbled Solution
- ASP. NET screen jump implementation and value passing Solution
- ASP. NET Web application user operation Information Description class
- The father of ASP. NET is strongly recommended: ASP. NET AJAX