Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><strong>Let me start of by warning that if you wish to execute commands asynchronously in a web application, you might want to take a step back and look at what you are trying to achieve. There is always the risk of the web application being recycled just after you started your handler on a background thread. When a ASP.NET app gets recycled, all background threads will be aborted. It would perhaps be better to publish commands to a (transactional) queue and let a background service pick them up. This ensures that commands can't 'get lost'. And also allows you to re-execute commands when the handler does not succeed successfully. It can also save you from having to do some nasty registrations (which you will probably have no matter which DI framework you pick), but this probably just a side issue. And if you do need to run handlers async, at least try to minimize the number of handlers that you run async.</strong></p> <p>With that out of the way, what you need is the following.</p> <p>As you noted, since you are running (some) command handlers asynchronously, you can't use the per web request lifestyle on them. You will need a hybrid solution, that mixes between per web request and 'something else'. That something else will most likely be a <a href="http://simpleinjector.codeplex.com/wikipage?title=ObjectLifestyleManagement#PerLifetimeScope" rel="nofollow">per lifetime scope</a>. There are no built-in extensions for these hybrid solutions, because of a couple reasons. First of all it's quite an exotic feature that not many people need. Second, you can mix any two or three lifestyles together, so that would be almost an endless combination of hybrids. And last, it is (pretty) easy do register this yourself.</p> <p>In Simple Injector 2, the <code>Lifestyle</code> class has been added and it contains a <code>CreateHybrid</code> method that allows combining any two lifestyles to create a new lifestyle. Here's an example:</p> <pre><code>var hybridLifestyle = Lifestyle.CreateHybrid( () =&gt; HttpContext.Current != null, new WebRequestLifestyle(), new LifetimeScopeLifestyle()); </code></pre> <p>You can use this hybrid lifestyle to register the unit of work:</p> <pre><code>container.Register&lt;IUnitOfWork, DiUnitOfWork&gt;(hybridLifestyle); </code></pre> <p>Since you are registering the unit of work as Per Lifetime Scope, you must explicitly create and dispose a Lifetime Scope for a certain thread. The simplest thing to do is to add this to your <code>ThreadedCommandHandlerProxy</code>. This is not the most <a href="http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29" rel="nofollow" title="Wikipedia - SOLID">SOLID</a> way of doing things, but it is the easiest way for me to show you how to do this. </p> <blockquote> <p>If we had a problem within the command-handler/service-layer and didn't want to save the UnitOfWork, would we simply throw an exception?</p> </blockquote> <p>The typical thing to do is to throw an exception. It's in fact the general rule of exceptions: </p> <blockquote> <p>If your method can't do what it's name promises it can, throw. <a href="http://www.hanselman.com/blog/IfYourMethodCantDoWhatItsNamePromisesItCanThrow.aspx" rel="nofollow">-></a></p> </blockquote> <p>The command handler should be ignorant about how the context in which it is executed, and the last thing you want is to differentiate in whether it should throw an exception. So throwing is your best option. When running on a background thread however, you'd better catch that exception, since .NET will kill the whole AppDomain, if you don't catch it. In a web application this means a AppDomain recycle, which means you're web application (or at least that server) will be offline for a short period of time.</p> <p>On the other hand, you also don't want to lose any exception information, so you should log that exception, and probably want to log a serialized representation of that command with that exception, so you can see what data was passed in. When added to the <code>ThreadedCommandHandlerProxy.Handle</code> method, the it would look like this:</p> <pre><code>public void Handle(TCommand command) { string xml = this.commandSerializer.ToXml(command); Task.Factory.StartNew(() =&gt; { var logger = this.container.GetInstance&lt;ILogger&gt;(); try { using (container.BeginTransactionScope()) { // must be created INSIDE the scope. var handler = this.instanceCreator(); handler.Handle(command); } } catch (Exception ex) { // Don't let the exception bubble up, // because we run in a background thread. this.logger.Log(ex, xml); } }); } </code></pre> <p>I warned about how running handlers asynchronously might not be the best idea. However, since you are applying this command / handler pattern, you will be able to switch to using queuing later on, without having to alter a single line of code in your application. It's just a matter of writing some sort of <code>QueueCommandHandlerDecorator&lt;T&gt;</code> (which serializes the command and sends it to the queue) and change the way things are wired in your composition root, and you're good to go (and of course don't forget to implement the service that executes commands from the queue). In other words, what's great about this SOLID design is that implementing these features is constant to the size of the application.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload