Castle Windsor

Part One- Getting Windsor

通过Nuget引入Castle.Windsor

Part Two- Plugging Windsor in 

To get started using Windsor we need to plug it into the application.

The first and most publicized MVC extension point that we'll look at is controller factory. We'll use it to have Windsor manage our controllers and all of their dependencies.

通过Mvc 的公开扩展点ControllerFactory,通过它控制Controller和所有的依赖关系。

Windsor Controller Factory

In this part we created a controller factory which uses Windsor to manage components in our application.

Controller factory的两个职责。

(通过Container.IKernel) 为每个request创建新的Controller实例,请求结束后Release Controller实例

为什么不使用IControllerActivator作为扩展点呢?因为它只有创建实例的方法,没有释放实例的方法。 Because it only has a Create method, and lacks method for releasing the controllers. 

Part Three- Writing First Installer

安装注册项目中的相关Compnent

Windsor 使用Installer类(IWindsorInstaller) registration 程序中的Component(依赖组件、类)

IWindsorInstaller只有一个方法 public void Install(IWindsorContainer container, IConfigurationStore store) ,参数container提供方法注册具体的Component

注意:

1.分类自己的WindsorInstaller,使它们保持简单,可读,职责单一,有利于测试和职责划分查找问题。

2.By default Installers must be public with public default constructor

Using installers

FromAssembly

container.Install(
   FromAssembly.This(),//在本程序集中安装
   FromAssembly.Named("Acme.Crm.Bootstrap"),//
   FromAssembly.Containing<ServicesInstaller>(),
   FromAssembly.InDirectory(new AssemblyFilter("Extensions")),
   FromAssembly.Instance(this.GetPluginAssembly())
);
安装程序集中所有个IWindsorInstaller
注意:安装顺序不确定,需要确定安装顺序时使用InstallerFactory
FromAssembly.This()
在本程序集中安装
FromAssembly.Named("Acme.Crm.Bootstrap")
Install from assembly with specified assembly name using standard .NET assembly locating mechanism. 通过程序集名字注册
You can also provide path to a .dll or .exe file when you have the assembly in some non-standard location.可以添加程序集的路径
FromAssembly.Containing<ServicesInstaller>()
在存在指定类的程序集中安装,和
FromAssembly.Named 二选一。Installs from assembly containing designated type. This method is usually used as string-less alternative to FromAssembly.Named.
FromAssembly.InDirectory(new AssemblyFilter("Extensions"))
FromAssembly.Instance  
InstallerFactory class 以上方法都有接受InstallerFactory参数的重载,通过它可以控制注册顺序、选择程序集中部分Installer进行注册。

Configuration class 通过配置文件注册Installers
container.Install(
   Configuration.FromAppConfig(),
   Configuration.FromXmlFile("settings.xml"),
   Configuration.FromXml(new AssemblyResource("assembly://Acme.Crm.Data/Configuration/services.xml"))
);

Part Four - Putting it All Together

在Application_Start时

container = new WindsorContainer().Install(FromAssembly.This());//创建容器
var controllerFactory = new WindsorControllerFactory(container.Kernel);//创建ControllerFactory
ControllerBuilder.Current.SetControllerFactory(controllerFactory);//设置当前ControllerFactory
在Application_End时
container.Dispose();//释放容器
 
 
 
 

Lifestyles

Singleton(default)

第一次请求此Component时创建,以后重复使用。即使调用release也不会起作用,只会在container被释放时销毁。

注意多线程时的状态,保证线程安全。

Transient

瞬时的,当使用它的对象released时,释放Component

注意:如果使用container.Resolve<MyTransientComponent>()需要显示调用container.Release(myTransientInstance) 释放。

Scoped

eq:

using Castle.MicroKernel.Lifestyle;
using (Container.BeginScope()) //extension method
{
	var one = Container.Resolve<MyScopedComponent>();
	var two = Container.Resolve<MyScopedComponent>();
	Assert.AreSame(one, two);
} // releases the instance.

Bound

PerThread

Instance of a component will be shared in scope of a single thread of execution. 
It will be created the first time the component is requested on given thread.
Releasing the component explicitly does nothing.
Instances will be released when the container they're registered with is disposed.
单个线程内共享,只有container释放才会回收
注意:Basically it should be used only when your application controls the thread, and never when thread pool threads (or Tasks) are involved.

