I'm new to async calls and face an issue I can't find a solution for.
I have a class library I'm calling from a CRM software. The CRM application sends XML data at the beginning and it expects XML to be returned from the library if the screen data should be updated by the library.
In the library I'm calling a function and this functions calls another function and
the third function in that row is an async function with an await get call.
Here is an overview about the structure. When
public string[] Function1(string sXmlDoc)
{
//...
Function2(par1, par2);
//Returns to here from Async Call in Function 3
return xml;
}
public void Function2(string par1, string par2)
{
//...
Function3(par3);
//...
}
public await void Function3(string par3)
{
//...
//When it arrives here it jumps back to the first function
byte[] fileBytes = await httpClient.GetByteArrayAsync(uri);
//and after jumping back it comes back to here.
//...
}
I hope it is clear what I mean. The problem is that the jump back returns already the xml
string to the CRM application. But in that xml I need data from the async call.
How to achieve that ? Any ideas ?
Thanks a lot in advance
Michael
Related
I am currently developing a simple c# formflow bot that captures the values and sends those values off to an external api, gets the json data back from the external api and creates Card Attachments based on the results returned. I am making the call to the external api in the OnCompletion delegate as follows, To keep it simple I am not passing any values to the api (For testing purposes)
.OnCompletion(async (context, profileForm) =>
{
var reply = context.MakeMessage();
var carsFromApi = await GetCarsAsync("/api/values");
reply.AttachmentLayout = AttachmentLayoutTypes.Carousel;
reply.Attachments = GetCards(carsFromApi);
await context.PostAsync(reply);
// Tell the user that the form is complete
})
I make the call to the api and store the results in "carsFromApi" , I step into that which is the following code snippet
private static async Task<List<Car>> GetCarsAsync(string path)
{
List<Car> car = new List<Car>();
HttpResponseMessage response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
car = await response.Content.ReadAsAsync<List<Car>>();
}
return await response.Content.ReadAsAsync<List<Car>>();
}
Problem is when I press F10 and go to the next line which is "reply.AttachmentLayout = AttachmentLayoutTypes.Carousel;". The local variable that stored the cars "carsFromApi " is now null. This is the part where it all falls over. I cant pass this "carsFromApi" to "reply.Attachments = GetCards(carsFromApi);" I have tried to store the data in a private variable but that also seems to be null. The external api is working because it just returns a list of static text for now. Any ideas? Thanks in advance.
Based on what you are describing it sounds that your code is not existing through the path of the if (response.IsSuccessStatusCode). Check if that point is reached as I suspect an exception or something is going wrong with the request.
Alternatively, you can try doing the request in the ResumeAfter<T> method you specified when calling the Form instead of that in the OnCompletion delegate
The Situation
I'm working on a OAuth2 Api Wrapper. Some api routes are for logged people and some for anonymous and logged.
Here is an example of one method in my wrapper :
public async Task<UploadListResponse> List(bool pagination = false, int page = 1, int limit = 10)
{
var request = UploadRequests.List(pagination, page, limit);
var cancellationTokenSource = new CancellationTokenSource();
var restResponse = await Context.Client.ExecuteTaskAsync(request, cancellationTokenSource.Token);
return restResponse.Handle<UploadListResponse>();
}
I build a request with all parameter set up then execute the request and then handle the answer in case I have an api error and then output an object containing all the data that request gave me.
The problem
With OAuth2, when you log to the API you'll receive an access token and a refresh token. If your access token is expired you have to contact the api with your refresh token to get a fresh new access token.
As I said earlier some of my method needs you to be logged but if your access token is expired I want to try to refresh token before throwing an exception like with this method :
public async Task<bool> NeedRelog()
{
try
{
var validAuth = await ValidAuth();
}
catch
{
try
{
var refresh = await Refresh(Context.Client.Config.RefreshToken);
}
catch
{
return true;
}
}
return false;
}
ValidAuth check with the API if you are logged and if I have an exception then I'll try to refreshToken.
I want to tag method that need logged to call NeedRelog() and those who aren't tag to not call it.
I may just do it in every method but it wouldn't be clean.
What I've done so far
I've found a great tool : PostSharp that seems to fit my needs.
I've started to do a checkLog aspect like this :
[Serializable]
public class CheckLog : OnMethodBoundaryAspect, IOnStateMachineBoundaryAspect
{
public CheckLog()
{
ApplyToStateMachine = false;
}
public override void OnEntry(MethodExecutionArgs args)
{
var instance = (ApiService)args.Instance;
var res = instance.Parent.OAuth.NeedRelog().Result;
if (!res)
{
args.Exception = new Exception("Need to relog");
args.FlowBehavior = FlowBehavior.Return;
}
}
}
Where I'm stuck
The Main problem is with the call to my NeedRelog() Method. Due to the fact this is an async method I'm struggling to make my aspect await for it.
If my OnEntry method is async then It won't block the call if you are not logged.
If my OnEntry method is not async and I wait for needLog it freeze and nothing happen.
I really want to know to use this kind of "conditional method call" with postsharp, it looks awesome but the fact is after looking for hours in the documentation I didn't find a way to do what I want.
I'm starting to ask myself if it is even possible to achieve what I'm aiming to do.
Did you try using a way to make the call synchronous maybe with something like this stackoverflow.com/a/25097498/3131696 ? – M22an 5 hours ago
As I can't mark a comment as answering a question I quote your comment to make this question answered as it is said here : link
Thanks you for this M22an.
How to get the value of a returned value from an async from an external function in PowerBuilder? I made a simple example in VB2013 .NET 4.5 and compiled it as a DLL. And inside the DLL is an async method like so:
test.DLL
public async Task<string> GetTestAsync()
{
Task<string> task = GetTest();
string test = await task;
return test;
}
public async Task<string> GetTest()
{
string test;
test = "TEST";
return test;
}
and I have called the DLL in PowerBuilder like so:
String test
test = String(myoleobject.GetPortsTestAsync())
if isnull(test) then
messagebox('', 'null value')
end if
The result always returns a null value.
I've also tried this one, but it still returns a null value.
public Task<string> GetTestAsync()
{
return Task.Factory.StartNew(() =>
{
return "hello";
});
}
You'll need to perform a callback from your DLL to PowerBuilder.
I assume that because you call a method of "myoleobject" that you are using oleobject.
If that is the case, here is something to try.
In VB
Create an OLE event
Set the value
Trigger the event
In PowerBuilder
Inherit an OLEOBJECT
Create an event that corresponds to the VB OLE event
Get the value.
You might need to get creative here, the only thing that jumps out at me is to set a property in your VB control that informs your PB application that a value is ready. The problem is that you are forced to poll the VB application constantly.
Another option is to hold-up PB when the function is called in VB, but it totally defeats the purpose of an async function. Wish I could help more been a while since I've done anything like this.
The snippet below is from a Windows 8 store app in c# and xaml.
I have put this code together from variou samples on the web so this may not be the neatest way of doing this. Most of it is from the Grid template supplied in VS2012 and I have hooked up my web api as the source of the data
Please explain the following
When i call the Get method all works fine and i get data back into the xaml view
When i uncomment the Take(10) in the same method i get no data back.
It seems any attempt to put an extension method of a LINQ variety just stops the data being returned and also gives no indication why, it complies fine!
Any help appreciated
Thanks
Mark
public class TeamDataSource
{
private static TeamDataSource _sampleDataSource = new TeamDataSource();
private ObservableCollection<TeamDataItem> _items = new ObservableCollection<TeamDataItem>();
public ObservableCollection<TeamDataItem> Items
{
get { return this._items; }
}
public TeamDataSource()
{
this.Initialize();
}
public static IEnumerable<TeamDataItem> Get()
{
var thisdata = _sampleDataSource.Items;
return thisdata;//.Take(10);
}
private async void Initialize()
{
using (var client = new DataServiceClient())
{
List<TeamDataItem> list = await client.Download<List<TeamDataItem>>("/teams");
foreach (var i in list.OrderByDescending(t => t.Points).ThenByDescending(t => t.GoalDiff))
{
TeamDataItem team = i;
_items.Add(team);
}
}
}
}
Your problem is that Take doesn't immediately enumerate the items. It defers enumeration until either foreach is called on it or GetEnumerator is called on it. In this case the collection it is enumerating is disposed (as soon as the Get content ends) and so when it finally enumerates the items, there are no items anymore. Try adding thisdata.GetEnumerator(); as a line before your return statement.
From here:
This method is implemented by using deferred execution. The immediate
return value is an object that stores all the information that is
required to perform the action. The query represented by this method
is not executed until the object is enumerated either by calling its
GetEnumerator method directly or by using foreach in Visual C# or For
Each in Visual Basic.
Seems it was quite obvious in the end. As I was using aync and await, the call was immediately returning before the data had arrived. Therefore nothing for the Take(4) to work on.
Only problem now is when can i tell the task has completed?
I have two methods in a C# business logic class. I need a flag mechanism so that one method can update the flag and the other method will react when the flag is updated. Below I will paste my situation, which is very simple:
// BusinessLogic.cs
bool photoResizingFinished = false;
public int SavePhoto() {
while (!photoResizingFinished) {
System.Threading.Thread.Sleep(100);
Trace.TraceInformation("PhotoResizingWorkerRole has not finnished yet.");
} }
public bool UpdateStatus(bool statusUpdate) {
photoResizingFinished = statusUpdate;
return true;
}
The two methods above live in the same class BusinessLogic.cs.
The only thing I need is to be able to have SavePhoto() react when
the bool photoResizingFinished is updated by UpdateStatus(bool statusUpdate)
You can use the class as a webservice and implement callback function that called when the ws finishes its work.
example code:
<script>
var timerID = setTimeout(CallWS, 1000)//call a js func which calls the WevService
function CallWS()
{
clearTimeout(timerID)//to stop the calling...
WSClassName.WSFuncName(param1,param2,....,callBackSuccess,callBackFailur)
///the param1,param2 are according to the parameter the function is expected to get.
}
function callBackSuccess(result,eventArgs)
{
//When the WS function finished successfuly
//**set flag to true.**
}
function callBackFailur(result,eventArgs)
{
//when error occured in the WS function
alert(result.get_message()).
}
</script>
Let me know if you need more help...
goodluck!
You could try using the Task class from .Net 4. It allows you to queue up tasks, so your SavePhoto() code would wait until the PhotoResizing() method finished.
Here's a nice article on the Task namespace if you want more details: http://www.codethinked.com/net-40-and-systemthreadingtasks
using System.Threading.Tasks;
public void SavePhoto(CancellationTokenSource taskCancellationTokenSource){
// preliminary code
// start resize
Task resizeTask = Task.Factory.StartNew( ResizePhoto, taskCancellationTokenSource ) ;
// queue up final save method
Task finalTask = resizeTask.ContinueWith(t => {
if (!t.IsFaulted && !t.IsCancelled){
FinishSaving();
}
});
// Wait for everything to finish
finalTask.Wait(taskCancellationTokenSource);
}
public void ResizePhoto(){
// code
}
public void FinishSaving(){
// code
}
I'd change the bool like this:
bool _photoResizingFinished=false;
bool photoResizingFinished
{
get{return _photoResizingFinished;}
set
{
if(value) SavePhoto();
_photoResizingFinished=value;
}
}
Or, you can make UpdatePhoto() call SavePhoto() after updating the bool. Might be a better solution.
Maybe I have found a solution to my problem using a Multithreaded Singleton
http://msdn.microsoft.com/en-us/library/ff650316.aspx
Here are some attempts of implementation:
http://forums.asp.net/t/1783765.aspx/2/10?How+to+have+two+methods+of+the+same+class+flag+to+eachother+
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/abd53523-658b-442a-bac0-1c74c1d90a90
I don't understand the mecanics of this myself totally, but I hope it's ok.