我使用MvcSiteMapProvider设置了面包屑。 我有一个具有一些静态节点的结构,然后在一些叶子上有使用asp.net属性添加的动态节点。
[MvcSiteMapNode(DynamicNodeProvider = "Web.DealerNet.CommonFramework.UserDynamicNodeProvider)]
这样做很好,但是当你深入了解时,性能真的非常糟糕,因为在启动时所有用户都被加载到内存中,并且每个用户都创建了一个节点。 这是official docu中建议的方法。有没有办法在这里使用延迟加载? (在真正调用时加载用户对象的属性,而不是为每个用户创建一个节点......我有20k个用户......)
public class UserDynamicNodeProvider : DynamicNodeProviderBase
{
public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node)
{
UserDao dao = DependencyResolver.Current.GetService<UserDao>();
// Create a node for each element
foreach (User user in dao.GetAll())
{
DynamicNode dynamicNode = new DynamicNode();
dynamicNode.Title = user.UserName;
dynamicNode.Description = user.UserName;
dynamicNode.RouteValues.Add("id", user.IdUser);
dynamicNode.ParentKey = "TheParentKey";
dynamicNode.Clickable = false;
dynamicNode.Area = "MyArea";
yield return dynamicNode;
}
}
}
答案 0 :(得分:2)
目前不支持延迟加载(尽管为v5计划添加请求级节点)。
目前,用户列表听起来并不像您需要在搜索引擎中编制索引(除非您正在构建社交网站)。每个用户在/sitemap.xml端点中都不需要单独的条目。因此,为每个用户添加节点没什么价值。
如果是这种情况,更好的方法是使用savedRouteParameters强制所有请求匹配单个节点,然后使用visibility providers和SiteMapTitleAttribute调整Menu和SiteMapPath HTML帮助程序的显示方式
[MvcSiteMapNode(Area="MyArea", PreservedRouteParameters="id", Clickable="False")]
在您的控制器操作中,将节点(或其父节点)的标题设置为正确的用户。
[SiteMapTitle("UserName")]
public ViewResult Details(int id) {
UserDao dao = DependencyResolver.Current.GetService<UserDao>();
// This example assumes your user model object has a public property "UserName"
var user = dao.Find(id);
return View(user);
}
这将复制每个请求上的id,使其与每个请求匹配,为breadcrumb路径中的每个用户提供一个节点的外观。通常,您需要使用FilteredSiteMapNodeVisibilityProvider从菜单中隐藏此“ghost”节点 - 使用此方法时,无法列出菜单中的所有用户。如果您需要所有用户的列表,我建议您创建一个直接从数据库加载的列表。
在帖子How to Make MvcSiteMapProvider Remember a User's Position上查看一些可下载的演示。
另一方面,如果 构建一个社交网站,我会建议extending the cache,以便它缓存到磁盘而不是将其全部保存在内存中。这不会改善初始启动时间,但会阻止您耗尽所有服务器的内存。在线提供了open source file cache和一些instructions on how you could build your implmentation。如果您对重新加载缓存的频率非常小心,这种方法可能对您有用。
可能导致性能问题的另一个问题是您使用DependencyResolver作为服务定位器(anti-pattern)。假设您正在使用外部DI,通过构造函数注入依赖项可确保您的DI容器(而不是应用程序)可以控制对象的生命周期。
public class UserDynamicNodeProvider : DynamicNodeProviderBase
{
private readonly UserDao userDao;
public UserDynamicNodeProvider(UserDao userDao)
{
if (userDao == null)
throw new ArgumentNullException("userDao");
this.userDao = userDao;
}
public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node)
{
// Create a node for each element
foreach (User user in this.userDao.GetAll())
{
DynamicNode dynamicNode = new DynamicNode();
dynamicNode.Title = user.UserName;
dynamicNode.Description = user.UserName;
dynamicNode.RouteValues.Add("id", user.IdUser);
dynamicNode.ParentKey = "TheParentKey";
dynamicNode.Clickable = false;
dynamicNode.Area = "MyArea";
yield return dynamicNode;
}
}
}
Microsoft不鼓励在您自己的应用程序代码中使用DependencyResolver.Current(请参阅Professional ASP.NET MVC 4,Wrox Press,第308页 - 由Jon Galloway,Phil Haack,Brad Wilson和K. Scott Allen撰写),以及如此紧密地将你的类绑定到MVC框架。