Ajax 在ASPNET MVC SinglePageApplication中缓存数据
我正在寻找解决问题的方法或最佳实践。因为这更像是一个架构挑战,所以我没有任何源代码 我的问题是如何处理与我的需求有关的ASP.NET会话。还是不符合我的要求 情景:我正在ASP.NETMVC上构建一个单页应用程序。MVC应用程序提供服务器端接口来处理后端。MVC应用程序调用不同后端服务器的服务来请求数据。这些数据可能很多,应该缓存在MVC应用程序中 就我所见,ASP.NET-session似乎不是SPA的最佳解决方案,因为它的并发行为?!如果有任何请求需要对会话进行写访问,那么就不可能有并发ajax请求(在我的例子中,这种情况发生了,因为必须缓存数据) 示例:典型情况(至少在我的应用程序中)是,当用户访问某个屏幕时,会执行一些ajax请求。例如,第一个请求触发从后端服务器加载数据,需要一些时间(可能约30秒…)。它还需要对会话进行写访问,因为它应该缓存此(!)用户的数据。其他请求现在必须等待,即使它们只需要对会话进行读取访问,并且不处理要加载的数据。一个请求等待另一个请求的行为只应在某些情况下发生 我现在可以使用System.Runtime.Caching为每个用户实现不同的数据缓存机制,但这是推荐的还是最好的解决方案 处理这种情况的最佳模式是什么 有什么最佳实践吗 Edit2: 一个要点是执行并发ajax调用时会话的行为。我准备了一个小例子:一个执行ajax调用的应用程序——一些将会话用作只读会话——另一些则需要ReadWrite。这些操作有一个超时,使问题更加明显 这些是我的控制器:Ajax 在ASPNET MVC SinglePageApplication中缓存数据,ajax,asp.net-mvc,session,single-page-application,Ajax,Asp.net Mvc,Session,Single Page Application,我正在寻找解决问题的方法或最佳实践。因为这更像是一个架构挑战,所以我没有任何源代码 我的问题是如何处理与我的需求有关的ASP.NET会话。还是不符合我的要求 情景:我正在ASP.NETMVC上构建一个单页应用程序。MVC应用程序提供服务器端接口来处理后端。MVC应用程序调用不同后端服务器的服务来请求数据。这些数据可能很多,应该缓存在MVC应用程序中 就我所见,ASP.NET-session似乎不是SPA的最佳解决方案,因为它的并发行为?!如果有任何请求需要对会话进行写访问,那么就不可能有并发aj
[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
public class SessionReadOnlyController : Controller
{
public ActionResult Perform()
{
Session["x"] = 5;
Thread.Sleep(1500);
return Json(new { success = true }, JsonRequestBehavior.AllowGet);
}
}
[SessionState(System.Web.SessionState.SessionStateBehavior.Required)]
public class SessionReadWriteController : Controller
{
public ActionResult Perform()
{
Session["x"] = 5;
Thread.Sleep(1500);
return Json(new { success = true }, JsonRequestBehavior.AllowGet);
}
}
这是执行ajax调用的javascript代码。立即执行所有呼叫:
jQuery(function ()
{
$('body').append('<p>start....1</p>');
$.ajax({
url: '/SessionReadWrite/Perform?id=1',
success: function () { $('body').append('<p>success1</p>'); }
});
$('body').append('<p>start....2</p>');
$.ajax({
url: '/SessionReadWrite/Perform?id=2',
success: function () { $('body').append('<p>success2</p>'); }
});
$('body').append('<p>start....3</p>');
$.ajax({
url: '/SessionReadOnly/Perform?id=3',
success: function () { $('body').append('<p>success3</p>'); }
});
$('body').append('<p>start....4</p>');
$.ajax({
url: '/SessionReadOnly/Perform?id=4',
success: function () { $('body').append('<p>success4</p>'); }
});
$('body').append('<p>start....5</p>');
$.ajax({
url: '/SessionReadOnly/Perform?id=5',
success: function () { $('body').append('<p>success5</p>'); }
});
});
jQuery(函数()
{
$('body')。追加('start….1');
$.ajax({
url:'/SessionReadWrite/Perform?id=1',
成功:函数(){$('body').append('p>success1');}
});
$('body')。追加('start….2');
$.ajax({
url:'/SessionReadWrite/Perform?id=2',
成功:函数(){$('body').append('p>success2');}
});
$('body')。追加('start….3');
$.ajax({
url:'/SessionReadOnly/Perform?id=3',
成功:函数(){$('body').append('p>success3');}
});
$('body')。追加('start….4');
$.ajax({
url:'/SessionReadOnly/Perform?id=4',
成功:函数(){$('body').append('p>success4');}
});
$('body')。追加('start….5');
$.ajax({
url:'/SessionReadOnly/Perform?id=5',
成功:函数(){$('body').append('p>success5');}
});
});
我的案例中的结果(取自internet explorer的开发者工具):
- 呼叫1在1,51秒后响应
- 呼叫2在3,03秒后响应
- 呼叫3在4,56秒后响应
- 呼叫4在4,56秒后响应
- 呼叫5在4,56秒后响应
Edit2:添加了一个示例…现在,问题终于清楚了。由于ASP.NET从不同线程锁定同一用户的会话访问,会话将不允许您解决问题 因此,您需要自己实现线程安全的东西。正如您在问题中所说,没有很多人,内存消耗不是问题,您可以使用自定义静态类,其生命周期从创建(首次访问)到结束或应用程序(例如服务器重启或应用程序池回收) 您必须决定是为用户还是为会话存储数据。如果它是为用户存储的,它将在会话超时后“生存”。如果它是为会话存储的,由会话ID标识,则可以在会话结束时在
global.asax
中处理会话结束事件
您需要两个级别的锁定:
GetOrAdd
方法
对于2,您可以使用具有如下成员的对象,当提供用户id时,该对象将是从字典返回的对象:
private object _data; // to store the cached data
public void StoreData(object data)
{
// - If there is a lock return inmediately:
// someone is already writing the data
// - If there is no lock, create the lock, store the data in _data,
// and release the lock
}
public object GetData(int userId)
{
// - Wait for the lock
// - Return data from _data
}
有许多方法可以锁定对\u数据的访问
public void CreateStoreData(Func<object> methodThatCreatesData)
{
// - If there is a lock return inmediately:
// someone is already writing the data
// - If there is no lock, create the lock, call methodThatCreatesData,
// write the data, and release the lock
}
DataCreator dc = new DataCreator(); // prepare the class that generates the data
var userData = UsersData.GetOrAdd(...) // get the dictionary entry for the user
userData.CreateStoreData(dc.DataCreatorMethod);