c# - How to make async with linq -
i'm trying make first web application asp.net mvc including remote database linq. i'm using default template mvc, i've remade code in accountcontroller implement register users using linq, , i'm interesting async. possible handle linq async? , if yes, show me please example how that, helpful me. here's example of registration via linq:
[allowanonymous] public actionresult register() { return view(); } // // post: /account/register [httppost] [allowanonymous] [validateantiforgerytoken] public actionresult register(registerviewmodel model) { if (modelstate.isvalid) { using (databaseclassdatacontext dc = new databaseclassdatacontext()) { users tbusers = new users(); tbusers.login = model.login; tbusers.name = model.name; tbusers.surname = model.surname; tbusers.password = model.password; tbusers.e_mail = model.email; tbusers.knowledge = model.knowledge; dc.users.insertonsubmit(tbusers); dc.submitchanges(); modelstate.clear(); viewbag.message = "successfully registration done"; } } // if got far, failed, redisplay form return view(model); }
let's @ first action first:
[allowanonymous] public actionresult register() { return view(); }
well, there's nothing here delay current thread, there's no benefit in doing asynchronously, best thing leave 1 alone.
now, let's @ second action. contains:
dc.submitchanges();
that indeed block current thread while changes sent database. won't big hit, somewhere might benefit using asynchronous code, because it's darn easy these days.
first change signature:
public async task<actionresult> register(registerviewmodel model)
if compile work, you'll warning:
async method lacks 'await' operators , run synchronously. consider using 'await' operator await non-blocking api calls, or 'await task.run(...)' cpu-bound work on background thread.
but we've done 2 things:
- changed returning
actionresult
returningtask<actionresult>
. - used
async
mean canreturn view(model);
, gets turned code returnstask<actionresult>
when run run code in original method.
but we've not gained anything. instead of dc.submitchanges()
we'll use dc.submitchangesasync()
.
this assuming exists, depend on data provider. more on in bit.
if exist instead of returning void
or value t
return task
or task<t>
.
we could write code handle task ourselves, easiest thing is:
await dc.submitchangesasync();
now method have 1 returns task<action>
when run
(mvc handle bit us) execute code far await
. release thread running code other things. after submitchangesasync
has done job, execution of method resumes @ point.
similarly turn method like:
var somelist = somequery.tolist();
into:
var somelist = await somequery.tolistasync();
now, said, depends on methods result in database access having async version. if there no submitchangesasync()
either have give on approach (boo!) or have write own implementation (not trivial).
the current version of entityframework provides following:
allasync anyasync averageasync containsasync countasync firstasync firstordefaultasync foreachasync loadasync longcountasync maxasync minasync singleasync singleordefaultasync sumasync toarrayasync todictionaryasync tolistasync savechangesasync
that is, pretty of methods result in actual database access have async
version.
if not using provider offers this, moving asynchronous code not easy; it'll involve more can put quick answer well.
one final caveat. have async
method single await
, await
tail-call:
public async task<list<int>> getlist(int typeid) { if(typeid < 1) throw new argumentoutofrangeexception(); return await (from stuff in place stuff.typeid == typeid select stuff).tolistasync(); }
here should not use async
, await
@ all, because creating task result in single task being awaited on, , await
complicates things behind scenes no reason. here should return task:
public task<list<int>> getlist(int typeid) { if(typeid < 1) throw new argumentoutofrangeexception(); return (from stuff in place stuff.typeid == typeid select stuff).tolistasync(); }
but note looks tail call inside using
block not tail call, because implicitly dispose()
@ end of using
, can't simplify such calls in way.
you can though simplify cases there different possible tail calls, long every path either such call, or throws exception:
public async task<list<int>> getlist(int? typeid) { if(!typeid.hasvalue) throw new argumentnullexception(); if(typeid.value < 0) return await (from stuff in place).tolistasync(); return await (from stuff in place stuff.typeid == typeid select stuff).tolistasync(); }
can become:
public task<list<int>> getlist(int? typeid) { if(!typeid.hasvalue) throw new argumentnullexception(); if(typeid.value < 0) return (from stuff in place).tolistasync(); return (from stuff in place stuff.typeid == typeid select stuff).tolistasync(); }
Comments
Post a Comment