2

In an ASP.Net project I recently changed some lengthy functions to async. This has turned out to cause some unexpacted problems.

Basically the functions are working when using await, but having to call it from another async function end up being an issue in the form. So far I set page directive Async to true and used RegisterAsyncTask to initiate calls to async functions. The call works. But it turns out when I have Async page directive enabled, the user context sometimes changes.

To imposonate the calling user for all code in certain pages, I have inherited the class System.Web.UI.Page to ImpersonatedPage. In my class I use OnLoad to imporsonate the calling user. This way I am certain user can never see or do any more then he/she has access to already, and audit logs shows the correct user.

When Async page directive enabled it still impersonates the user. But for example in the code for a button click, user context is suddently back to the application pools context. In Page_Load the user context is the calling user as expected. What is causing this, and is it possible to avoid switching back to the application pool user?

Alternatively I tried removing the Async page directive, and calling the async function by using Task.Run. Then the user context does not switch back, but instead HttpContext.Current is null and the async function is not able to do it's work.

Any other ways to call async function from ASP.Net without having to enable Async page directive?

Target Framework: 4.6.1 AFAIK no quirks enabled

ImpersonatedPage class:

public class ImpersonatedPage : System.Web.UI.Page
{
    WindowsImpersonationContext m_wic = null;

    protected override void OnLoad(EventArgs e)
    {
        WindowsIdentity wi = (WindowsIdentity)System.Web.HttpContext.Current.User.Identity;
        m_wic = wi.Impersonate();
        HttpContext.Current.Response.Write("Impersonate<br />");
        base.OnLoad(e);
    }

    protected override void OnUnload(EventArgs e)
    {
        base.OnUnload(e);
        _ImpersonationUndo();
    }

    protected void _ImpersonationUndo()
    {
        if (m_wic != null)
        {
            m_wic.Undo();
            HttpContext.Current.Response.Write("Impersonate undo<br />");
        }
        m_wic = null;
    }
}

Form page directives:

<%@ Page Async="true" Language="C#" AutoEventWireup="true" Inherits="ProxyAddresses" Codebehind="ProxyAddresses.aspx.cs" %>

Class declaration:

public partial class ProxyAddresses : ImpersonatedPage

Page_Load:

protected void Page_Load(object sender, EventArgs e)
{
    Response.Write("Page_Load: " + WindowsIdentity.GetCurrent().Name + "<br />");

    if (!IsPostBack)
    {
        RegisterAsyncTask(new PageAsyncTask(InitialPageLoadAsync));
    }
    ...

Async func:

private async Task InitialPageLoadAsync()
{
    Response.Write("InitialPageLoadAsync: " + WindowsIdentity.GetCurrent().Name + "<br />");

    await fnDoSomeAsyncWork();
    ...

Button click:

protected void idBtnSaveSrv_Click(object sender, EventArgs e)
{
    Response.Write("idBtnSaveSrv_Click: " + WindowsIdentity.GetCurrent().Name + "<br />");
    ...

Debug output - Initial request:

  • Impersonate
  • Page_Load: DOMAIN\myuser
  • InitialPageLoadAsync: IIS APPPOOL\appuser (Why?)
  • [page content]
  • Impersonate undo

Debug output - Button click:

  • Impersonate
  • Page_Load: DOMAIN\myuser
  • idBtnSaveSrv_Click: IIS APPPOOL\appuser (Why?)
  • [page content]
  • Impersonate undo
3
  • 2
    Please post some code. Commented Mar 22, 2016 at 14:08
  • 1
    If you want to make asynchronous calss in Page_Load you should declare it async void, not use RegisterAsyncTask. RegisterAsyncTask is meant to notify IIS about a running task that shouldn't be aborted when the current request ends Commented Mar 22, 2016 at 16:09
  • Almost too easy and obvious... I though I tried that and it didn't work, then followed the example here: link Anyway, making Page_Load async seem to work perfect. Commented Mar 22, 2016 at 20:21

1 Answer 1

1

It appears as though you're missing the Async="true" in the form page directives, detailed here. Try this instead:

<%@ Page Async="true" Language="C#" Async="true"
    AutoEventWireup="true" Inherits="ProxyAddresses" 
    Codebehind="ProxyAddresses.aspx.cs" %>
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.