0

Net 4.5 Task-based Asynchronous Pattern (TAP) using web forms and user controls There seems to some tricky differences between webforms, winforms, WCF and MVC approaches. So far I have: In my <%@ Page Async="true"

In Web Config: appSettings - add key="aspnet:UseTaskFriendlySynchronizationContext" (This means I can use Tasks without having to register them in my page?)

My User control will call a web service to get a User profile based on a Membership Number. In my User Control I want to display a progress bar while the long running process proceeds. Since the actual length of the call will always be undetermined the timing of the progress bar will be a little faked (Currently 10 seconds to complete the task). I tried to use the Task IProgress reporting but I found it would only report the start and the end of the process in webforms, not intermediate steps, so I created a Javascript reporter for the UI and call ajax to a fake status processor. My Ajax responds with a % complete in a custom Response.AppendHeader(ProgressStatus, value);

So System.Web.HttpResponse HttpContext.Current is key to this but when I run my Task, HttpContext.Current gets blocked and the prog bar starts after the Task is complete. I Can't see where the Thread gets blocked?

Here is some code: UserControl.ascx.cs

protected void Page_Load(object sender, EventArgs e)
    {
        Response.AddHeader("cache-control", "no-cache");
        if (!Page.IsPostBack)
        {
            InitialiseControl();
        }
    }

public async void InitialiseControl() // Its an event
    {
    // wait for a command from the ajax
    if (Request["startTask"] != null)
            {
        //..do some progress stuff
        await GetUserProfileAsync(request.MembershipNumber);
        //..Report back to the UI
    }

    if (Request["getStatus"] != null)
            {
        //..polling from the ajax, continue with progress reporting back to the UI
    }
}

// we are still in HttpContext.Current so add object to session
    private async Task  GetUserProfileAsync(string membershipNumber)
    {
        UserProfile profile = 
    await WebApplication.Library.Methods.Membership.UserProfile.GetUsersProfileTaskAsync(membershipNumber);
        HttpContext.Current.Session["UserProfile_" + membershipNumber] = profile;
    }

WebApplication.Library.Methods.Membership.UserProfile:

    public async static Task<UserProfile> GetUsersProfileTaskAsync(string usersMembershipNumber)
    {
        Task<UserProfile> t = new Task<UserProfile>
        (
            () =>
            {
                UserProfile profile = new UserProfile() { Name = "Some name", 
            Password = "TestPassword", 
            MembershipNumber = usersMembershipNumber };
                return profile;
            }
        );

        // start the task
        t.Start();

        int i = 0;
        for (i = 0; i < 8; i++)
        {
            // Fake delay simulating a web service
            Thread.Sleep(1000);
        }

        if (i == 8)
        {
            return await t;
        }
        return null;
    }

Hi Stephen thanks for your reply. "I hope by this that you mean it sends a complete response" My JavaScript picks up the response as a full header returned: xmlhttp.getResponseHeader("ProgressStatus");

However Im not even sure my code is running asyncly. If I try to register my Task on Page Load:

this.Page.RegisterAsyncTask(new PageAsyncTask(() => GetUserProfileAsync(membershipNumber))); (does this approach refer to the legacy usage for Async? and not the 4.5 Task usage)

I get Error: Task-returning Page methods are unsupported in the current application configuration. To work around this, remove the following configuration switch in Web.config: add key="aspnet:UseTaskFriendlySynchronizationContext"

When I remove the switch: System.InvalidOperationException: An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%@ Page Async="true" %>. This exception may also indicate an attempt to call an "async void" method, which is generally unsupported within ASP.NET request processing. Instead, the asynchronous method should return a Task, and the caller should await it.

This error occurs at InitialiseControl();

I think the first thing is to prove we can do async in a UserControl. This is the first time I have used any Async stuff and I have spent a lot of time watching the fantastic videos made by Lucian Wischik, but he never really covers webforms (which I have to use since my company will not move to MVC).

0

1 Answer 1

1

In Web Config: appSettings - add key="aspnet:UseTaskFriendlySynchronizationContext" (This means I can use Tasks without having to register them in my page?)

No; it means you can use async and await. More info.

In my User Control I want to display a progress bar while the long running process proceeds.

async won't help you here. The easiest approach is to use SignalR, which has built-in support for progress updates.

I created a Javascript reporter for the UI and call ajax to a fake status processor.

AJAX is an appropriate alternative solution.

My Ajax responds with a % complete in a custom Response.AppendHeader(ProgressStatus, value);

I hope by this that you mean it sends a complete response, not just flushing headers to your JavaScript.

I Can't see where the Thread gets blocked?

What I suspect is happening is that the session state is preventing the second request; see the "Concurrent Requests" section of the Session State Overview.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.