C# 跨.NET MVC控制器请求持久化变量

C# 跨.NET MVC控制器请求持久化变量,c#,asp.net-mvc,caching,paging,C#,Asp.net Mvc,Caching,Paging,我的处境很奇怪——有人要求我优化一个依赖于延迟加载的搜索功能。我已经意识到速度的主要问题是由于分页请求之间的等待时间(大约1.5秒),在代码中,我意识到控制器处理的每个页面请求都会导致模型执行完整的DB查询(而不是仅对该页面的结果进行部分查询) 我们使用的是一个定制的ORM,所以我不确定它在分页方面处理了什么(我想这就是它以这种方式实现的原因)。我们将DB结果存储到IEnumerable,然后使用LINQ进行过滤以检索正确的页面结果 我想做的是将这个请求缓存在内存中——因为我们将把完整的结果放入

我的处境很奇怪——有人要求我优化一个依赖于延迟加载的搜索功能。我已经意识到速度的主要问题是由于分页请求之间的等待时间(大约1.5秒),在代码中,我意识到控制器处理的每个页面请求都会导致模型执行完整的DB查询(而不是仅对该页面的结果进行部分查询)

我们使用的是一个定制的ORM,所以我不确定它在分页方面处理了什么(我想这就是它以这种方式实现的原因)。我们将DB结果存储到IEnumerable,然后使用LINQ进行过滤以检索正确的页面结果

我想做的是将这个请求缓存在内存中——因为我们将把完整的结果放入一个IEnumerable中,所以将其保存在某个地方(即使我必须将其传递到我的模型中)会很方便

有人建议在我的控制器或模型中使用一个静态变量,但我认为如果有多个请求,这将很难失败。我认为可能有一种方法可以暂时将其存储在服务器端会话变量中,并在所有页面请求完成后将其删除。手动缓存,如果您愿意的话

我知道这不是最好的方法,但这可能是我在优化方面唯一明智的选择(除非我们转向另一种ORM)。有人有任何建议、想法或批评吗?我如何实现这样的东西

多谢各位

控制器代码:

    [HttpGet, JsonErrorCatcher, NoCache]
    public ActionResult Accounts(int page = 0)
    {
        using (var context = PersistenceContext.Create())
        {
            var model = new ContactsModel(context);
            return new JsonNetResult(model.GetAccountsWebView(CurrentUser, page));
        }
    }
模型方法:

    public ContactsWebViewModel GetAccountsWebView(User user, int page)
    {
        // This is what I'd like to avoid doing every time, by persisting this value.
        // I can pass it into this method if necessary.
        IEnumerable<Account> accounts = Context.Get<Account>()
            .Include(x => x.AssignedGroups)
            .Include(x => x.AssignedUsers)
            .Include(x => x.Contacts)
            .Where(x => x.IsActive)
            .OrderBy(x => x.Name)
            .ToArray();
        if (!user.HasPermission("Administrator.Contacts:View")) accounts = accounts.Where(x => x.IsReadableBy(user));
        int totalPages = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(accounts.Count()) / 25.0));
        accounts = accounts.Skip(page * 25).Take(25);
        var model = GetWebView(user, null, accounts, page == 0);
        model.TotalPages = totalPages;
        return model;
    }
public contactsWebView模型GetAccountsWebView(用户,int页)
{
//这就是我希望通过坚持这个值来避免每次都这样做的原因。
//如果有必要,我可以将其传递到这个方法中。
IEnumerable accounts=Context.Get()
.Include(x=>x.AssignedGroups)
.包括(x=>x.AssignedUsers)
.包括(x=>x.联系人)
.其中(x=>x.IsActive)
.OrderBy(x=>x.Name)
.ToArray();
如果(!user.HasPermission(“Administrator.Contacts:View”))accounts=accounts.Where(x=>x.IsReadableBy(user));
inttotalpages=Convert.ToInt32(Math.天花(Convert.ToDouble(accounts.Count())/25.0));
accounts=accounts.Skip(第25页)。Take(第25页);
var model=GetWebView(用户,空,帐户,页面==0);
model.TotalPages=TotalPages;
收益模型;
}

如果要缓存的数据是只读的,并且对于所有用户都是相同的,那么使用
静态变量是不存在问题的

如果不是这样,那么您应该将IEnumerable缓存为
System.Runtime.Caching.MemoryCache
对象中的
CacheItem
。您可以缓存多个版本以适应可能需要的各种场景


有关的详细信息。

如果要缓存的数据是只读的,并且对所有用户都是相同的,那么使用
静态变量是不成问题的

如果不是这样,那么您应该将IEnumerable缓存为
System.Runtime.Caching.MemoryCache
对象中的
CacheItem
。您可以缓存多个版本以适应可能需要的各种场景


有关的详细信息。

最简单的解决方案可能是使用内置的asp.net缓存。您没有说您正在使用的框架的版本,但是类似的东西应该可以工作

if (HttpContext.Cache["Key1"] == null)
  HttpContext.Cache.Add("Key1", "Value 1", null, DateTime.Now.AddSeconds(60), 
      Cache.NoSlidingExpiration, CacheItemPriority.High, null);
您可以随意调整缓存时间。但是请注意,如果结果很大,并且有多个用户,则很容易耗尽内存或造成巨大的分页延迟


您可以将搜索条件设置为键,只要返回的结果总是相同的搜索条件。

最简单的解决方案可能是使用内置的asp.net缓存。您没有说您正在使用的框架的版本,但是类似的东西应该可以工作

if (HttpContext.Cache["Key1"] == null)
  HttpContext.Cache.Add("Key1", "Value 1", null, DateTime.Now.AddSeconds(60), 
      Cache.NoSlidingExpiration, CacheItemPriority.High, null);
您可以随意调整缓存时间。但是请注意,如果结果很大,并且有多个用户,则很容易耗尽内存或造成巨大的分页延迟


您可以将搜索条件设置为键,只要返回的结果总是相同的搜索条件。

我最终使用此答案缓存db请求,这太棒了!不幸的是,事实证明,大部分问题都在别处,而且更难优化-(我最终使用这个答案来缓存db请求,这太棒了!不幸的是,事实证明,大部分问题都在其他地方,而且更难优化……:-(