c# - Can this MVC code be refactored using a design pattern? -
i've got controller code on asp.net mvc 3 site:
[httppost] public actionresult save(postviewmodel viewmodel) { // vm -> domain mapping. definetely belongs here. happy this. var post = mapper.map<postviewmodel, post>(viewmodel); // saving. again, fine. controllers job update model. _postrepository.save(post); // no. noooo..caching, thread spawning, user?? why.... task.factory.startnew(() => { _cache.refreshsomecache(post); _cache2.refreshsomeothercache(post2); _userrepository.giveuserpoints(post.user); _someotherrepo.auditthishappened(); }); // should 3rd line in method. return redirecttoaction("index"); }
basically, i'm referring code in threading block. things need happen, user doesn't need wait them (good case background thread, right?).
just clear, use caching (regular asp.net data cache) on site, , of has "no expire" cache policy, manually evict when required (like above).
and user part giving user rep doing (like stack).
so let's recap: have caching, user reputation handling, auditing, in one. doesn't belong in 1 spot it. hence problem current code, , problem trying figure out how move away.
the reason want refactor few reasons:
- difficult unit test. multithreading , unit testing doesn't play nice.
- readability. it's hard read. messy.
- srp. controller doing/knowing much.
i solved 1) wrapping thread spawning code interface, , mocking/faking out.
but kind of pattern, code this:
[httppost] public actionresult save(postviewmodel viewmodel) { // map. var post = mapper.map<postviewmodel, post>(viewmodel); // save. _postrepository.save(post); // tell this. _eventmanager.raiseevent(post); // redirect. return redirecttoaction("index"); }
basically, putting onus on "something else" react, not controller.
i've heard/read tasks, commands, events, etc have yet see 1 implemented in asp.net mvc space.
first thoughts tell me create kind of "event manager". thought, go? in domain? how handle interactions cache, infrastructure concern. , threading, infrastructure concern. , if want synchronously, instead of async? makes decision?
i don't want have pile logic somewhere else. ideally should re factored manageable , meaningful components, not shifted responsbility, if makes sense.
any advice?
first thoughts tell me create kind of "event manager". thought, go? in domain?
it's way solve problem. see event manager infrastructure. actual events belongs in domain.
well how handle interactions cache, infrastructure concern. , threading, infrastructure concern. , if want synchronously, instead of async? makes decision?
async nice, makes transaction handling complex. if use ioc container have defined scope , transaction can used during event propagation.
imho it's subscriber schedule/thread it's task if knows it's event handling take time.
proposed solution:
use ioc container publish events. let repository publish events (either postupdated
or entityupdated
depending on want event) rather controller (to reduce code duplication).
i've made ioc implementation autofac allows to:
domaineventdispatcher.current.dispatch(new entityupdated(post));
subscription:
public class cacheservice : iautosubscriberof<entityupdated> { public void handle(entityupdated domainevent) {}; }
https://github.com/sogeti-se/sogeti.pattern/wiki/domain-events
typical usage
- implement iserviceresolver (for container)
- assign it:
serviceresolver.assign(new yourresolver(yourcontainer))
- use described here.
Comments
Post a Comment