C# 设置控制器操作的超时
我已经遇到过了,但我可能需要一些别的东西来应对我的处境 我有一个操作返回一个C# 设置控制器操作的超时,c#,jquery,asp.net-mvc-2,azure,timeout,C#,Jquery,Asp.net Mvc 2,Azure,Timeout,我已经遇到过了,但我可能需要一些别的东西来应对我的处境 我有一个操作返回一个ViewResult,客户端的$.post() JavaScript: var link = 'GetFoo?fooBar=' + fooBar; var jqxhr = $.post(link, function (response) { $('#myDiv').replaceWith(response); }); public ViewResult GetFoo(String fooBar) {
ViewResult
,客户端的$.post()
JavaScript:
var link = 'GetFoo?fooBar=' + fooBar;
var jqxhr = $.post(link, function (response) {
$('#myDiv').replaceWith(response);
});
public ViewResult GetFoo(String fooBar)
{
if (Request.IsAjaxRequest())
{
// perform a ridiculously long task (~12 minutes)
// algorithm: 1) download files from the Azure blob storage
// 2) update each file
// 3) reupload to blob storage
// 4) return a list of URIs to be displayed to the UI
return View("MyFooView", data);
}
throw new InvalidOperationException();
}
控制器:
var link = 'GetFoo?fooBar=' + fooBar;
var jqxhr = $.post(link, function (response) {
$('#myDiv').replaceWith(response);
});
public ViewResult GetFoo(String fooBar)
{
if (Request.IsAjaxRequest())
{
// perform a ridiculously long task (~12 minutes)
// algorithm: 1) download files from the Azure blob storage
// 2) update each file
// 3) reupload to blob storage
// 4) return a list of URIs to be displayed to the UI
return View("MyFooView", data);
}
throw new InvalidOperationException();
}
正如注释所暗示的,在控制器内部有一个长任务正在运行。(这是一个文档生成模块,用于将PDF上载到Azure blob存储并将指向该存储的链接返回到视图。)
这在我的开发机器上运行良好,但当它在(安全的)Azure生产环境中运行时,它就会超时。我在任何地方都输入了大量日志条目,事实证明,它能够上传文档并返回到控制器(即,它到达上面的控制器返回语句)。但是,当需要将模型数据返回到视图时,客户端脚本不会回调(即,div
内容不会被结果替换)
有没有办法延长通话的超时时间?很难在我(不安全的)本地环境中复制,因此最终的修复将有所帮助
如果在我的GetFoo()
方法上使用属性[AsyncTimeout(3600)]
,则此操作永远不会从UI调用
任何建议都将不胜感激。您想看看这个吗 您的问题的答案是:[异步超时(3600000)] 在这里看到更多
你想看看这个吗 您的问题的答案是:[异步超时(3600000)] 在这里看到更多
问题在于Azure负载平衡器有自己的超时,设置为1分钟。任何需要更长时间的请求。这是无法改变的 在Azure环境中解决这个问题的方法是让一个ajax调用启动流程并返回某种流程ID,然后让客户端轮询另一个ajax调用以传递此流程ID,以查看它是否完成。它可能看起来像这样未编译且未经测试的代码。在javascript中:
var link = 'BeginFooProcessing?fooBar=' + fooBar;
var jqxhr = $.post(link, function (response) {
var finishedlink = 'CheckFooFinished?fooId=' + response;
// Check to see if we're finished in 1 second
setTimeout("CheckIfFinishedYet('" + finishedlink + "')", 1000);
});
function CheckIfFinishedYet(finishedlink) {
var response = $.post(finishedlink, function (response) {
if (response == null) {
// if we didn't get a result, then check in another second
setTimeout("CheckIfFinishedYet('" + finishedlink + "')", 1000);
}
else {
// Yay, we've got a result so we'll just write it out
$('#myDiv').replaceWith(response);
}
});
}
在控制器中:
public ViewResult BeginFooProcessing(String fooBar)
{
if (Request.IsAjaxRequest())
{
Guid fooId = Guid.NewGuid();
var result = new FooResult
{
FooId = fooId,
HasFinishedProcessing = false,
Uris = new List<string>()
};
// This needs to go to persistent storage somewhere
// as subsequent requests may not come back to this
// webserver
result.SaveToADatabaseSomewhere();
System.Threading.Tasks.Task.Factory.StartNew(() => ProcessFoo(fooId));
return View("MyFooStartView", fooId);
}
throw new InvalidOperationException();
}
private void ProcessFoo(Guid fooId)
{
// Perform your long running task here
FooResult result = GetFooResultFromDataBase(fooId);
result.HasFinishedProcessing = true;
result.Uris = uriListThatWasCalculatedAbove;
result.SaveToADatabaseSomewhere();
}
public ViewResult CheckFooFinished(Guid fooId)
{
if (Request.IsAjaxRequest())
{
FooResult result = GetFooResultFromDataBase(fooId);
if (result.HasFinishedProcessing)
{
// Clean up after ourselves
result.DeleteFromDatabase();
return View("MyFooFinishedView", result.Uris);
}
return View("MyFooFinishedView", null);
}
throw new InvalidOperationException();
}
private class FooResult
{
public Guid FooId { get; set; }
public bool HasFinishedProcessing { get; set; }
public List<string> Uris;
}
public class WebsiteController : AsyncController
public view结果BeginFooProcessing(字符串fooBar)
{
if(Request.IsAjaxRequest())
{
Guid fooId=Guid.NewGuid();
var result=新结果
{
FooId=FooId,
HasFinishedProcessing=false,
Uris=新列表()
};
//这需要转到某个地方的持久性存储
//因为后续的请求可能不会返回到此
//网络服务器
result.savetoadabasesomewhere();
System.Threading.Tasks.Task.Factory.StartNew(()=>ProcessFoo(fooId));
返回视图(“MyFooStartView”,fooId);
}
抛出新的InvalidOperationException();
}
私有void ProcessFoo(Guid fooId)
{
//在这里执行长时间运行的任务
FooResult=GetFooResultFromDataBase(fooId);
result.HasFinishedProcessing=true;
result.Uris=上面计算的尿酸列表;
result.savetoadabasesomewhere();
}
public ViewResult CheckFooFinished(Guid fooId)
{
if(Request.IsAjaxRequest())
{
FooResult=GetFooResultFromDataBase(fooId);
if(结果已完成数据处理)
{
//打扫干净
result.DeleteFromDatabase();
返回视图(“MyFooFinishedView”,result.Uris);
}
返回视图(“MyFooFinishedView”,null);
}
抛出新的InvalidOperationException();
}
私有类结果
{
公共Guid FooId{get;set;}
public bool已完成数据处理{get;set;}
公共列表URI;
}
希望这将为您提供一个起点。问题在于Azure负载平衡器有自己的超时,设置为一分钟。任何需要更长时间的请求。这是无法改变的 在Azure环境中解决这个问题的方法是让一个ajax调用启动流程并返回某种流程ID,然后让客户端轮询另一个ajax调用以传递此流程ID,以查看它是否完成。它可能看起来像这样未编译且未经测试的代码。在javascript中:
var link = 'BeginFooProcessing?fooBar=' + fooBar;
var jqxhr = $.post(link, function (response) {
var finishedlink = 'CheckFooFinished?fooId=' + response;
// Check to see if we're finished in 1 second
setTimeout("CheckIfFinishedYet('" + finishedlink + "')", 1000);
});
function CheckIfFinishedYet(finishedlink) {
var response = $.post(finishedlink, function (response) {
if (response == null) {
// if we didn't get a result, then check in another second
setTimeout("CheckIfFinishedYet('" + finishedlink + "')", 1000);
}
else {
// Yay, we've got a result so we'll just write it out
$('#myDiv').replaceWith(response);
}
});
}
在控制器中:
public ViewResult BeginFooProcessing(String fooBar)
{
if (Request.IsAjaxRequest())
{
Guid fooId = Guid.NewGuid();
var result = new FooResult
{
FooId = fooId,
HasFinishedProcessing = false,
Uris = new List<string>()
};
// This needs to go to persistent storage somewhere
// as subsequent requests may not come back to this
// webserver
result.SaveToADatabaseSomewhere();
System.Threading.Tasks.Task.Factory.StartNew(() => ProcessFoo(fooId));
return View("MyFooStartView", fooId);
}
throw new InvalidOperationException();
}
private void ProcessFoo(Guid fooId)
{
// Perform your long running task here
FooResult result = GetFooResultFromDataBase(fooId);
result.HasFinishedProcessing = true;
result.Uris = uriListThatWasCalculatedAbove;
result.SaveToADatabaseSomewhere();
}
public ViewResult CheckFooFinished(Guid fooId)
{
if (Request.IsAjaxRequest())
{
FooResult result = GetFooResultFromDataBase(fooId);
if (result.HasFinishedProcessing)
{
// Clean up after ourselves
result.DeleteFromDatabase();
return View("MyFooFinishedView", result.Uris);
}
return View("MyFooFinishedView", null);
}
throw new InvalidOperationException();
}
private class FooResult
{
public Guid FooId { get; set; }
public bool HasFinishedProcessing { get; set; }
public List<string> Uris;
}
public class WebsiteController : AsyncController
public view结果BeginFooProcessing(字符串fooBar)
{
if(Request.IsAjaxRequest())
{
Guid fooId=Guid.NewGuid();
var result=新结果
{
FooId=FooId,
HasFinishedProcessing=false,
Uris=新列表()
};
//这需要转到某个地方的持久性存储
//因为后续的请求可能不会返回到此
//网络服务器
result.savetoadabasesomewhere();
System.Threading.Tasks.Task.Factory.StartNew(()=>ProcessFoo(fooId));
返回视图(“MyFooStartView”,fooId);
}
抛出新的InvalidOperationException();
}
私有void ProcessFoo(Guid fooId)
{
//在这里执行长时间运行的任务
FooResult=GetFooResultFromDataBase(fooId);
result.HasFinishedProcessing=true;
result.Uris=上面计算的尿酸列表;
result.savetoadabasesomewhere();
}
public ViewResult CheckFooFinished(Guid fooId)
{
if(Request.IsAjaxRequest())
{
FooResult=GetFooResultFromDataBase(fooId);
if(结果已完成数据处理)
{
//打扫干净
result.DeleteFromDatabase();
返回视图(“MyFooFinishedView”,result.Uris);
}
返回视图(“MyFooFinishedView”,null);
}
抛出新的InvalidOperationException();
}
私有类结果
{
公共Guid FooId{get;set;}
public bool已完成数据处理{get;set;}
公共列表URI;
}
希望这将为您提供一个起点。要使用异步控制器,您的控制器必须从AsyncController继承:
public ViewResult BeginFooProcessing(String fooBar)
{
if (Request.IsAjaxRequest())
{
Guid fooId = Guid.NewGuid();
var result = new FooResult
{
FooId = fooId,
HasFinishedProcessing = false,
Uris = new List<string>()
};
// This needs to go to persistent storage somewhere
// as subsequent requests may not come back to this
// webserver
result.SaveToADatabaseSomewhere();
System.Threading.Tasks.Task.Factory.StartNew(() => ProcessFoo(fooId));
return View("MyFooStartView", fooId);
}
throw new InvalidOperationException();
}
private void ProcessFoo(Guid fooId)
{
// Perform your long running task here
FooResult result = GetFooResultFromDataBase(fooId);
result.HasFinishedProcessing = true;
result.Uris = uriListThatWasCalculatedAbove;
result.SaveToADatabaseSomewhere();
}
public ViewResult CheckFooFinished(Guid fooId)
{
if (Request.IsAjaxRequest())
{
FooResult result = GetFooResultFromDataBase(fooId);
if (result.HasFinishedProcessing)
{
// Clean up after ourselves
result.DeleteFromDatabase();
return View("MyFooFinishedView", result.Uris);
}
return View("MyFooFinishedView", null);
}
throw new InvalidOperationException();
}
private class FooResult
{
public Guid FooId { get; set; }
public bool HasFinishedProcessing { get; set; }
public List<string> Uris;
}
public class WebsiteController : AsyncController
然后是使用异步的任何操作