📜 ⬆️ ⬇️

Microsoft Object Builder

Hello! This is my first article in Habré. Faced today in the tape on the description of Java-frameworks Spring and Tapestry, decided to browse Habra and find lovers of "competing" frameworks from Microsoft - in particular Composite UI Application Block (CAB) and Unity. To my surprise, I found nothing. Seeing the comments in the article about the Java framework, the request to describe the mechanism of dependency injection, I decided to start my cycle of articles about the .Net framework specifically by clarifying IoC issues. So, meet - the cornerstone (in the past) of the wonderful CAB engine - Microsoft Object Builder.

What it is and where it is used


Object Builder (hereinafter OB) is a mechanism for implicitly automatic composition of a set of dependent objects into a connected graph. OB was provided by Microsoft in May 2005 through its open-source Patterns and Practices complex “open-source project” forge in tandem with the desktop application framework CAB (or SmartClient). A set of fundamental classes CAB uses OB as a mechanism for injection of dependencies when a user creates engine objects (user controls, services, extensions, etc.).

How to set yourself


Download CAB from here and put. The installer will add three assemblies to the GAC, one of which is an OB.

What does the Object Builder consist of and how does it work?


Essentially, an OB is an aggregation of several programming patterns. Briefly describe the structure.
')


Soul requires examples! For example, let's create an object - the IProgramService microservice:
interface IProgramService
{
void DoWork();
}


* This source code was highlighted with Source Code Highlighter .

But its implementation:
class ProgramService : IProgramService
{
#region IProgramService Members

public void DoWork()
{
Console .WriteLine( string .Format( "[{0}] Program Service: DoWork()" , _guid));
}

#endregion

private Guid _guid = Guid .NewGuid();
public Guid Guid
{
get { return _guid; }
}
}


* This source code was highlighted with Source Code Highlighter .

Then the creation code will be like this:
Builder builder = new Builder();
Locator locator = new Locator();
IProgramService service = builder.BuildUp<ProgramService>(locator, null , null );

service.DoWork();


* This source code was highlighted with Source Code Highlighter .

Just like that.

Let us consider the strategies for inserting dependencies.

Application


If you look at the build code for the builder, you can see how he adds vital strategies to himself:

public Builder(IBuilderConfigurator<BuilderStage> configurator)
{
Strategies.AddNew<TypeMappingStrategy>(BuilderStage.PreCreation);
Strategies.AddNew<SingletonStrategy>(BuilderStage.PreCreation);
Strategies.AddNew<ConstructorReflectionStrategy>(BuilderStage.PreCreation);
Strategies.AddNew<PropertyReflectionStrategy>(BuilderStage.PreCreation);
Strategies.AddNew<MethodReflectionStrategy>(BuilderStage.PreCreation);
Strategies.AddNew<CreationStrategy>(BuilderStage.Creation);
Strategies.AddNew<PropertySetterStrategy>(BuilderStage.Initialization);
Strategies.AddNew<MethodExecutionStrategy>(BuilderStage.Initialization);
Strategies.AddNew<BuilderAwareStrategy>(BuilderStage.PostInitialization);

Policies.SetDefault<ICreationPolicy>( new DefaultCreationPolicy());

if (configurator != null )
configurator.ApplyConfiguration( this );
}


* This source code was highlighted with Source Code Highlighter .


We will understand what methods you can create links between dependencies and how these strategies work.

TypeMappingStrategy (PreCreation) - Type matching policy. For example, in the last example, we explicitly indicated which type to create. But what if we don’t want to specify each time which class implements the IProgramService interface? What if we want to create an IProgramService , and who will be a specific type, we don’t want to know - let the programmer Vasya have a headache about it? We use the ITypeMappingPolicy creation ITypeMappingPolicy . This policy will indicate to the locator the correspondence between the interface and the specific type:

class TypeMappingPolicy : ITypeMappingPolicy
{
#region ITypeMappingPolicy Members

public DependencyResolutionLocatorKey Map(DependencyResolutionLocatorKey incomingTypeIDPair)
{
return new DependencyResolutionLocatorKey( typeof (ProgramService), null );
}

#endregion
}


* This source code was highlighted with Source Code Highlighter .


Registration policy occurs in this way:
builder.Policies.Set<ITypeMappingPolicy>( new TypeMappingPolicy(), typeof (IProgramService), null );
IProgramService service = builder.BuildUp<IProgramService>(locator, null , null );


* This source code was highlighted with Source Code Highlighter .


SingletonStrategy (PreCreation) - The strategy of creating an object as a singleton. This means that the created object for the specified type will be created only once. All subsequent attempts to create this type will be replaced by the substitution of an existing object. To do this, you must explicitly mark the created type with a special key, the so-called. DependencyResolutionLocatorKey :
IProgramService service = builder.BuildUp<ProgramService>(locator, null , null );
DependencyResolutionLocatorKey key = new DependencyResolutionLocatorKey( typeof (ProgramService), null );
locator.Add(key, service);

IProgramService service2 = builder.BuildUp<ProgramService>(locator, null , null );


* This source code was highlighted with Source Code Highlighter .

In this case, service and service2 point to the same object.

ConstructorReflectionStrategy (PreCreation) is a strategy for creating an object through a constructor. The name speaks for itself - the strategy will select an object constructor marked with the [InjectionConstructor] attribute and for each parameter marked with the [Dependency] attribute it will find it through the locator. After which it will call the constructor, passing there the otrezolvlennye parameters.
[InjectionConstructor]
public ServiceConsumer([Dependency]IProgramService service)
{
_service = service;
}


* This source code was highlighted with Source Code Highlighter .

