Overview

When you write a task, your components are instantiated and invoked by the PostSharp Platform. But there are situations where you would like to instantiate the PostSharp Platform yourself. For instance when you develop an application server. See for instance COM+. You can define transactional behavior using the management GUI. Suppose you want to do something else without COM+. You will need to weave assemblies at runtime, exactly before they are loaded into memory for execution. 

Even if you cannot weave at compile time, PostSharp is still a good choice. But you need to host it in your application server.

PostSharp comes with two standard hosts:

Additionally, the PostSharp.Samples.Host sample illustrates how to host PostSharp to perform runtime weaving.

The PostSharp Object

The PostSharp Object is interface between the host and the Platform Infrastructure. Its semantics are defined by the IPostSharpObject interface. They are very simple: a single method InvokeProjects that allows to execute a set of projects.

In order to get an instance of the PostSharp Object, you should use the CreateInstance method of the PostSharpObject class. This method requires that you pass a PostSharpObjectSettings object. It allows you to determine whether PostSharp will share the current application domain or will create its own. 

When to use a Private Application Domain?

You should use a Private Application Domain when you do not want original assemblies to be loaded in the current application domain. If you use a private application domain, you will be able, after you do not need PostSharp any more, to unload it and all assemblies it contains.

For instance, we use a private application domain for the PostSharp MSBuild task, because we are not allowed to load into the MSBuild application domain assemblies that are being built. But for the console application, we can share the main application domain. In runtime scenarios, you will probably want to have a private application domain for security reasons (you do not want the woven code to 'see' the unwoven code).

The PostSharp Host

Conceptually, the PostSharp Host is the software component that instantiates and invokes the PostSharp Object. Technically, the PostSharp Host should implement the IPostSharpHost interface. This interface is invoked by the PostSharp Object principally when it does not know what to do with an assembly. 

The IPostSharpHost interface is useful when assemblies and loaded and processed dynamically as they are requested by the runtime engine. This is typically the case for runtime execution scenarios. In compile-time scenarios, there is no meaningful interaction between the PostSharp Platform and the host. That's why PostSharp provides a default implementation of the IPostSharpHost interface for compile-time scenarios.

Additionally to providing (even implicitly) a IPostSharpHost implementation, the host should register to the Message event of the Messenger class in order to propagate messages to the proper sink.

The Remote and the Local Host

The implementation of this interface resides in the host application domain. For this reason, taking from the point of view of PostSharp, it is called the remote host. If your host need to execute some logic in the PostSharp application domain, you need to implement a local host.

The local host resides in the PostSharp application domain and lays between the PostSharp Object and the remove host. The PostSharp Object never contacts directly the remote host. It goes always through the local host.

PostSharp provides a default implementation in the PostSharpLocalHost class. The default behavior is just to call the remote host. If you want to customize this behavior, you can derive this class and use the LocalHostImplementation property of the PostSharpObjectSettings class to tell PostSharp to use your class instead of the default one.

Custom local hosts can also be used to react to the events defined on the PostSharpObject.

Interaction between the Platform and the Host

The PostSharp Object has the possibility to process modules in deep-first order. That is, referenced assemblies are processed before referencing ones. If you start a program, all its dependencies would be processed fist and the program in itself would be processed as the last. 

This feature is useful when the transformation of an  assembly depends on a transformation or an analysis performed on dependencies, for instance if you want to modify public fields into properties.

Deep-first processing is enabled (for each module independently) by the ProcessDependenciesFirst property of the ProjectInvocationParameters class.

When deep-first processing is enabled, the Platform will contact the host for each dependency it finds and has no information about yet:

Assembly Renaming

If you use PostSharp to modify an assembly at runtime, you will probably need to change their identity. There are two good reasons:

For this reason, it is necessary to change the name of woven assemblies both in AssemblyManifestDeclaration and AssemblyRefDeclaration.

PostSharp can do it automatically if the OverwriteAssemblyNames property of the PostSharpObjectSettings object is set.

Order of Project Execution

When you process many modules in a single call of the IPostSharpObject.InvokeProjects method, tasks can be executed in different order.

First, remember that tasks are grouped in phases. The application-level configuration file standardly define four phases: load, analyze, transform and generate. All tasks that implement the Execute method should belong to one phase.

Say we have phases H1 ... H4 and projects P1 ... P7. Two orders of project execution are available:

The order of execution is influenced by the PostSharpObjectSettings.ProjectExecutionOrder property.