IHttpAsyncHandler не выполняется асинхронно
Я работаю с существующей кодовой базой внешнего интерфейса Silverlight и коллекцией внутренних классов IHttpHandler. У меня возникла ситуация, когда мне нужно связать клиента и дождаться завершения действия на стороннем сайте, а затем перезвонить на наш сайт и сказать, что "ожидаемое действие завершено", чтобы клиент мог продолжить.
Основной поток:
- Клиент направляет пользователя на сторонний сайт в новой вкладке
- Клиент вызывает серверный класс для ожидания обновления статуса в базе данных
- Пользователь выполняет действие на стороннем сайте, сторонний сайт перенаправляет на страницу на нашем сайте
- Страница из #3 отмечает действие как выполненное в базе данных
- Класс из #2 видит статус "завершен", возвращается к клиенту
- Клиент продолжает как обычно
У меня нет большого контроля над этим процессом; без существенных изменений в существующем коде, это более или менее то, как этот процесс должен происходить.
При тестировании этого я обнаружил, что хотя вызов #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, слишком много унаследованного кода зависит от него), но я готов полностью разделить эти два процесса, если есть нет способа повторно использовать этот метод.
Есть идеи? Заранее спасибо!