Вызов асинхронной функции из ASP.Net

В проекте ASP.Net я недавно изменил некоторые длинные функции на асинхронные. Это оказалось причиной некоторых неожиданных проблем.

В основном функции работают при использовании await, но необходимость вызывать их из другой асинхронной функции в конечном итоге становится проблемой в форме. До сих пор я устанавливал для директивы страницы Async значение true и использовал RegisterAsyncTask для инициирования вызовов асинхронных функций. Звонок работает. Но оказывается, когда у меня включена директива страницы Async, контекст пользователя иногда меняется.

Чтобы олицетворять вызывающего пользователя для всего кода на определенных страницах, я унаследовал класс System.Web.UI.Page от класса ImpersonatedPage. В моем классе я использую OnLoad для имитации вызывающего пользователя. Таким образом, я уверен, что пользователь никогда не сможет видеть или делать больше, чем он/она уже имеет доступ, и журналы аудита показывают правильного пользователя.

Когда директива асинхронной страницы включена, она по-прежнему олицетворяет пользователя. Но, например, в коде нажатия кнопки пользовательский контекст внезапно возвращается к контексту пулов приложений. В Page_Load пользовательский контекст — это вызывающий пользователь, как и ожидалось. Что вызывает это, и можно ли избежать переключения обратно на пользователя пула приложений?

В качестве альтернативы я попытался удалить директиву страницы Async и вызвать функцию async с помощью Task.Run. Затем пользовательский контекст не переключается обратно, а вместо этого HttpContext.Current имеет значение null, и асинхронная функция не может выполнять свою работу.

Любые другие способы вызова асинхронной функции из ASP.Net без включения директивы страницы Async?

Целевая платформа: 4.6.1, насколько мне известно, причуды не включены

Класс ImpersonatedPage:

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;
    }
}

Директивы страницы формы:

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

Объявление класса:

public partial class ProxyAddresses : ImpersonatedPage

Страница_Загрузка:

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

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

Асинхронная функция:

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

    await fnDoSomeAsyncWork();
    ...

Щелчок кнопки:

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

Вывод отладки — первоначальный запрос:

  • Выдавать себя за
  • Page_Load: ДОМЕН\мой пользователь
  • InitialPageLoadAsync: IIS APPPOOL\appuser (почему?)
  • [содержимое страницы]
  • Выдать себя за отмену

Вывод отладки — нажатие кнопки:

  • Выдавать себя за
  • Page_Load: ДОМЕН\мой пользователь
  • idBtnSaveSrv_Click: IIS APPPOOL\appuser (Почему?)
  • [содержимое страницы]
  • Выдать себя за отмену

person Jan    schedule 22.03.2016    source источник
comment
Пожалуйста, опубликуйте код.   -  person Anderson Pimentel    schedule 22.03.2016
comment
Если вы хотите сделать асинхронный вызов в Page_Load, вы должны объявить его async void, не использовать RegisterAsyncTask. RegisterAsyncTask предназначен для уведомления IIS о запущенной задаче, которую не следует прерывать после завершения текущего запроса.   -  person Panagiotis Kanavos    schedule 22.03.2016
comment
Почти слишком просто и очевидно... Хотя я попробовал это, и это не сработало, я последовал примеру здесь: link В любом случае, асинхронная загрузка Page_Load кажется идеальной.   -  person Jan    schedule 22.03.2016


Ответы (1)


Похоже, вам не хватает Async="true" в директивах страницы формы, подробно здесь. Попробуйте это вместо этого:

<%@ Page Async="true" Language="C#" Async="true"
    AutoEventWireup="true" Inherits="ProxyAddresses" 
    Codebehind="ProxyAddresses.aspx.cs" %>
person David Pine    schedule 24.03.2016