这是我解决问题的方法。此解决方案应适用于使用具有不合理超时的负载平衡器的任何 .net 托管。Rackspace 云站点的负载均衡器有 30 秒的超时。Amazon 和 Azure 的超时时间更长,但如果您碰巧有一个长时间运行的操作,这仍然可能是一个有用的解决方案。
在 asp.net mvc 4 中,您可以将控制器更改为从 AsyncController 继承。这允许您分离异步任务,然后等待它们完成。此解决方案创建一个“保持活动状态”任务,该任务每 10 秒通过 asp.net 响应发回数据,以便负载均衡器检测到活动并且不会超时。该任务一直运行,直到它看到uploadFinished 变量设置为true。
另一个任务执行长时间运行的上传,或者在 asp.net mvc 控制器结束它正在处理的 Web 请求之前需要完成的任何任务。长时间运行的操作完成后,它将uploadFinished 变量设置为true。
最后,我围绕实际的 json 响应手动构建了一个容器 json 对象,这样我就可以让“保持活动”数据成为发送回浏览器的有效 json 的一部分。一个有点丑陋的黑客,但它有效!
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;
namespace MvcApplication4.Controllers
{
public class ExampleController : AsyncController
{
[HttpPost]
public string Upload(UploadModel model, HttpPostedFileBase videoFile)
{
// when using jquery ajax form for upload
// IE requires text/plain content type
// otherwise it will try to open the response as a file
// instead of pass the response back to your javascript
if (Request.AcceptTypes.Contains("application/json"))
{
Response.ContentType = "application/json";
}
else
{
Response.ContentType = "text/plain";
}
// start json object
Response.Write("{\"keepalive\":\"");
Response.Flush();
Task[] tasks = new Task[2];
tasks[0] = Task.Factory.StartNew(() => DoKeepAlive());
tasks[1] = Task.Factory.StartNew(() => DoUpload(model, videoFile));
Task.WaitAll(tasks);
// end keepalive json property
Response.Write("\",\"data\":");
// insert actual response data
JavaScriptSerializer json = new JavaScriptSerializer();
Response.Write(json.Serialize(uploadResponse));
// end json object
Response.Write("}");
return "";
}
public bool uploadFinished = false;
public UploadResponseModel uploadResponse = null;
public void DoUpload(UploadModel model, HttpPostedFileBase videoFile)
{
// do upload to 3rd party
MyServiceClient c = new MyServiceClient();
uploadResponse = c.UploadVideo(model, videoFile);
uploadFinished = true;
}
public void DoKeepAlive()
{
// send . every 10 seconds
while (!uploadFinished)
{
Response.Write(".");
Response.Flush();
Thread.Sleep(10000);
}
}
}
}
此解决方案依赖于 .Net 4 来执行异步操作。如果您有 .Net 4.5,则有更新的方法可以在不依赖 AsyncController 类的 mvc 控制器中执行异步操作。
该站点很有帮助,并解释了如何在各种版本的 .Net 框架中在 asp.net mvc 中执行异步操作:
http://dotnet.dzone.com/news/net-zone-evolution