我正在努力取得进步吧。在服务器端,我创建了一个控制器,它应该获取进度值并将值存储在会话中。
在客户端,我创建了两个ajax请求。其中一个启动一个函数,我想监视它,另一个只是检查进度阶段。我的意思是,这就是我认为它会起作用的方式。但它只会在完成后输出一些东西。
只需等待几秒钟然后发出警报即可完成!"这就是全部。
问题是什么?也许我应该在控制器中创建新线程来监控进度阶段?
这是客户端代码:
function generate() {
setTimeout(checkProgress, 400);
$.ajax({
type: "POST",
url: "/PPTReport/Generate",
async: true,
success: function (text) {
console.log(text);
},
error:function() {
console.log("error! error!");
}
});
}
function checkProgress() {
var id = "reportProgress";
$.ajax({
type: "POST",
url: "/PPTReport/GetProgress",
async: true,
data: "id="+id,
success: function (data) {
if (data.done) {
console.log('Done!');
} else {
console.log('Progress at ' + data.percent + '%');
console.log(data.percent);
setTimeout(checkProgress, 100 );
}
},
error: function() {
console.log('ajax error');
}
});
}
这是服务器端代码
public class ProgressInfo
{
public int Percent { get; set; }
public bool Done { get; set; }
}
public JsonResult GetProgress(string id)
{
ProgressInfo progress;
if (string.IsNullOrEmpty(id)
|| (progress = Session[id] as ProgressInfo) == null)
{
return Json(new
{
success = false
});
}
if (progress.Done)
{
Session.Remove(id);
}
return Json(new
{
success = true,
done = progress.Done,
percent = progress.Percent
}
);
}
public JsonResult Generate(){
//init stuff
//there are somtheing like that
ProgressInfo progress = new ProgressInfo();
progress.Percent = 0;
progress.Done = false;
if (tabs > 0)
{
FirstPage();
progress.Percent++;
Session["reportProgress"] = progress;
if (tabs > 1)
{
SecondPage();
progress.Percent++;
Session["reportProgress"] = progress;
if (tabs > 2)
{
ThirdPage();
progress.Percent++;
Session["reportProgress"] = progress;
if (tabs > 3)
{
LastPage();
}
}
}
}
//what we've gonna return stuff etc
}
UPD: 好吧,我终于有点做了 - 我做了测试功能(几乎就像在例子中) 这是代码:
JS:
function doCalculation() {
$.post('/PPTReport/DoCalculation/sas');
setTimeout(pollProgress, 1000);
}
function pollProgress() {
var progressID = "sas";
$.post('/PPTReport/GetProgress/' + progressID, function (response) {
if (!response.success) {
alert('Cannot find progress');
return;
}
if (response.done) {
alert('Done!');
} else {
alert('Progress at ' + response.percent + '%');
setTimeout(pollProgress, 1000);
}
}, 'json');
}
服务器端:
public void DoCalculation(string id)
{
ProgressInfo progress = new ProgressInfo();
if (!string.IsNullOrEmpty(id))
{
Session[id] = progress;
}
//periodicly update progress
int i = 0;
while(i == 0 && progress.Percent != 7600000340)
{
progress.Percent++;
Thread.Sleep(1000);
}
}
public JsonResult GetProgress(string id)
{
ProgressInfo progress;
if (string.IsNullOrEmpty(id)
|| (progress = Session[id] as ProgressInfo) == null)
{
return Json(new
{
success = false
});
}
if (progress.Done)
{
Session.Remove(id);
}
return Json(new
{
success = true,
done = progress.Done,
percent = progress.Percent
});
}
但我等了一分多钟,直到行动第一次执行! Look
为什么会这样?它只是调用简单函数,为什么要等这么久?
答案 0 :(得分:7)
这是一个老问题的实例,请参见此处:
http://msdn.microsoft.com/en-us/library/ms178581.aspx
对于每个会话,访问ASP.NET会话状态是独占的,这意味着 如果两个不同的用户发出并发请求,则访问每个用户 同时授予单独的会话。但是,如果两个并发 请求是针对同一会话进行的(使用相同的SessionID) value),第一个请求获得对会话的独占访问权 信息。第二个请求仅在第一个请求之后执行 完了。 (如果排他性,第二次会议也可以访问 锁定信息被释放,因为第一个请求超过了 锁定超时。)如果@Page中的EnableSessionState值 指令设置为ReadOnly,即只读会话的请求 信息不会导致会话数据的独占锁定。 但是,会话数据的只读请求可能仍需要等待 对于由会话数据的读写请求设置的锁定来清除。
我认为你可以找到很多关于SO的帖子来讨论这个问题。这是一个:
Asynchronous Controller is blocking requests in ASP.NET MVC through jQuery
这是一个解决方法:
Disable Session state per-request in ASP.Net MVC
好的,添加一些(未经测试的!)示例代码。这只是为了说明如何解决这个问题:
public class myCache {
private static Dictionary<string, ProgressInfo> _pinfos = new Dictionary<string, ProgressInfo>();
private static readonly object _lockObject = new object();
public static void Add(string key, ProgressInfo value)
{
lock (_lockObject)
{
if (!_pinfos.ContainsKey(key)) {
_pinfos.Add(key, value);
}
else {
_pinfos[key] = value;
}
}
}
public static ProgressInfo Get(string key) {
if (_pinfos.ContainsKey(key)) {
return _pinfos[key];
}
else {
return null;
}
}
public static void Remove(string key) {
lock (_lockObject)
{
if (_pinfos.ContainsKey(key)) {
_pinfos.Remove(key);
}
}
}
}
[SessionState(SessionStateBehavior.ReadOnly)]
public class TestController : AsyncController
public void DoCalculation(string id)
{
ProgressInfo progress = new ProgressInfo();
if (!string.IsNullOrEmpty(id)) {
myCache.Add(id,progress);
}
//periodicly update progress
int i = 0;
while(i == 0 && progress.Percent != 7600000340)
{
progress.Percent++;
Thread.Sleep(1000);
}
}
public JsonResult GetProgress(string id)
{
ProgressInfo progress;
if (string.IsNullOrEmpty(id)
|| (progress = myCache.Get(id)) == null)
{
return Json(new
{
success = false
});
}
if (progress.Done)
{
myCache.Remove(id);
}
return Json(new
{
success = true,
done = progress.Done,
percent = progress.Percent
});
}
}
答案 1 :(得分:2)
Well Skarist解释了为什么它正在发生以及我遇到了什么。我做了一个(错误的)假设,即将会话状态更改为只读将阻止我写入会话,但它没有。
我为解决我的问题所做的是将EnableSessionState设置为&#34; ReadOnly&#34;在页面上我也分配了会话值。这基本上使Session不是线程安全的,并允许我在轮询服务器时拉取值。我目前正在使用WebForms,但在MVC中使用[SessionState(SessionStateBehavior.Disabled)]应该类似。