Ticket T744098
Visible to All Users

Use async await in Action.Execute to fetch a NonPersistent object in XAF.Web

created 6 years ago

Hi Folks!

I'm currently working on a project with an external Web-API. It supports both Win and Web. You know my knowledge with XAF.Web is not that advanced.
So basically the question is, how to use async await (or any task based api) in a controller for win and web:

C#
private async void FetchRemoteObject_Execute(object sender, SimpleActionExecuteEventArgs e) { View.CurrentObject = null; var httpClient = new HttpClient(); var response = await httpClient.GetAsync("/api/foo"); if(response.IsSuccessStatusCode) { var payload = JsonConvert.DeserializeObject<MyObject>(await response.Content.ReadAsStringAsync()); View.CurrentObject = payload; } }

This will work fine in a win project (cause we have an SynchronizationContext) but not for an web appication. What's the easiest solution to make this in web work? I've found the following docs in MSDN but have to clue where to put that registration logic in a web application. Would be cool if I don't need to duplicate the code for win and web.

https://docs.microsoft.com/en-us/aspnet/web-forms/overview/performance-and-caching/using-asynchronous-methods-in-aspnet-45

Kind regards,
Manuel

Answers approved by DevExpress Support

created 6 years ago (modified 6 years ago)

Hello Manuel,

Thank you for contacting us. XAF WebForms support only the synchronous approach. So, you can use a synchronous API or the Task.Run(() => <async method>).Result construction to wait till the task is executed, for example:

C#
private void FetchRemoteObject_Execute(object sender, SimpleActionExecuteEventArgs e) { View.CurrentObject = null; var httpClient = new HttpClient(); var response = Task.Run(() => httpClient.GetAsync("/api/foo")).Result; if(response.IsSuccessStatusCode) { var payload = JsonConvert.DeserializeObject<MyObject>(Task.Run(() => response.Content.ReadAsStringAsync()).Result); View.CurrentObject = payload; } }

I hope you find this information helpful.

Thanks,
Ilya P

    Comments (2)
    MG MG
    Manuel Grundner 6 years ago

      Wouldn't this deadlock?

      DevExpress Support Team 6 years ago

        You are right, there is potential deadlock. Wrap the async method call with the Task.Run method to avoid it. I have updated the answer accordingly.

        Other Answers

        created 6 years ago (modified 6 years ago)

        After some thinking i came to the conclusion that is possible the best thing to write a helper function with an ManualResetEvent. It's ugly, and not cross platform yet, (cause I don't want it to block on winforms). But here is a proof of concept code:

        C#
        public static class AsyncExtensions { public static T WaitForResult<T>(this Task<T> task, int? delay = null, CancellationToken cancellationToken = default) { var result = default(T); Exception exception = null; var @event = new ManualResetEvent(false); task.ContinueWith(t => { if(t.IsCanceled) { exception = new OperationCanceledException(); @event.Set(); return; } if(cancellationToken.IsCancellationRequested) { exception = new OperationCanceledException(); @event.Set(); return; } if(t.IsFaulted) { exception = t.Exception.InnerException; @event.Set(); return; } if(t.IsCompleted) { result = t.Result; @event.Set(); return; } }); if(delay.HasValue) { if(!@event.WaitOne(delay.Value, false)) { throw new TimeoutException(); } } else { @event.WaitOne(); } if(exception != null) { throw exception; } return result; } }

        I will write a blog post on this, and link it here afterwards.
        Thanks for your help Ilya

          Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

          Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.