gpt4 book ai didi

c# - 使用 IHttpAsyncHandler 异步调用 WebService

转载 作者:太空狗 更新时间:2023-10-29 21:24:28 25 4
gpt4 key购买 nike

这是基本设置。我们有一个 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。欢迎任何反馈。谢谢!!

最佳答案

哇,是的,如果您使用的是 .NET 4.0,则可以通过利用任务并行库使这一切变得更容易/更清晰。检查一下:

public class MyAsyncHandler : IHttpAsyncHandler
{
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
// NOTE: the result of this operation is void, but TCS requires some data type so we just use bool
TaskCompletionSource<bool> webClientDownloadCompletionSource = new TaskCompletionSource<bool>();

WebClient webClient = new WebClient())
HttpContext currentHttpContext = HttpContext.Current;

// Setup the download completed event handler
client.DownloadDataCompleted += (o, e) =>
{
if(e.Cancelled)
{
// If it was canceled, signal the TCS is cacnceled
// NOTE: probably don't need this since you have nothing canceling the operation anyway
webClientDownloadCompletionSource.SetCanceled();
}
else if(e.Error != null)
{
// If there was an exception, signal the TCS with the exception
webClientDownloadCompletionSource.SetException(e.Error);
}
else
{
// Success, write the response
currentHttpContext.Response.ContentType = "text/xml";
currentHttpContext.Response.OutputStream.Write(e.Result, 0, e.Result.Length);

// Signal the TCS that were done (we don't actually look at the bool result, but it's needed)
taskCompletionSource.SetResult(true);
}
};

string url = "url_web_service_url";

// Kick off the download immediately
client.DownloadDataAsync(new Uri(url));

// Get the TCS's task so that we can append some continuations
Task webClientDownloadTask = webClientDownloadCompletionSource.Task;

// Always dispose of the client once the work is completed
webClientDownloadTask.ContinueWith(
_ =>
{
client.Dispose();
},
TaskContinuationOptions.ExecuteSynchronously);

// If there was a callback passed in, we need to invoke it after the download work has completed
if(cb != null)
{
webClientDownloadTask.ContinueWith(
webClientDownloadAntecedent =>
{
cb(webClientDownloadAntecedent);
},
TaskContinuationOptions.ExecuteSynchronously);
}

// Return the TCS's Task as the IAsyncResult
return webClientDownloadTask;
}

public void EndProcessRequest(IAsyncResult result)
{
// Unwrap the task and wait on it which will propagate any exceptions that might have occurred
((Task)result).Wait();
}

public bool IsReusable
{
get
{
return true; // why not return true here? you have no state, it's easily reusable!
}
}

public void ProcessRequest(HttpContext context)
{
}
}

关于c# - 使用 IHttpAsyncHandler 异步调用 WebService,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6388793/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com