Raf*_*afe 5 asp.net asp.net-mvc load-balancing
我正在使用ASP.NET MVC 4来接受最大30 mb的视频上传.将视频上传到网站后,视频将使用HttpWebRequest发布到第三方Web服务.此上传到第三方服务必须完成并返回响应,然后我的网站才能向浏览器返回响应.在Rackspace Cloud Sites上,负载均衡器有30秒超时.如果我的站点没有通过负载均衡器返回响应30秒,则负载均衡器会向浏览器返回超时错误并终止请求.
所以我被告知需要发生的事情是,我的网站需要通过在我的网站将视频发送到第三方系统时将数据发送回浏览器来保持连接活动,以便负载均衡器不会超时.你将如何完成这项任务?
我正在寻找两件事 - 在上传过程中,我将什么作为数据发送回浏览器?我的实际响应是JSON,所以如果我能在最后保持我的常规JSON响应,那将是理想的.
最后,如何在同时发送保持活动数据的同时将HttpWebRequest上传到第三方?
-
作为参考,这是来自rackspace cloud的负载均衡器连接超时文档:http://www.rackspace.com/knowledge_center/article/connection-timed-out-error-message-1
他们没有为这个问题提供任何具体的解决方案.
这是我解决问题的方法。此解决方案应该适用于任何使用具有不合理超时的负载均衡器的 .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);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
该解决方案依赖于 .Net 4 来完成异步工作。如果您有 .Net 4.5,则可以在不依赖于 AsyncController 类的 mvc 控制器中执行异步的更新方法。
该站点很有帮助,并解释了如何在 .Net 框架的各个版本中的 ASP.NET MVC 中执行异步操作:
http://dotnet.dzone.com/news/net-zone-evolution