Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <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>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. COThanks Steven, your comment on having a background service run everything may be exactly what i am looking for without any other issue of concerns about threads or registration - by 'service' just to clarify could we have the QueueCommandHandlerDecorator write the job to the database (or a WCF web service, or some other inter-process communication method), and have an entirely seperate process (write a second program as a windows service or WCF service) running that picks these job requests up and processes them? Thanks for the great insight into design and avoiding pitfalls.
      singulars
    2. CO@g18c: You can use whatever queue you like best (database, MSMQ), and you can write to your queue in any way you like (directly from within the MVC, or let a WCF service write to the queue), but for picking commands from the queue and executing them, it would be best to use a Windows Service. Or at least, don't use a web service, since in that case you'll face the same problems with app domain recycling as you are already having with your web application. Web services are not meant do deal with background processing. They are for handling requests. Good luck.
      singulars
    3. COGreat stuff, in addition to my existing MVC app I will use my common service/contracts class library with a new windows service that registers required commands in a Simple Injector container (with per thread or perlifetime scope) - since database access is transactional and handled by the container I can easily queue tasks in a jobs to run table without worry of race conditions as the service can poll this table for new records. This design methodology is very powerful as the services are instantly useable regardless of MVC app or Windows Service - many thanks greatly appreciate it.
      singulars
 

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