Recently on the ABP project, see the Sun Ming Rui blog, ABP's di and AOP framework with Castle Windsor
The following is an introduction to the common methods of Castle Windsor Project and summary of the use of ABP
1. Download Castle.windsor required DLL, run Install-package in Package Manager console Castle.windsor
Let's look at a simple example below.
var container = new WindsorContainer (); container. Register (Component.for (typeof (Imyservice). Implementedby (typeof (Myserviceimpl));//control inversion Gets the instance var myservice= container. Resolve<imyservice> ();
We first created the WindsorContainer and then registered the Myserviceimpl and its interfaces, and then we created an instance of Myserviceimpl with the container.
2, registration Castle.windsor There are many ways to register your class, the following describes several methods of registration
General Registration
We can use Castle.MicroKernel.Registration.Component this static class, the For method to register, return a componentregistration, you can use him to further register
Register a class to a container, the default registration type is singleton, which is a singleton
Container. Register ( component.for<myserviceimpl> ());
Register a default instance of the interface, which is used in many of the ABP projects
Container. Register ( component.for (typeof (Imyservice) . Implementedby (typeof (Myserviceimpl));
Of course, we can also specify the way to register instances, mainly transient and singleton,transient are each request to create a new instance, Singleton is a singleton, they are lifestyle properties
Container. Register ( component.for<imyservice> () . Implementedby<myserviceimpl> () . Lifestyle.transient);
When registering an interface with more than one instance, we can register it in a named way, the following is the case of no renaming, the default is to register the first Myserviceimpl
Container. Register ( component.for<imyservice> (). Implementedby<myserviceimpl> (), component.for<imyservice> (). Implementedby<otherserviceimpl> ());
For example, the cache in a NOP project, but the NOP project is AUTOFAC, so you can reverse it by name.
Builder. Registertype<memorycachemanager> (). As<icachemanager> (). Named<icachemanager> ("Nop_cache_static"). SingleInstance (); builder. Registertype<perrequestcachemanager> (). As<icachemanager> (). Named<icachemanager> ("Nop_cache_per_request"). Instanceperlifetimescope ();
At Castle Windsor we can
Container. Register ( component.for<imyservice> (). Named ("Otherserviceimpl"). Implementedby<otherserviceimpl> ());
As mentioned above, the simplest registration method commonly used in Windsor projects, we can also register as an assembly, such as an instance registered with IController as an interface based on the current assembly.
Public windsorcontrollerfactory (IWindsorContainer container) { This.container = container; var controllertypes = from T in assembly.getexecutingassembly (). GetTypes () where typeof (IController). IsAssignableFrom (t) select T; foreach (Var t in controllertypes) container. Register (Component.for (t). lifestyle.transient);}
Assembly.getexecutingassembly () is to get the currently running assembly, or you can do the following, which is the ABP code
Context. IocManager.IocContainer.Register ( classes.fromassembly) (context. Assembly) . Includenonpublictypes () . Basedon<isingletondependency> () . Withservice.self () . Withservice.defaultinterfaces () . Lifestylesingleton () );
Custom Registration
You can also override the Iwindsorinstaller method install for unified registration
public class repositoriesinstaller:iwindsorinstaller{public void Install (IWindsorContainer container, Iconfigurationstore store) { container. Register (classes.fromthisassembly () . Where (component.isinsamenamespaceas<king> ()) . Withservice.defaultinterfaces () . Lifestyletransient ());} }
Constructors & Attribute Injection
Constructor and attribute injection are best practices for project development, and you can use it to get the dependencies of your classes.
public class personappservice{Public ILogger Logger {get; set;} Private IPersonRepository _personrepository; Public Personappservice (ipersonrepository personrepository) { _personrepository = personrepository; Logger = nulllogger.instance; } public void Createperson (string name, int.) { logger.debug ("Inserting a new person to database with name =" + name); var person = new Person {name = name, age = age}; _personrepository.insert (person); Logger.debug ("Successfully inserted!");} }
IPersonRepository is injected from the constructor, and the ILogger instance is injected from the public attribute. In this way, your code will not reflect the dependency injection system. This is the most appropriate way to use the DI system.
General Controller, we will be unified registration, the following is the ABP Registration controller code
public class windsorcontrollerfactory:defaultcontrollerfactory{private ReadOnly Ikernel kernel; Public windsorcontrollerfactory (Ikernel kernel) {this.kernel = kernel; } public override void Releasecontroller (IController controller) {kernel. Releasecomponent (Controller); } protected override IController GetControllerInstance (RequestContext requestcontext, Type controllertype) { if (Controllertype = = null) {throw new HttpException (404, String. Format ("The Controller for path ' {0} ' could not being found.", RequestContext.HttpContext.Request.Path)); } return (IController) kernel. Resolve (Controllertype); }}
The injection pattern using constructors is a perfect way to provide a class's dependency. In this way, only instances that rely on you to create a class are provided. And it's also a powerful way to explicitly declare what the class needs
Rely on to be able to work correctly. However, in some cases, the class relies on another class, but it can also be without it. This is usually appropriate for crosscutting concerns, such as logging. A class can have no logbook, but it can write logs if you provide a log object.
in this case, you can define dependencies as public properties, rather than having them put in constructors . ---from ABP Chinese documents
Well, to finally put Castle Windsor some commonly used registration is finished, the above is mainly about the dependency injection, the following start ABP related introduction
ABP defines a unified registration class Iocmanager, mainly provides registration, inversion, logoff and other operations
public class Iocmanager:iiocmanager {public static iocmanager Instance {get; private set;} Public IWindsorContainer Ioccontainer {get; private set;} Private ReadOnly list<iconventionaldependencyregistrar> _conventionalregistrars; Static Iocmanager () {Instance = new Iocmanager (); } public Iocmanager () {ioccontainer = new WindsorContainer (); _conventionalregistrars = new list<iconventionaldependencyregistrar> (); Register self! Ioccontainer.register (Component.for<iocmanager, Iiocmanager, Iiocregistrar, iiocresolver> (). Usingfactorymethod (() = this)); }//<summary>//registers types of given assembly by all conventional registrars. See <see cref= "Addconventionalregistrar"/> method. </summary>//<param name= "assembly" >assembly to Register</param>//<param name= "config" >additional configuration</param> public void Registerassemblyb Yconvention (Assembly Assembly, conventionalregistrationconfig config) {var context = new Conventionalre Gistrationcontext (assembly, this, config); This loop is still four registered, foreach (var registerer in _conventionalregistrars) {registerer. registerassembly (context); } if (config. Installinstallers) {Ioccontainer.install (fromassembly.instance (assembly)); } }
One important way is that registerassemblybyconvention loops through all classes that inherit the Iconventionaldependencyregistrar interface and registers
To view the code discovery for the ABP, the main implementation of the interface is four classes, respectively registering the Dbcontex type, the controller and the Apicontroller and registering the interface -based Classes implemented by Itransientdependency and Isingletondependency and Iinterceptor
Because of the length of the relationship, I only show the registration controller
<summary>// registers all MVC Controllers derived from <see cref= "Controller"/>. </summary> public class Controllerconventionalregistrar:iconventionaldependencyregistrar { <inheritdoc/> public void registerassembly (Iconventionalregistrationcontext context) { Context. IocManager.IocContainer.Register ( classes.fromassembly) (context. Assembly) . Basedon<controller> () . Lifestyletransient () ); } }
About Castle.windsor Registration There is an entity, generally we commonly use singleton (singleton) and transient (each time a new object is created) so let's see what the ABP does.
public enum Dependencylifestyle {//<summary>// Singleton object. Created a single object on first resolving/// Same instance is used for subsequent resolves. </summary> Singleton,/// <summary>/ Transient object. Created one object for every resolving. </summary> Transient }
Defines an enumeration of lifestyle for related registrations
public void Register (type type, dependencylifestyle lifeStyle = Dependencylifestyle.singleton) { Ioccontainer.register (Applylifestyle (component.for (type), LifeStyle)); }
In addition Castle Windsor also support the log, which is also applied to the ABP, support log4net and so on first need to download the corresponding DLL, Install-package castle.windsor-log4net next automatically register a log instance
public class loggerinstaller:iwindsorinstaller{public void Install (IWindsorContainer container, Iconfigurationstore store) { container. Addfacility<loggingfacility> (f = f.uselog4net ());} }
The third configuration under the Log4net.config file, below is my simple configuration
<?xml version= "1.0" encoding= "Utf-8"?><configuration> <configSections> <!--Log configuration section--<se ction name= "log4net" type= "log4net. Config.log4netconfigurationsectionhandler,log4net "/> </configSections> <log4net> <root> &l T;priority value= "All"/> <appender-ref ref= "Fileappender"/> <appender-ref ref= "InfoLoging"/> </root> <appender name= "Fileappender" type= "log4net. Appender.rollingfileappender "> <file value=" log\\log.txt "/> <appendtofile value=" true "/> & Lt;maxsizerollbackups value= "Ten"/> <maximumfilesize value= "10000KB"/> <rollingstyle value= "Size"/ > <staticlogfilename value= "true"/> <filter type= "log4net. Filter.levelrangefilter "> <levelmin value=" error "/> <levelmax value=" error "/> </fil ter> <lockingmodel type= "log4net. Appender.fileappender+minimallock "/> <layout type= "log4net. Layout.patternlayout "> <conversionpattern value="%date [%thread]%-5level%logger [%PROPERTY{NDC}]-%message %newline "/> </layout> </appender> <appender name=" infologing "type=" log4net. Appender.rollingfileappender "> <file value=" log\\logdata.txt "/> <appendtofile value=" true "/> <maxsizerollbackups value= "Ten"/> <maximumfilesize value= "10000KB"/> <rollingstyle value= "Siz E "/> <staticlogfilename value=" true "/> <filter type=" log4net. Filter.levelrangefilter "> <levelmin value=" info "/> <levelmax value=" info "/> </filte r> <lockingmodel type= "log4net. Appender.fileappender+minimallock "/> <layout type=" log4net. Layout.patternlayout "> <conversionpattern value="%date [%thread]%-5level%logger [%PROPERTY{NDC}]-%message %newline "/> </layout> </appender> </log4net></configuration>
At the end of the article will be attached source code, including configuration
In the end, we can use it, and I'm using the attribute injection method.
public class Accountcontroller:controller {public ILogger Logger {get; set;} Public AccountController () { Logger = nulllogger.instance; } Public ActionResult LogOn () { logger.error ("test"); return View (); } }
Of course ABP is also available in this way with the log4net log, but it is driven by the time it is configured in global
Above is the application of the IOC of the Castle Windsor, and of course the AOP method is also useful in the ABP, we can inherit the Iinterceptor intercept method to intercept
namespace castle.dynamicproxy{ using System; Public interface Iinterceptor { void Intercept (Iinvocation invocation);} }
Below is a look at the most important interception method of the ABP
Internal class Unitofworkinterceptor:iinterceptor {private ReadOnly Iunitofworkmanager _unitofworkmanager ; Public Unitofworkinterceptor (Iunitofworkmanager unitofworkmanager) {_unitofworkmanager = Unitofworkmana Ger }//<summary>//intercepts a method. </summary>//<param name= "invocation" >method invocation arguments</param> public voi D Intercept (iinvocation invocation) {if (_unitofworkmanager.current! = null) { Continue with current UOW invocation. Proceed (); Return } var unitofworkattr = Unitofworkattribute.getunitofworkattributeornull (invocation. Methodinvocationtarget); if (unitofworkattr = = NULL | | unitofworkattr.isdisabled) {//no need to a UOW inv Ocation. Proceed (); Return }//no Current UOW, run a new one PERFORMUOW (invocation, unitofworkattr.createoptions ()); }
Its registration is registered in the module, the registration mainly contains irepository and Iapplicationservice and Unitofworkattribute, so contains [unitofwork] Methods and methods of inheriting irepository and Iapplicationservice will be blocked
<summary>//Intercept registration events///</summary>//<param name= "key" ></PARAM&G T <param name= "Handler" ></param> private static void componentregistered (string key, Ihandler handler ) {if (Unitofworkhelper.isconventionaluowclass (handler). Componentmodel.implementation) {//intercept All methods of all repositories. Handler. COMPONENTMODEL.INTERCEPTORS.ADD (New Interceptorreference (typeof (Unitofworkinterceptor))); } else if (handler. ComponentModel.Implementation.GetMethods (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic). Any (Unitofworkhelper.hasunitofworkattribute)) {//intercept All methods of classes those has at Least one method that has unitofwork attribute. Todo:intecept only unitofwork methods, not other methods! Handler. COMPONENTMODEL.INTERCEPTORS.ADD (New Interceptorreference (typeof (Unitofworkinterceptor)); } }
The above will be Castle Windsor common functions and the use of ABP project is simply finished. Main references for several projects ABP, NOP, Prodinner
Simple Source Address: Http://pan.baidu.com/s/1kTCNpQZ
Reference article:
Https://github.com/ABPFrameWorkGroup/AbpDocument2Chinese
Https://github.com/castleproject/Windsor/blob/master/docs/README.md
Http://www.cnblogs.com/wucg/archive/2012/03/09/2387946.html
Castle Windsor Common Introduction and its application in ABP project