Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ajax/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ajax 在ASPNET MVC SinglePageApplication中缓存数据_Ajax_Asp.net Mvc_Session_Single Page Application - Fatal编程技术网

Ajax 在ASPNET MVC SinglePageApplication中缓存数据

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

我正在寻找解决问题的方法或最佳实践。因为这更像是一个架构挑战,所以我没有任何源代码

我的问题是如何处理与我的需求有关的ASP.NET会话。还是不符合我的要求

情景:我正在ASP.NETMVC上构建一个单页应用程序。MVC应用程序提供服务器端接口来处理后端。MVC应用程序调用不同后端服务器的服务来请求数据。这些数据可能很多,应该缓存在MVC应用程序中

就我所见,ASP.NET-session似乎不是SPA的最佳解决方案,因为它的并发行为?!如果有任何请求需要对会话进行写访问,那么就不可能有并发ajax请求(在我的例子中,这种情况发生了,因为必须缓存数据)

示例:典型情况(至少在我的应用程序中)是,当用户访问某个屏幕时,会执行一些ajax请求。例如,第一个请求触发从后端服务器加载数据,需要一些时间(可能约30秒…)。它还需要对会话进行写访问,因为它应该缓存此(!)用户的数据。其他请求现在必须等待,即使它们只需要对会话进行读取访问,并且不处理要加载的数据。一个请求等待另一个请求的行为只应在某些情况下发生

我现在可以使用System.Runtime.Caching为每个用户实现不同的数据缓存机制,但这是推荐的还是最好的解决方案

处理这种情况的最佳模式是什么

有什么最佳实践吗

Edit2:

一个要点是执行并发ajax调用时会话的行为。我准备了一个小例子:一个执行ajax调用的应用程序——一些将会话用作只读会话——另一些则需要ReadWrite。这些操作有一个超时,使问题更加明显

这些是我的控制器:

[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秒后响应
据我所知,读写会话操作会锁定会话,即使是只读会话操作。。。?!(还是我完全做错了什么?)

摘自msdn(),最后一章:

[…]但是,如果对同一会话发出两个并发请求(通过使用相同的SessionID值),则第一个请求以独占方式访问会话信息。第二个请求仅在第一个请求完成后执行。[…]但是,会话数据的只读请求可能仍然必须等待会话数据的读写请求设置的锁才能清除

关于我的情况:如果我想在单页应用程序中缓存数据(在内存中是可以的,因为应用程序只被少数用户使用),我需要一个不同于会话的概念。。。因此,我的问题是,是否有最佳做法

编辑:改进的情况描述


Edit2:添加了一个示例…

现在,问题终于清楚了。由于ASP.NET从不同线程锁定同一用户的会话访问,会话将不允许您解决问题

因此,您需要自己实现线程安全的东西。正如您在问题中所说,没有很多人,内存消耗不是问题,您可以使用自定义静态类,其生命周期从创建(首次访问)到结束或应用程序(例如服务器重启或应用程序池回收)

您必须决定是为用户还是为会话存储数据。如果它是为用户存储的,它将在会话超时后“生存”。如果它是为会话存储的,由会话ID标识,则可以在会话结束时在
global.asax
中处理会话结束事件

您需要两个级别的锁定:

  • 一个是访问特定用户的数据和锁(或者创建一个新的并返回它)
  • 其他用于用户的锁和数据(如上所述)
  • 对于1,你可以使用类似于a的东西。在此字典中,保留用户id+相关锁和用户数据。每当您需要为用户读取或写入数据时,请从此字典中获取数据。此第一级或锁保证访问用户的锁和数据时不会受到其他线程的干扰。您可以为此使用
    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);