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