6

我正在使用 ASP.NET MVC 4 来接受最大 30 mb 的视频上传。将视频上传到站点后,然后使用 HttpWebRequest 将视频发布到第 3 方 Web 服务。在我的网站可以向浏览器返回响应之前,必须完成向 3rd 方服务的上传并返回响应。在 Rackspace 云站点上,负载均衡器有 30 秒的超时。如果在 30 秒内没有通过负载均衡器从我的站点返回任何响应,则负载均衡器会向浏览器返回超时错误并终止请求。

因此,我被告知需要发生的是,我的站点需要通过在我的站点将视频发送到第 3 方系统时将数据发送回浏览器来保持连接,以便负载均衡器不会超时。你将如何完成这项任务?

我正在寻找 2 件事 - 上传时我将什么作为数据发送回浏览器?我的实际响应是 JSON,所以如果我能在最后保留我的常规 JSON 响应,那将是理想的。

最后,如何在发送保活数据的同时执行我的 HttpWebRequest 上传到第 3 方?

-

作为参考,这是来自 rackspace 云的负载均衡器连接超时文档:http ://www.rackspace.com/knowledge_center/article/connection-timed-out-error-message-1

他们没有为这个问题提供任何具体的解决方案。

4

2 回答 2

4

这是我解决问题的方法。此解决方案应适用于使用具有不合理超时的负载平衡器的任何 .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

于 2012-10-10T15:07:46.443 回答
1

太糟糕了,您无法为您的站点调整负载均衡器配置。

我想你想做一个 javascript keep-alive。

例如:

(function poll(){
$.ajax({ url: "server", success: function(data){
    //Update your dashboard gauge
    salesGauge.setValue(data.value);

}, dataType: "json", complete: poll, timeout: 30000 });
})();

参考:

相关问题

jQuery 示例

于 2012-10-08T19:49:47.727 回答