|
Metadata
Autofac provides facilities for creating and consuming component metadata.
Autofac2 If you’re familiar with the Managed Extensibility Framework (MEF) you have probably seen examples using component metadata. Metadata is information about a component, stored with that component, accessible without necessarily creating a component instance. Adding Metadata to a Component RegistrationValues describing metadata are associated with the component at registration time. Each metadata item is a name/value pair: builder.Register(c => new ScreenAppender())
.As<ILogAppender>()
.WithMetadata("AppenderName", "screen");The same thing can be represented in XML: <component
type="MyApp.Components.Logging.ScreenAppender, MyApp"
service="MyApp.Services.Logging.ILogAppender, MyApp" >
<metadata>
<item name="AppenderName" value="screen" type="System.String" />
</metadata>
</component>Consuming MetadataUnlike a regular property, a metadata item is independent of the component itself. This makes it useful when selecting one of many components based on runtime criteria; or, where the metadata isn’t intrinsic to the component implementation. Metadata could represent the time that an ITask should run, or the button caption for an ICommand. Other components can consume metadata using the Meta<T> type. public class Log
{
readonly IEnumerable<Meta<ILogAppender>> _appenders;
public Log(IEnumerable<Meta<ILogAppender>> appenders)
{
_appenders = appenders;
}
public void Write(string destination, string message)
{
var appender = _appenders.First(a => a.Metadata["AppenderName"].Equals( destination));
appender.Value.Write(message);
}
}To consume metadata without creating the target component, use Meta<Lazy<T>> or the .NET 4 Lazy<T, TMetadata> types as shown below. Strongly-Typed MetadataTo avoid the use of string-based keys for describing metadata, an interface can be defined with a readable property for every metadata item: public interface IAppenderMetadata
{
string AppenderName { get; }
}At registration time, the interface is used with the overloaded WithMetadata method to associate values: builder.Register(c => new ScreenAppender())
.As<ILogAppender>()
.WithMetadata<IAppenderMetadata>(m =>
m.For(am => am.AppenderName, "screen"));(A further example can be seen in this unit test.) In .NET 4.0, Autofac supports the Meta<T, TMetadata> and System.Lazy<T, TMetadata> types for consuming values from the strongly-typed interface: public class Log
{
readonly IEnumerable<Lazy<ILogAppender, ILogAppenderMetadata>> _appenders;
public Log(IEnumerable<Lazy<ILogAppender, ILogAppenderMetadata>> appenders)
{
_appenders = appenders;
}
public void Write(string destination, string message)
{
var appender = _appenders.First(a => a.Metadata.AppenderName == destination);
appender.Value.Write(message);
}
}Notice the use of the strongly-typed AppenderName property. Registration and consumption of metadata are separate, so strongy-typed metadata can be consumed via the weakly-typed techniques and vice-versa. Note: in version 1.4 of Autofac, metadata was known as "extended properties". The extended property feature has been replaced by metadata. | |