C# ASP.NET获取数据太慢

C# ASP.NET获取数据太慢,c#,asp.net,angularjs,C#,Asp.net,Angularjs,我目前正在使用ASP.NET MVC和Angular开发一个web应用程序。我希望能够根据每个用户的角色为其获取一个导航项列表,将它们全部存储在一个对象列表中,并将其序列化为JSON以返回到angular 我的方法目前运行得很好,但是当我的页面在不到一秒钟内加载时,数据到达页面至少需要5秒钟。因此,我的用户只是坐在那里等待navitems弹出,这是不好的 以下是我使用的两种方法: public NavDirectoryViewModel GetAllUserNavItems(string Use

我目前正在使用ASP.NET MVC和Angular开发一个web应用程序。我希望能够根据每个用户的角色为其获取一个导航项列表,将它们全部存储在一个对象列表中,并将其序列化为JSON以返回到angular

我的方法目前运行得很好,但是当我的页面在不到一秒钟内加载时,数据到达页面至少需要5秒钟。因此,我的用户只是坐在那里等待navitems弹出,这是不好的

以下是我使用的两种方法:

public NavDirectoryViewModel GetAllUserNavItems(string UserId)
{
    NavDirectoryViewModel model = new NavDirectoryViewModel();
    model.NavItems = new List<NavViewModel>();
    foreach (var nav in GetAllNavItems())
    {
        if (GetUserNavItem(UserId, nav) != null)
        {
            if (nav.ParentId == 0)
                model.NavItems.Add(GetUserNavItem(UserId, nav));
        }
    }
    model.NavItems = model.NavItems.OrderBy(x => x.SortOrder).ToList();
    return model;
}

public NavViewModel GetUserNavItem(string UserId, NavModel model)
{

    try
    {
        if(model.AllowedUsers.FirstOrDefault(x => x.UserId.Equals(UserId)) != null || model.AllowedRoles.FirstOrDefault(x => x.Role.Users.FirstOrDefault(y => y.UserId.Equals(UserId)) != null) != null)
        {
            return new NavViewModel { Name = model.Name, Href = model.Href, Image = model.Image, SortOrder = model.SortOrder, SubItems = GetNavItems(model.Id).Where(x => x.ParentId == model.Id).Select(x => GetUserNavItem(UserId, x)).ToList() };
        }
        else
        {
            return null;
        }
    }
    catch(Exception e1) { return null; }
}

嗯,你应该重新考虑你的模型。你把安全问题和实际的[导航数据]混为一谈,这就是为什么你不得不拿出这么多信息来验证用户的身份

这就是说,您有很多链接的LINQ查询,如果您深入研究,这些查询可能会导致执行大量SQL。请尝试以下方法:

public NavDirectoryViewModel GetAllUserNavItems(string userId)
{
    NavDirectoryViewModel model = new NavDirectoryViewModel();
    model.Items = GetNavItems(0, userId).OrderBy(x => x.SortOrder);
    return model;
}

private static IEnumerable<NavViewModel> GetNavItems(int parentId, string userId)
{
    List<NavViewModel> items = new List<NavViewModel>();
    var children = GetAllNavItems(parentId);
    foreach (var child in children)
    {
        if (child.IsUserAllowed(userId))
        {
            var navItem = new NavViewModel() { Name = child.Name, Href = child.Href, Image = child.Image, SortOrder = child.SortOrder };
            navItem.SubItems = GetNavItems(child.Id, userId);
            items.Add(navItem);
        }
    }
    return items;
}
注意在LINQ查询中使用了任何vs FirstOrDefault

这种修改应该会给您带来相当快的速度,因为您将不会提取不需要的数据,并且将避免所有嵌套查询。您还在很多地方调用ToList(),这会导致执行查询并将数据投影到对象中

尽管如此,你的模型还是需要修改。拉取的数据太多了


我在几分钟内就解决了这个问题,所以请检查错误/语义,但这应该会让您了解如何提高性能。

第一个问题是,您调用
GetUserNavItem
两次,一次在
if(GetUserNavItem(UserId,nav)!=null)
中,然后再次调用
if(nav.ParentId==0)
,您可以进行一次调用,将其分配给一个变量,然后使用变量值,而不是再次调用该方法。如果您共享更多代码,这会有所帮助。一般来说,最好是a)从数据库加载所有可能的导航节点并缓存它-在我看来,您正在逐节点加载它b)根据用户请求从缓存的节点列表中选择有效的节点(在a中检索)要构建导航树,另一个问题是在这里调用GetUserNavItem和GetNavItems时的递归,这将运行这些昂贵的查询。。。它需要重大的重构。还有其他更有效的方法来存储/构建导航树。不过,在这种情况下,缓存至少对您现在的操作有所帮助。这太棒了!它把速度提高了一两秒钟,比原来好多了!谢谢你的建议。我很高兴能帮上忙。:-)
if (HttpContext.Cache[User.Identity.GetUserId() + "NAV"] == null)
{
    string NavJSON = JsonConvert.SerializeObject(nrepo.GetAllUserNavItems(User.Identity.GetUserId()), Formatting.Indented, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
    HttpContext.Cache[User.Identity.GetUserId() + "NAV"] = NavJSON;
    return Json(NavJSON, JsonRequestBehavior.AllowGet);
}
else
{
    string NavJSON = HttpContext.Cache[User.Identity.GetUserId() + "NAV"].ToString();
    return Json(NavJSON, JsonRequestBehavior.AllowGet);
}
public NavDirectoryViewModel GetAllUserNavItems(string userId)
{
    NavDirectoryViewModel model = new NavDirectoryViewModel();
    model.Items = GetNavItems(0, userId).OrderBy(x => x.SortOrder);
    return model;
}

private static IEnumerable<NavViewModel> GetNavItems(int parentId, string userId)
{
    List<NavViewModel> items = new List<NavViewModel>();
    var children = GetAllNavItems(parentId);
    foreach (var child in children)
    {
        if (child.IsUserAllowed(userId))
        {
            var navItem = new NavViewModel() { Name = child.Name, Href = child.Href, Image = child.Image, SortOrder = child.SortOrder };
            navItem.SubItems = GetNavItems(child.Id, userId);
            items.Add(navItem);
        }
    }
    return items;
}
public bool IsUserAllowed(string userId)
{
    return AllowedUsers.Any(x => x.UserId.Equals(userId)) || AllowedRoles.SelectMany(r => r.Role.Users).Any(y => y.UserId.Equals(userId));
}