During a workflow design session I noticed that sometimes using a classes design just based on inheritance is not enough and not as flexible as I expected. You can refer to a previous post to get some background Developing Tridion 2013 Workflows.
In that previous post I was reusing code by having an abstract class called BaseActivity and then creating more specialized classes like PublishActivity and RejectActivity that inherit from BaseActivity. This design allows me to reuse and to create specialized functionality for my activities.
There is a concept that I remember from my days studying computer engineering at the University (old and fun days) “Favor composition over inheritance” – Thanks Alvin Reyes for refreshing my mind. Why composition and why not inheritance, well Inheritance is not bad but if we can combine it with composition then we get an stronger result.
I decided to integrate an IoC Container to my workflow implementation so that I can instantiate my objects members (composition) at runtime, giving flexibility and scalability to my implementation. I used Ninject as my IoC container because it is light and easy to use.
Integrating Ninject with a Tridion Workflow Implementation
The following classes design clearly shows two classes hierarchies that are not linked and can be developed / extended independently.
![](data:image/png;base64,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)
In order to bind those two classes hierarchies I will use Ninject to inject dependencies at runtime based on the class composition.
Binding Activity Classes with Worker Classes
In that previous post I was reusing code by having an abstract class called BaseActivity and then creating more specialized classes like PublishActivity and RejectActivity that inherit from BaseActivity. This design allows me to reuse and to create specialized functionality for my activities.
There is a concept that I remember from my days studying computer engineering at the University (old and fun days) “Favor composition over inheritance” – Thanks Alvin Reyes for refreshing my mind. Why composition and why not inheritance, well Inheritance is not bad but if we can combine it with composition then we get an stronger result.
I decided to integrate an IoC Container to my workflow implementation so that I can instantiate my objects members (composition) at runtime, giving flexibility and scalability to my implementation. I used Ninject as my IoC container because it is light and easy to use.
Integrating Ninject with a Tridion Workflow Implementation
The following classes design clearly shows two classes hierarchies that are not linked and can be developed / extended independently.
In order to bind those two classes hierarchies I will use Ninject to inject dependencies at runtime based on the class composition.
Binding Activity Classes with Worker Classes
1. Declare loosely coupled links in the activity classes.
namespace Tridion.ContentManager.Spark.Workflow.Publish {
public class PublishToDraftActivity : BaseActivity {
protected Publisher publisher;
protected Notifier notifier;
}
}
Notice that I am declaring abstract types in order to avoid linking the activity class with a concrete implementation.
2. Declare a constructor that will receive concrete instances of abstract members.
namespace Tridion.ContentManager.Spark.Workflow.Publish {
public class PublishToDraftActivity : BaseActivity {
protected Publisher publisher;
protected Notifier notifier;
public PublishToDraftActivity(Publisher publisher, Notifier notifier) {
this.publisher = publisher;
this.notifier = notifier;
}
}
}
3. Define injection rules, in this implementation I am using a Ninject module, however you can use an XML file or Ninject naming conventions.
namespace Tridion.ContentManager.Spark.Workflow.Modules {
public class InjectionModule : NinjectModule {
public override void Load() {
Bind<Publisher>().To<StandardPublisher>();
Bind<Notifier>().To<EmailNotifier>();
}
}
}
The injection rules above will bind any Publisher reference to StandardPublisher and any Notifier reference to EmailNotifier. Here the beauty of Dependencies Injections, we can change bindings and it doesn’t affect the activities implementation. For instance we can decide to notify using Rss instead of sending an email, then we should change the binding to use RssNotifier instead of EmailNotifier.
Creating Activity Classes Instances – Linking all together at runtime.
In order to accomplish this I have created a new Workflow Script Executor that will use the Ninject Kernel to create instances instead of System.Reflection. You can get information about how to create your own Workflow Script Executor in this post Extending Workflow Scripts
The Ninject Kernel will instantiate Activity Instances and “Apply” the injection rules when the object is being constructed (the magic happens in the constructor).
External Activity Script
AssemblyTbbId = "tcm:2-49-2048"
Type = "Tridion.ContentManager.Spark.Workflow.Publish.PublishToDraftActivity"
private IExternalActivity GetExternalActivity(string script, bool isExpiration, string currentActivityInstanceId) {
IEnumerable<Match> matches = _nameValuePairRegex.Matches(script).Cast<Match>();
Match assemblyMatch = matches.FirstOrDefault(m => m.Groups["Name"].Value.ToUpperInvariant().Trim() == _assemblyTbbIdParam);
Match typeMatch = matches.FirstOrDefault(m => m.Groups["Name"].Value.ToUpperInvariant().Trim() == _typeParam);
TcmUri uri = new TcmUri(assemblyMatch.Groups["Value"].Value);
string typeName = typeMatch.Groups["Value"].Value;
StreamDownloadClient downloadChannel = new StreamDownloadClient(TcmConstants.LatestStreamDownloadNetTcpEndPointName);
FullVersionInfo fullVersionInfo = (FullVersionInfo)buildingBlockData.VersionInfo;
byte[] bytes = ReadContentBytes(downloadChannel.DownloadBinaryContent(uri));
Assembly assembly =
TemplateAssemblyCache.GetCachedAssembly(bytes, uri, new TcmUri(buildingBlockData.BluePrintInfo.OwningRepository.IdRef), fullVersionInfo.Version.Value, fullVersionInfo.Revision.Value);
Type type = assembly.GetType(typeName);
IKernel kernel = new StandardKernel();
kernel.Load(assembly);
return (IExternalActivity)kernel.Get(type, contextDataParameter);
}
The Kernel will execute the Injections Modules and will glue everything while the object is being constructed.
No comments:
Post a Comment