我使用ASP.NET IHttpAsyncHandler将异步重定向长轮询HTTP重新设置到其他URL。它与.NET 4.5(Windows 7,8)完美配合。但不适用于Mono(Mono JIT编译器版本3.2.8(Debian 3.2.8 + dfsg-4ubuntu1),Ubuntu 14.04)。完成request.BeginGetResponse后,AsyncCallback不会调用EndProcessRequest。
public bool IsReusable { get { return true; } }
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
var request = (HttpWebRequest)HttpWebRequest.Create("http://www.google.com/");
request.Method = context.Request.HttpMethod;
request.UserAgent = context.Request.UserAgent;
request.Accept = string.Join(",", context.Request.AcceptTypes);
if (!string.IsNullOrEmpty(context.Request.Headers["Accept-Encoding"]))
{
request.Headers["Accept-Encoding"] = context.Request.Headers["Accept-Encoding"];
}
request.ContentType = context.Request.ContentType;
request.ContentLength = context.Request.ContentLength;
using (var stream = request.GetRequestStream())
{
CopyStream(context.Request.InputStream, stream);
}
return request.BeginGetResponse(cb, new object[] { context, request });
}
public void EndProcessRequest(IAsyncResult result)
{
// EndProcessRequest never called
var context = (HttpContext)((object[])result.AsyncState)[0];
var request = (HttpWebRequest)((object[])result.AsyncState)[1];
using (var response = request.EndGetResponse(result))
{
context.Response.ContentType = response.ContentType;
foreach (string h in response.Headers)
{
context.Response.AppendHeader(h, response.Headers[h]);
}
using (var stream = response.GetResponseStream())
{
CopyStream(stream, context.Response.OutputStream);
}
response.Close();
context.Response.Flush();
}
}
private void CopyStream(Stream from, Stream to)
{
var buffer = new byte[1024];
while (true)
{
var read = from.Read(buffer, 0, buffer.Length);
if (read == 0) break;
to.Write(buffer, 0, read);
}
}
我不知道这个奇怪的beahaviour的原因。我想这种行为是Mono框架中HttpWebRequest类的错误,但我不确定。可能有这个问题的解决方法吗?
答案 0 :(得分:0)
我们通过使用ThreadPool.QueueUserWorkItem找到了问题的一些解决方法:
public bool IsReusable { get { return true; }}
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
return new AsynchOperation(cb, context, extraData).Start();
}
public void EndProcessRequest(IAsyncResult result) { }
public void ProcessRequest(HttpContext context) { }
private class AsynchOperation : IAsyncResult
{
private AsyncCallback cb;
private HttpContext context;
public WaitHandle AsyncWaitHandle { get { return null; } }
public object AsyncState { get; private set; }
public bool IsCompleted { get; private set; }
public bool CompletedSynchronously { get { return false; } }
public AsynchOperation(AsyncCallback callback, HttpContext context, object state)
{
cb = callback;
this.context = context;
AsyncState = state;
IsCompleted = false;
}
public IAsyncResult Start()
{
ThreadPool.QueueUserWorkItem(AsyncWork, null);
return this;
}
private void AsyncWork(object _)
{
var request = (HttpWebRequest)WebRequest.Create(boshUri);
request.Method = context.Request.HttpMethod;
// copy headers & body
request.UserAgent = context.Request.UserAgent;
request.Accept = string.Join(",", context.Request.AcceptTypes);
if (!string.IsNullOrEmpty(context.Request.Headers["Accept-Encoding"]))
{
request.Headers["Accept-Encoding"] = context.Request.Headers["Accept-Encoding"];
}
request.ContentType = context.Request.ContentType;
request.ContentLength = context.Request.ContentLength;
using (var stream = request.GetRequestStream())
{
CopyStream(context.Request.InputStream, stream);
}
request.BeginGetResponse(EndGetResponse, Tuple.Create(context, request));
}
private void EndGetResponse(IAsyncResult ar)
{
var data = (Tuple<HttpContext, HttpWebRequest>)ar.AsyncState;
var context = data.Item1;
var request = data.Item2;
try
{
using (var response = request.EndGetResponse(ar))
{
context.Response.ContentType = response.ContentType;
// copy headers & body
foreach (string h in response.Headers)
{
context.Response.AppendHeader(h, response.Headers[h]);
}
using (var stream = response.GetResponseStream())
{
CopyStream(stream, context.Response.OutputStream);
}
context.Response.Flush();
}
}
catch (Exception err)
{
if (err is IOException || err.InnerException is IOException)
{
// ignore
}
else
{
LogManager.GetLogger("ASC.Web.BOSH").Error(err);
}
}
finally
{
IsCompleted = true;
cb(this);
}
}