Using async/await from within DataPortal_XYZ methods

Using async/await from within DataPortal_XYZ methods

Old forum URL: forums.lhotka.net/forums/t/11431.aspx


pcanada posted on Monday, June 25, 2012

In CSLA 4.5.1 (alpha) is it safe (or would it have the expected behavior) if you used await from within DataPortal_Fetch or DataPortal_Update/etc?

In my particular case, the business objects retrieve and store all their data from a WCF service, in a service-oriented architecture (NOT using WCF data portal).

It has been recommended to call WCF service methods using the task-based async pattern with the await keyword, so the calling thread is not blocking while waiting for a response. This leads to having the await keyword in the DP_XYZ methods, but I wonder if the rest of the internal code between the DataPortal.FetchAsync<T>() call and the execution of the DataPortal_Fetch() is designed to handle the await symantics.

From my understanding, when it gets to the await, it will likely exit the DP_XYZ method prematurely and return to the previous caller(s) on up the stack, but a brief review of the CSLA code made me think that in order to properly work with the await keyword, the one who called DP_XYZ would need to also await (or .Wait()) for the results. I did not see such support there, and I think the calling code would continue on without the DP_XYZ method having fully done its job, especially if the await occurred in a DataPortal_Update() where a new BO needs to be returned using data that we are still waiting on from the wcf service (and what if the wcf service call fails).

 

RockfordLhotka replied on Tuesday, June 26, 2012

I am trying to figure out exactly how to approach this problem, yes.

One solution is to change the method signature of DataPortal_XYZ methods to return a Task object. This is probably the ideal solution, except that it would be a breaking change for over 99% of all existing CSLA code...

So I'm researching ways to avoid making such a drastic change...

Btw, I DO plan to make that change for the local Silverlight and WinRT data portal implementation. The amount of local data portal code on Silverlight is comparatively low, and of course there's none on WinRT yet, so the impact is relatively low and the benefit quite high.

pcanada replied on Tuesday, June 26, 2012

For what its worth, we are using full .NET and would certainly benefit from Task based support throughout CSLA.

The data portal sure is getting messy as I read in another post ( http://forums.lhotka.net/forums/t/11428.aspx ). Perhaps it has come to the point of needing separate a separate .dll for each dataportal/platform. It seems that the 'noise' is just going to get worse for the next few years until we can all target Win8/RT in our apps.

RockfordLhotka replied on Tuesday, June 26, 2012

I absolutely intend to support async/await at the DataPortal_XYZ level - don't let my rambling thoughts mislead you as to my intent :)

We already do create a different Csla.dll for each platform, so the noise is actually pretty minimal. For example, WP7 only sees the event-driven async options (BeginFetch, etc) because nothing else works there.

The one platform that sees everything (all three options) is full .NET, because all three options are perfectly valid on full .NET.

I could arguably drop the sync and event-driven versions in 4.5, but that would mean breaking backward compatibility - preventing people from easily moving to .NET 4.5 just for the sake of "purity".

Now I might eliminate the sync and event-driven options in CSLA 5, as that would give people substantial warning of the upcoming change. But I won't do it in 4.5 because I can't now provide sufficient advance notice, nor is there a true pressing need to create such a breaking change.

pcanada replied on Wednesday, June 27, 2012

What if a new attribute was introduced, very similar to the RunLocal attribute, maybe RunLocalAsync? This could cause new DataPortal (and related) classes to be instantiated which are async/await aware so it doesn't break backward compatibility.

The desire to use async/await on the "server" side really only applies when you are running the dataportal locally without a server. Doing async data access from an actual server might be more trouble than its worth.

Can you think of any other workaround? Seems like I might be able to do asynchronous data access using the ObjectFactory approach, but is there any similar overload that takes a callback for non-object factory implementations? Our current project targets .NET 4.5 specifically so that we can take advantage of some of its new features.

RockfordLhotka replied on Wednesday, June 27, 2012

I can do better than that to be sure. I can detect whether the method returns a Task<T> and can do an await in that case.

What I'm struggling with right now is what to define as T. The methods are currently void, and the data portal needs no return value at all, so I don't really need a T at all except to enable the await keyword. So I'm considering making T be type object and you can return a null or whatever - but it will be ignored.

From what I can see T needs to be a fixed type, because I haven't been able to figure out how to cast object to a Task<T> where I don't know T until runtime. But if I hard-code T as a type, then it works fine.

pcanada replied on Wednesday, June 27, 2012

Couldn't the methods just return the non-generic Task? I believe you can await on that as well. Even though it looks funky in code:

 

await dp.Fetch();

RockfordLhotka replied on Saturday, June 30, 2012

Yes, this seems to be the best overall solution. I have a prototype of this working, and need to merge it into the actual data portal.

My prototype auto-detects whether your method is void or returns Task, and therefore does an await when appropriate. This should allow for backward compatibility with existing code, while at the same time allowing some/all of your methods to switch to being async (as long as they return Task).

Copyright (c) Marimer LLC