Pooled

A pool of instances will be created and then one of them will be returned when requested. 
When the component is first requested, the pool of initialSize elements is instantiated and a single one of them is marked internally as in use and returned.
When more components are requested, the pool will first return all of the components it has that are not in use, and if it runs out, will start creating new ones.
Releasing the components may do either of two things:
1.
When the pool has more components in use than maxSize the component will be released immediately
2.Otherwise the component will be recycled (if it implements IRecyclable) and returned to the pool marked as ready to use.
Windsor provides a special interface - Castle.Core.IRecyclable for poolable components.

It contains single method: void Recycle();

This method is invoked when the component is returned to the pool, and components can use it to implement custom initialization/clean up logic.

Setting lifestyle

API Setting
Container.Register( Classes.FromThisAssembly() .BasedOn<IController>() .LifestyleTransient());

XML Setting

Simple components

<components>
  <component
      id="notification"
      type="Acme.Crm.Services.EmailNotificationService, Acme.Crm">
  </component>
</components>

This is identical to specifying Component.For<EmailNotificationService>().Named("notification"); with Fluent Registration API.

Component with abstraction

<components>
  <component
      id="notification"
      service="Acme.Crm.Services.INotificationService, Acme.Crm"
      type="Acme.Crm.Services.EmailNotificationService, Acme.Crm">
  </component>
</components>
This is identical to specifying Component.For<INotificationService>().ImplementedBy<EmailNotificationService>().Named("notification");.

Component with lifestyle

<components>
  <component
      id="notification"
      service="Acme.Crm.Services.INotificationService, Acme.Crm"
      type="Acme.Crm.Services.EmailNotificationService, Acme.Crm"
      lifestyle="transient">
  </component>
</components>

The list of valid values for the lifestyle attribute (mapped to appropriate LifestyleManager enum values):

LifestyleNotes
singleton This is the default lifestyle in Windsor
transient Windsor keeps references to transient components!
pooled For pooled lifestyle two additional attributes need to be defined: initialPoolSize and maxPoolSize both of which accept positive integer values
thread  
custom For custom lifestyle additional attribute needs to be defined: customLifestyleType which points to the type implementing the lifestyle

Component with parameters

<components>
  <component
      id="notification"
      service="Acme.Crm.Services.INotificationService, Acme.Crm"
      type="Acme.Crm.Services.EmailNotificationService, Acme.Crm"
      lifestyle="transient">
    <parameters>
      <smtpServer>localhost:667</smtpServer>
      <senderEmail>#{admin.email}</senderEmail>
      <emailFormatter>${emailFormatter}</emailFormatter>
    </parameters>
  </component>
</components>
smtpServer is an inline parameter,也可以传递list、array、dictionary  or any other complex types 。(read more
senderEmail is a property references ,its value is defined in the <properties> section of the configuration file (not shown here) under name admin.email. You specify property references using #{property.id}notation.
emailFormatter is a service override parameter: as its value another component, registered with id equals emailFormatter will be used. You specify service overrides using ${service.id} notation.

Component with multiple services (forwarded types)

<components>
  <component
      id="notification"
      service="Acme.Crm.Services.INotificationService, Acme.Crm"
      type="Acme.Crm.Services.EmailNotificationService, Acme.Crm">
    <forwardedTypes>
      <add service="Acme.Crm.Services.IEmailSender, Acme.Crm" />
    </forwardedTypes>
  </component>
</components>

Setting properties

By default when Windsor creates component it will try to set all its settable properties it can provide value for. 
When using XML configuration this behavior can be adjusted.
<component
      id="notification"
      service="Acme.Crm.Services.INotificationService, Acme.Crm"
      type="Acme.Crm.Services.EmailNotificationService, Acme.Crm"
      inspectionBehavior="none">
</component>
 
Inspection behaviorNotes
all This is the default behavior
none Windsor will not try to set any properties
declaredonly Only properties declared on the component's type (and not ones declared on base types) will be set
 
中文文档
我的笔记

原文地址:https://www.cnblogs.com/fmys/p/9161783.html