9.62 Registering components in XML

优质
小牛编辑
131浏览
2023-12-01

Components are defined by tag <component/> within <components/> section.

<components>
  <component ...attributes>
    ...elements
  </component>
</components>

Simple components

To register a component you need to specify at least two things - id of the component, and its type)

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

:information_source: In Windsor 3 id attribute is optional, so you need to only specify type.

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

Component with abstraction

More often you will want the component type to be an abstract base type, or interface, implemented by the type you're exposing

<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

It is possible to specify a lifestyle via the XML configuration

<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
singletonThis is the default lifestyle in Windsor
transientWindsor keeps references to transient components!
pooledFor pooled lifestyle two additional attributes need to be defined: initialPoolSize and maxPoolSize both of which accept positive integer values
thread
customFor custom lifestyle additional attribute needs to be defined: customLifestyleType which points to the type implementing the lifestyle

Component with parameters

It is possible to specify parameters via XML configuration.

<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>

As shown in the example parameters can be defined in three distinct ways:

Inline parameters

In the above example smtpServer is an inline parameter: its value - localhost:667, is provided right on the spot. Windsor's XML format lets you specify not just primitive types, but also lists, arrays, dictionaries or any other complex types. (read more)

Property references

In the above example senderEmail is a property reference parameter: 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.

Service overrides (other service as parameter)

In the above example 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)

Single component can be used as multiple services. This feature, called forwarded types in Windsor, is also exposed via XML.

<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
allThis is the default behavior
noneWindsor will not try to set any properties
declaredonlyOnly properties declared on the component's type (and not ones declared on base types) will be set

Proxy components

All power of underlying DynamicProxy library is exposed via XML configuration.

:information_source: Read more: This guide only discusses the XML syntax. To learn more about how DynamicProxy works and how and where it can be helpful, read this tutorial.

Interceptors

Registering interceptors is very similar to service overrides:

<component
      id="notification"
      service="Acme.Crm.Services.INotificationService, Acme.Crm"
      type="Acme.Crm.Services.EmailNotificationService, Acme.Crm">
    <interceptors>
      <interceptor>${loggingInterceptor}</interceptor>
    </interceptors>
</component>

You reference interceptors via key, using standard reference notation.

Interceptors selector

You reference interceptor selector using selector attribute on <interceptors> element:

<component
      id="notification"
      service="Acme.Crm.Services.INotificationService, Acme.Crm"
      type="Acme.Crm.Services.EmailNotificationService, Acme.Crm">
    <interceptors selector="${interceptorsSelectorId}">
      <interceptor>${loggingInterceptor}</interceptor>
    </interceptors>
  </component>

Proxy hook

You reference proxy hook using hook attribute on <interceptors> element:

<component
      id="notification"
      service="Acme.Crm.Services.INotificationService, Acme.Crm"
      type="Acme.Crm.Services.EmailNotificationService, Acme.Crm">
  <interceptors hook="${proxyHookId}">
    <interceptor>${loggingInterceptor}</interceptor>
  </interceptors>
</component>

Mixins

Windsor lets you mix your service with additional services into one object:

<component
      id="notification"
      service="Acme.Crm.Services.INotificationService, Acme.Crm"
      type="Acme.Crm.Services.EmailNotificationService, Acme.Crm">
    <mixins>
      <mixin>${otherServiceId}</mixin>
    </mixins>
</component>

You reference other services you want to mix in using Windsor's standard reference notation.

Additional interfaces

Windsor lets you specify additional interfaces to be implemented by your proxy. Implementation for these interfaces should be provided by interceptors:

<component
      id="notification"
      service="Acme.Crm.Services.INotificationService, Acme.Crm"
      type="Acme.Crm.Services.EmailNotificationService, Acme.Crm">
    <interceptors>
      <interceptor>${metadataInterceptor}</interceptor>
    </interceptors>
    <additionalInterfaces>
      <add interface="Acme.Crm.Services.IMetadataService, Acme.Crm" />
    </additionalInterfaces>
</component>