I’ve got controller code like this all over my ASP.NET MVC 3 site:
[HttpPost]
public ActionResult Save(PostViewModel viewModel)
{
// VM -> Domain Mapping. Definetely belongs here. Happy with this.
var post = Mapper.Map<PostViewModel, Post>(viewModel);
// Saving. Again, fine. Controllers job to update model.
_postRepository.Save(post);
// No. Noooo..caching, thread spawning, something about a user?? Why....
Task.Factory.StartNew(() => {
_cache.RefreshSomeCache(post);
_cache2.RefreshSomeOtherCache(post2);
_userRepository.GiveUserPoints(post.User);
_someotherRepo.AuditThisHappened();
});
// This should be the 3rd line in this method.
return RedirectToAction("Index");
}
Basically, i’m referring to the code in the threading block. All things need to happen, but the user doesn’t need to wait for them (good case for a background thread, right?).
Just to be clear, i use caching (regular ASP.NET data cache) all over the site, and most of this has a “no expire” cache policy, so i manually evict it when required (like the above).
And the user part is basically giving user rep for doing something (like Stack).
So let’s recap: we have caching, user reputation handling, auditing, all in one. Doesn’t really belong in one spot does it. Hence the problem with the current code, and the problem with trying to figure out how to move it away.
The reason i want to refactor this is for a few reasons:
- Difficult to unit test. Multithreading and unit testing doesn’t really play nice.
- Readability. It’s hard to read. Messy.
- SRP. Controller doing/knowing too much.
I solved 1) by wrapping the thread spawning code into an interface, and just mocking/faking that out.
But i would like to do some kind of pattern, where my code could look like this:
[HttpPost]
public ActionResult Save(PostViewModel viewModel)
{
// Map.
var post = Mapper.Map<PostViewModel, Post>(viewModel);
// Save.
_postRepository.Save(post);
// Tell someone about this.
_eventManager.RaiseEvent(post);
// Redirect.
return RedirectToAction("Index");
}
Basically, putting the onus on “something else” to react, not the controller.
I’ve heard/read about Tasks, Commands, Events, etc but have yet to see one implemented in the ASP.NET MVC space.
First thoughts would tell me to create some kind of “event manager”. But then i thought, where does this go? In the domain? Well then how does it handle interactions with the cache, which is an infrastructure concern. And then threading, which is also an infrastructure concern. And what if i want to do is synchronously, instead of async? What makes that decision?
I don’t want to have to just pile all this logic somewhere else. It ideally should be re factored into manageable and meaningful components, not shifted responsbility, if that makes sense.
Any advice?
It’s the way I solve the problem. I see the event manager as infrastructure. But the actual events belongs in the domain.
Async is nice, but makes transaction handling complex. If you use an IoC container you already have a well defined scope and a transaction which can be used during the event propagation.
imho it’s up to the subscriber to schedule/thread it’s task if it knows that it’s event handling will take time.
Proposed solution:
Use your IoC container to publish the events. I would let the repository publish the events (either
PostUpdatedorEntityUpdateddepending on what you want to do with the event) rather than the controller (to reduce code duplication).I’ve made an IoC implementation for autofac which allows you to:
Subscription:
https://github.com/sogeti-se/Sogeti.Pattern/wiki/Domain-events
Typical usage
ServiceResolver.Assign(new yourResolver(yourContainer))