IHttpAsyncHandler не выполняется асинхронно - PullRequest
0 голосов
/ 10 февраля 2019

Я работаю с существующей кодовой базой внешнего интерфейса Silverlight и коллекцией внутренних классов IHttpHandler.У меня возникла ситуация, когда мне нужно связать клиента и дождаться завершения действия на стороннем сайте, а затем перезвонить на наш сайт и сказать, что «ожидаемое действие завершено», чтобы клиент мог продолжить.

Основной поток:

  1. Клиент перенаправляет пользователя на сторонний сайт в новой вкладке
  2. Клиент вызывает класс на стороне сервера для ожидания обновления статусав базе данных
  3. Пользователь выполняет действие на стороннем сайте, сторонний сайт перенаправляет на страницу на нашем сайте
  4. Страница из # 3 отмечает действие как выполненное в базе данных
  5. Класс из # 2 видит состояние «завершено», возвращает клиенту
  6. Клиент продолжает работать как обычно

У меня нет большого контроля над этим процессом;без существенных изменений в существующем коде, это более или менее так должно происходить в этом процессе.

При тестировании этого я обнаружил, что хотя вызов # 2 происходит асинхронно на клиенте, серверевсе еще связан во время ожидания обновления статуса (я не слишком знаком с IHttpHandlers; на этой неделе я узнал, что они синхронизированы), и никакие другие вызовы сервера не выполняются

Чтобы исправить это, яя пытаюсь сделать вызов в # 2 асинхронным путем реализации IHttpAsyncHandler:

public abstract class BaseControl_Asynchronous : BaseControl, IHttpAsyncHandler
{
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
    {
        this.Context = context;
        this.Login = Utils.IsNullOrEmpty(Context.Session["Login"] as string, string.Empty);
        this.Domain = Utils.IsNullOrEmpty(Context.Session["Domain"] as string, "Demo");
        this.Init();

        var processRequestAsync = this.ProcessRequestAsync(context);
        var completionSource = new TaskCompletionSource<object>(context);

        processRequestAsync.ContinueWith((t, o) =>
        {
            if (t.IsFaulted)

            {
                if (t.Exception != null)
                {
                    completionSource.SetException(t.Exception.InnerExceptions);
                }
            }
            else
            {
                completionSource.SetResult(null);
            }

            cb(completionSource.Task);
        }, extraData);

        return completionSource.Task;
    }

    private async Task ProcessRequestAsync(HttpContext context)
    {
        await Task.Run(() => this.ProcessRequest_Internal(context));
    }

    public void EndProcessRequest(IAsyncResult result)
    {
        ((Task)result).Wait();
    }

    public void ProcessRequest(HttpContext context)
    {
        throw new InvalidOperationException();
    }
}

BaseControl - это существующий базовый класс для существующей коллекции классов IHttpHandler.Я разделил это на BaseControl_Synchronous и BaseControl_Asynchronous (см. Выше) и BaseControl, который содержит общий код для них обоих.

Вот базовая реализация ProcessRequest_Internal (в BaseControl):

public virtual void ProcessRequest_Internal(HttpContext context)
    {
        string output = string.Empty;

        // output contains a response envelope, code to construct envelope skeleton removed

        // abstract method implemented by sub classes
        string result = Execute();

        // code that appends result to response envelope removed

        context.Response.ContentType = ContentType;
        context.Response.Output.Write(output);
    }

В моем случае код «Выполнить» ожидает обновления этого статуса в базе данных.Из-за кода в BaseControl_Asynchronous я бы подумал, что этот подход будет работать, но код, ожидающий обновления состояния, связывает сервер, и другие вызовы не выполняются, пока он ожидает.

Естьэто просто неправильный подход?Я пытаюсь оставить как можно больше кода (я не хочу так сильно изменять ProcessRequest_Internal, слишком много унаследованного кода зависит от него), но я готов полностью разделить эти два процесса, если естьнет способа повторно использовать этот метод.

Есть идеи?Заранее спасибо!

...