Я работаю с существующей кодовой базой внешнего интерфейса 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, слишком много унаследованного кода зависит от него), но я готов полностью разделить эти два процесса, если естьнет способа повторно использовать этот метод.
Есть идеи?Заранее спасибо!