使用 IHttpAsyncHandler 异步调用 WebService
这是基本设置。我们有一个 ASP.Net WebForms 应用程序,其中的页面包含需要访问外部 Web 服务的 Flash 应用程序。由于(我认为是安全性)Flash 的限制(不要问我,我根本不是 Flash 专家),我们无法直接从 Flash 连接到 Web 服务。解决方法是在 ASP.Net 中创建 Flash 应用程序将调用的代理,该代理将依次调用 WebService 并将结果转发回 Flash 应用程序。
不过,该网站的流量非常高,问题是,如果 Web 服务完全挂起,那么 ASP.Net 请求线程将开始备份,这可能会导致严重的线程匮乏。为了解决这个问题,我决定使用 IHttpAsyncHandler 正是为此目的而设计的。在其中,我将使用 WebClient 异步调用 Web 服务并将响应转发回来。网上关于如何正确使用 IHttpAsyncHandler 的示例很少,所以我只是想确保我没有做错。我的使用基于此处显示的示例: http://msdn.microsoft .com/en-us/library/ms227433.aspx
这是我的代码:
internal class AsynchOperation : IAsyncResult
{
private bool _completed;
private Object _state;
private AsyncCallback _callback;
private readonly HttpContext _context;
bool IAsyncResult.IsCompleted { get { return _completed; } }
WaitHandle IAsyncResult.AsyncWaitHandle { get { return null; } }
Object IAsyncResult.AsyncState { get { return _state; } }
bool IAsyncResult.CompletedSynchronously { get { return false; } }
public AsynchOperation(AsyncCallback callback, HttpContext context, Object state)
{
_callback = callback;
_context = context;
_state = state;
_completed = false;
}
public void StartAsyncWork()
{
using (var client = new WebClient())
{
var url = "url_web_service_url";
client.DownloadDataCompleted += (o, e) =>
{
if (!e.Cancelled && e.Error == null)
{
_context.Response.ContentType = "text/xml";
_context.Response.OutputStream.Write(e.Result, 0, e.Result.Length);
}
_completed = true;
_callback(this);
};
client.DownloadDataAsync(new Uri(url));
}
}
}
public class MyAsyncHandler : IHttpAsyncHandler
{
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
var asynch = new AsynchOperation(cb, context, extraData);
asynch.StartAsyncWork();
return asynch;
}
public void EndProcessRequest(IAsyncResult result)
{
}
public bool IsReusable
{
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
}
}
现在这一切都有效,我认为它应该可以解决问题,但我不是 100% 当然。另外,创建我自己的 IAsyncResult 似乎有点矫枉过正,我只是想知道是否有一种方法可以利用从 Delegate.BeginInvoke 返回的 IAsyncResult 或其他东西。欢迎任何反馈。谢谢!!
Here's the basic setup. We have an ASP.Net WebForms application with a page that has a Flash application that needs to access an external Web Service. Due to (security I presume) limitations in Flash (don't ask me, I'm not a Flash expert at all), we can't connect to the Web Service directly from Flash. The work around is to create a proxy in ASP.Net that the Flash application will call, which will in turn call the WebService and forward the results back to the Flash application.
The WebSite has very high traffic though, and the issue is, if the Web Service hangs at all, then the ASP.Net request threads will start backing up which could lead to serious thread starvation. In order to get around that, I've decided to use an IHttpAsyncHandler which was designed for this exact purpose. In it, I'll use a WebClient to asynchronously call the Web Service and the forward the response back. There are very few samples on the net on how to correctly use the IHttpAsyncHandler, so I just want to make sure I'm not doing it wrong. I'm basing my useage on the example show here: http://msdn.microsoft.com/en-us/library/ms227433.aspx
Here's my code:
internal class AsynchOperation : IAsyncResult
{
private bool _completed;
private Object _state;
private AsyncCallback _callback;
private readonly HttpContext _context;
bool IAsyncResult.IsCompleted { get { return _completed; } }
WaitHandle IAsyncResult.AsyncWaitHandle { get { return null; } }
Object IAsyncResult.AsyncState { get { return _state; } }
bool IAsyncResult.CompletedSynchronously { get { return false; } }
public AsynchOperation(AsyncCallback callback, HttpContext context, Object state)
{
_callback = callback;
_context = context;
_state = state;
_completed = false;
}
public void StartAsyncWork()
{
using (var client = new WebClient())
{
var url = "url_web_service_url";
client.DownloadDataCompleted += (o, e) =>
{
if (!e.Cancelled && e.Error == null)
{
_context.Response.ContentType = "text/xml";
_context.Response.OutputStream.Write(e.Result, 0, e.Result.Length);
}
_completed = true;
_callback(this);
};
client.DownloadDataAsync(new Uri(url));
}
}
}
public class MyAsyncHandler : IHttpAsyncHandler
{
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
var asynch = new AsynchOperation(cb, context, extraData);
asynch.StartAsyncWork();
return asynch;
}
public void EndProcessRequest(IAsyncResult result)
{
}
public bool IsReusable
{
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
}
}
Now this all works, and I THINK it should do the trick, but I'm not 100% sure. Also, creating my own IAsyncResult seems a bit overkill, I'm just wondering if there's a way I can leverage the IAsyncResult returned from Delegate.BeginInvoke, or maybe something else. Any feedback welcome. Thanks!!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
哇,是的,如果您使用 .NET 4.0,通过利用任务并行库,您可以使这变得更容易/更干净。检查一下:
Wow, yeah you can make this a lot easier/cleaner if you're on .NET 4.0 by leveraging the Task Parallel Library. Check it: