c# - Console app with MVC, Ninject and WCF Service (Dispose issue?) -
i have mvc application ninject stuff wired properly. within application wanted add functionality call wcf service, sends bulk messages (i.e. bulk printing) rabbitmq queue .
a 'processor' app subscribes messages in queue , process them. want update stuff in database, want services , repositories mvc app available too.
the processor app implements following:
public abstract class kernelimplementation { private ikernel _kernel; public ikernel kernel { { if (_kernel != null) return _kernel; else { _kernel = new standardkernel(new repositorymodule(), new domainmodule(), new servicemodule(), new messagemodule()); return _kernel; } } } }
all ninject repository bindings specified within repositorymodule, used within mvc app , this:
bind<ireviewrepository>().to<reviewrepository>().incallscope();
the processor class
public class processor : kernelimplementation { private readonly ireviewprintmessage _reviewprintmessage; public processor() { _reviewprintmessage = kernel.get<ireviewprintmessage>(); [...] _bus.subscribe<reviewprintcontract>("reviewprint_id", (reviewprintcontract) => _reviewprintmessage.processreviewprint(reviewprintcontract)); //calling processreviewprint want repositories available } }
everything works fine until update database mvc app or database directly. processor app doesn't know changes , next time tries process something, works on 'cached' dbcontext. i'm sure it's not disposing dbcontext properly, i'm not sure scope should used console app (tried sort of different scopes no avail).
the solution can think of @ moment call wcf service processor app , perform necessary updates within service, want avoid that.
update: adding update logic
simplified reviewprintmessage:
public class reviewprintmessage : ireviewprintmessage { private readonly ireviewservice _reviewservice; public reviewprintmessage(ireviewservice reviewservice) { _reviewservice = reviewservice; } public void processreviewprint(reviewprintcontract reviewprintcontract) { var review = _reviewservice.getreview(reviewprintcontract.reviewid); [...] //do sorts of stuff here [...] _reviewservice.updatereview(review); } }
updatereview method in reviewservice:
public void updatetenancyagreementreview(tenancyagreementreview review) { _tenancyagreementreviewrepository.update(review); _unitofwork.commit(); }
repositorybase:
public abstract class entityrepositorybase<t> t : class { protected mycontext _datacontext; protected entityrepositorybase(idbfactory dbfactory) { this.dbfactory = dbfactory; _dbset = this.datacontext.set<t>(); } [...] public virtual void update(t entity) { try { datacontext.entry(entity).state = entitystate.modified; } catch (exception exception) { throw new entityexception(string.format("failed update entity '{0}'", typeof(t).name), exception); } } }
context bound this:
bind<mycontext>().toself().incallscope();
from description of scopes thought transient scope right choice, said earlier tried sorts including requestscope, transientscope, namedscope , singleton (although knew wouldn't desired behaviour), none of them seem disposing context properly.
what you'll need 1 dbcontext
instance per transaction. other "applications" web-applications or wcf-service may doing 1 transaction per request (and use inrequestscope()
. note, these application create object graph each request. however, concept unknown console application.
furthermore, scoping affects instantiation of objects. once instantiated, scoping not have effect on them.
so 1 way solve issue create (relevant) object tree/graph per transaction , use incallscope()
(incallscope means "once per instantiation of object graph", see here). mean you'd need factory ireviewprintmessage
(have @ ninject.extensions.factory) , create instance of ireviewprintmessage
every time want execute ireviewprintmessage.processreviewprint
.
now have re-created "per request pattern".
however, regarding compositionroot not recommended.
alternative: can re-create dbcontext
needed. instead of passing around everywhere (dbcontext
additional parameter on every method) use synchronizationcontext
local storage (or if don't use tpl/async await
: threadlocal
). i've described method in more detail here
Comments
Post a Comment