There are several ways to insert parameters. Through the properties of the attribute Dependency, you can specify the type to be created, as well as define the behavior if the type you are looking for is not found. For example, create a new ( CreateNew ), or throw an exception:
[InjectionConstructor]
public ServiceConsumer(
[Dependency(CreateType= typeof (ProgramService), NotPresentBehavior=NotPresentBehavior.Throw)]IProgramService service)
{
_service = service;
}


* This source code was highlighted with Source Code Highlighter .

It goes without saying that if we create one object that has a dependency on another, then another object must be resolved in the locator:
IProgramService service = builder.BuildUp<ProgramService>(locator, null , null );
DependencyResolutionLocatorKey key = new DependencyResolutionLocatorKey( typeof (IProgramService), null );
locator.Add(key, service);

ServiceConsumer consumer = builder.BuildUp<ServiceConsumer>(locator, null , null );


* This source code was highlighted with Source Code Highlighter .


CreationStrategy (reation) is the usual creation strategy. In the very first example above, the object is built just through the creation strategy. How it works - first, the strategy looks for a custom ICreationPolicy policy, and if it does not find the policy, it uses the “native” one. The native creation policy instructs the builder to determine the first object constructor (through reflection) and run the build chain on each dependency (parameter) in the constructor. Then execute it through the Activator . A feature of this strategy is the fact that you can transfer an already created object to it. Then the strategy will do nothing :) Just transfer control to other strategies that have a Stage following Creation . Once again the last, but in other words - we can create an object through new() , pass it to the builder. In this case, the builder will not create an object, but simply insert dependencies into it.

PropertyReflectionStrategy + PropertySetterStrategy (Initialization). Strategies (in fact, semantically, this is one strategy), allowing to insert dependencies into the properties of an object. In a nutshell, this is how PropertyReflectionStrategy defines the properties of an object, marked with the [Dependency] attribute, recognizes the types of objects that need to be inserted, creates an IPropertySetterPolicy policy, where it lists this information. Then, walking along the chain, PropertySetterStrategy starts to work, which finds the policy, from it determines the properties that need to insert objects, resolves the objects and sets them in the right places. The strategy separation chip is here for the user to use his IPropertySetterPolicy .
[Dependency(CreateType= typeof (ProgramService),
NotPresentBehavior=NotPresentBehavior.CreateNew)]
public IProgramService ProgramService
{
set { _service = value ; }
get { return _service; }
}


* This source code was highlighted with Source Code Highlighter .


This code can be rewritten easier:
[CreateNew]
public ProgramService ProgramService2
{
set { _service = value ; }
}


* This source code was highlighted with Source Code Highlighter .


MethodReflectionStrategy + MethodExecutionStrategy (Initialization). In essence, these two strategies are isomorphic to the strategies of Property dependencies. Only, instead of setting the property, a call is made to the method marked with the [InjectionMethod] attribute.
[InjectionMethod]
public void DoWork([Dependency]IProgramService service)
{
service.DoWork();
}


* This source code was highlighted with Source Code Highlighter .


BuilderAwareStrategy (PostInitialization). In the OB there is such a special interface IBuilderAware , in which there are two methods - OnBuiltUp , OnTearingDown . You can implement them in your class, then when you build (or destroy) an object, the strategy will cause them. Very useful if you need to run something immediately after creating the object (when all dependencies are in place).
#region IBuilderAware Members

public void OnBuiltUp( string id)
{
Console .WriteLine( "Built Up!" );
}

public void OnTearingDown()
{
Console .WriteLine( "Tearing down!" );
}

#endregion


* This source code was highlighted with Source Code Highlighter .


I listed all the “native” OB strategies. In the engines, developers add their strategies so that you can link the specialized aspects of the framework. Unfortunately, completely disassemble all aspects of an OB — for example, the named instances are not affected, the politician theme is not fully developed, and so on. The reader, I think, if he wants, will figure it out himself :)

How to use it in real applications, pros and cons


The answer is simple - as an infrastructure aspect. If you want to implement in your application architecture that involves injection of dependencies, then the OB is what the doctor prescribed. OB itself was not originally intended for direct use. In the CAB engine, its methods turn into special collections - OB facades, which greatly facilitates the work of the programmer.

Minuses: The most, perhaps, the big minus of the solution - OB is heavy. It clutters up code with attributes (you can't do without them!), And its method BuildUp , you know, is not one of the fastest. This problem can be solved by optimizing links in the class graph — in fact, minimizing the number of dependencies with maximum code isolation.
Pros: Low connectivity code, objects, and all the ensuing. This is the simplicity of unit tests, and autonomous (when you don’t have to put anything up with pens) microservice architecture and the like.

Future Object Builder and Conclusion.


Now OB is outdated :( Yes, sorry, I wrote an article on outdated technology, but it seems to me that it is useful to start from the basics. In addition, it will be difficult to talk about Microsoft Object Builder 2 without understanding what Microsoft Object Builder was Microsoft replaces the CAB engine with a more modern Unity application. The Unity Application Block is an even more flexible platform with the long-awaited support for WPF. Actually, in the following articles I’ll tell you what CAB is and gradually move to Unity. Here are the links:
CAB: msdn.microsoft.com/en-us/library/aa480450.aspx
CAB: www.codeplex.com/smartclient
Unity: msdn.microsoft.com/en-us/library/cc468366.aspx
Unity: www.codeplex.com/unity
Difference of CAB from Unity: www.codeplex.com/CompositeWPF/Release/ProjectReleases.aspx?ReleaseId=16941

Thanks for attention.

Source: https://habr.com/ru/post/48450/


All Articles