我有一個MVC的網站,我們正在使用MVCSiteMapProvider 4.4.3與Autofac。我們使用XML和屬性的混合構建我們的網站。我們有幾百個動態節點,並且我們已啓用安全修整。過去一年,網站已經增加了大約120個控制器。所有控制器都使用根據角色而不同的授權屬性進行保護。MVC站點地圖提供程序 - SiteMapPath性能非常慢?
在我們的佈局中,我們調用@Html.MvcSiteMap().SiteMapPath()
,這會在頁面加載時間內增加大約950ms。如果我們刪除該行,我們的頁面幾乎立即加載。
我們用來進行第二次加載菜單 - 但是我們把它放在一個和的RenderAction簡單緩存這在很大程度上修復了問題的結果。
這是常見的表現?是否有增強的SiteMapPath或事物表現任何明顯的方式,可能會導致性能是如此之差
如果我們刷新頁面需要第二次,只要第一
只是瀏覽約十頁剖析但CPU個循環的約70%似乎已經到:
MvcSiteMapProvider.Caching.RequestCache.GetValue(String)
MvcSiteMapProvider.RequestCacheableSiteMapNode.GetCacheKey(String)
MvcSiteMapProvider.Collections.Specialized.RouteValueDictionary.GetCacheKey()
MvcSiteMapProvider.RequestCacheableSiteMap.GetCacheKey(String)
MvcSiteMapProvider.Web.Mvc.MvcContextFactory.CreateHttpContext(ISiteMapNode)
MvcSiteMapProvider.RequestCacheableSiteMapNode.get_AreRouteParametersPreserved()
MvcSiteMapProvider.SiteMap.GetChildNodes(ISiteMapNode)
MvcSiteMapProvider.SiteMap.FindSiteMapNodeFromControllerAction(ISiteMapNode, IDictionary[StringObject], RoutMvcSiteMapProvider.Collections.CacheableDictionary`2.ContainsKey(TKey)
eBase)
MvcSiteMapProvider.RequestCacheableSiteMap.IsAccessibleToUser(ISiteMapNode)
MvcSiteMapProvider.Collections.CacheableDictionary`2.get_ReadOperationDictionary()
總來電來MVCSiteMapProvder命名空間分別爲4.34億VS 100萬所有我們自己的代碼的命名空間。
我們Autofac模塊:
public class MvcSiteMapProviderModule : global::Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
const bool SecurityTrimmingEnabled = false;
const bool EnableLocalization = false;
var absoluteFileName = HostingEnvironment.MapPath("~/Mvc.sitemap");
var absoluteCacheExpiration = TimeSpan.FromMinutes(60);
var includeAssembliesForScan = new[] { "OnboardWeb" };
var currentAssembly = this.GetType().Assembly;
var siteMapProviderAssembly = typeof(SiteMaps).Assembly;
var allAssemblies = new Assembly[] { currentAssembly, siteMapProviderAssembly };
var excludeTypes = new Type[]
{
typeof(SiteMapNodeVisibilityProviderStrategy),
typeof(SiteMapXmlReservedAttributeNameProvider),
typeof(SiteMapBuilderSetStrategy)
};
var multipleImplementationTypes = new Type[]
{
typeof(ISiteMapNodeUrlResolver),
typeof(ISiteMapNodeVisibilityProvider),
typeof(IDynamicNodeProvider)
};
// Single implementations of interface with matching name (minus the "I").
CommonConventions.RegisterDefaultConventions(
(interfaceType, implementationType) => builder.RegisterType(implementationType).As(interfaceType).SingleInstance(),
new Assembly[] { siteMapProviderAssembly },
allAssemblies,
excludeTypes,
string.Empty);
// Multiple implementations of strategy based extension points
CommonConventions.RegisterAllImplementationsOfInterface(
(interfaceType, implementationType) => builder.RegisterType(implementationType).As(interfaceType).SingleInstance(),
multipleImplementationTypes,
allAssemblies,
excludeTypes,
"^Composite");
// Registration of internal controllers
CommonConventions.RegisterAllImplementationsOfInterface(
(interfaceType, implementationType) => builder.RegisterType(implementationType).As(interfaceType).AsSelf().InstancePerDependency(),
new Type[] { typeof(IController) },
new Assembly[] { siteMapProviderAssembly },
new Type[0],
string.Empty);
// Visibility Providers
builder.RegisterType<SiteMapNodeVisibilityProviderStrategy>()
.As<ISiteMapNodeVisibilityProviderStrategy>()
.WithParameter("defaultProviderName", string.Empty);
//.WithParameter("defaultProviderName", "MvcSiteMapProvider.FilteredSiteMapNodeVisibilityProvider, MvcSiteMapProvider");
//builder.RegisterType<BreadCrumbOnlyVisibilityProvider>()
// .As<ISiteMapNodeVisibilityProvider>().InstancePerLifetimeScope();
// Pass in the global controllerBuilder reference
builder.RegisterInstance(ControllerBuilder.Current)
.As<ControllerBuilder>();
builder.RegisterType<BuildManagerAdaptor>()
.As<IBuildManager>();
builder.RegisterType<ControllerBuilderAdaptor>()
.As<IControllerBuilder>();
builder.RegisterType<ControllerTypeResolverFactory>()
.As<IControllerTypeResolverFactory>()
.WithParameter("areaNamespacesToIgnore", new string[0]);
// Configure Security
builder.RegisterType<AuthorizeAttributeAclModule>()
.Named<IAclModule>("authorizeAttributeAclModule");
builder.RegisterType<XmlRolesAclModule>()
.Named<IAclModule>("xmlRolesAclModule");
builder.RegisterType<CompositeAclModule>()
.As<IAclModule>()
.WithParameter(
(p, c) => p.Name == "aclModules",
(p, c) => new[]
{
c.ResolveNamed<IAclModule>("authorizeAttributeAclModule"),
c.ResolveNamed<IAclModule>("xmlRolesAclModule")
});
builder.RegisterInstance(System.Runtime.Caching.MemoryCache.Default)
.As<System.Runtime.Caching.ObjectCache>();
builder.RegisterGeneric(typeof(RuntimeCacheProvider<>))
.As(typeof(ICacheProvider<>));
builder.RegisterType<RuntimeFileCacheDependency>()
.Named<ICacheDependency>("cacheDependency1")
.WithParameter("fileName", absoluteFileName);
builder.RegisterType<CacheDetails>()
.Named<ICacheDetails>("cacheDetails1")
.WithParameter("absoluteCacheExpiration", absoluteCacheExpiration)
.WithParameter("slidingCacheExpiration", TimeSpan.MinValue)
.WithParameter(
(p, c) => p.Name == "cacheDependency",
(p, c) => c.ResolveNamed<ICacheDependency>("cacheDependency1"));
// Configure the visitors
builder.RegisterType<UrlResolvingSiteMapNodeVisitor>()
.As<ISiteMapNodeVisitor>();
// Prepare for our node providers
builder.RegisterType<FileXmlSource>()
.Named<IXmlSource>("xmlSource1")
.WithParameter("fileName", absoluteFileName);
builder.RegisterType<SiteMapXmlReservedAttributeNameProvider>()
.As<ISiteMapXmlReservedAttributeNameProvider>()
.WithParameter("attributesToIgnore", new string[0]);
// Register the sitemap node providers
builder.RegisterType<XmlSiteMapNodeProvider>()
.Named<ISiteMapNodeProvider>("xmlSiteMapNodeProvider1")
.WithParameter("includeRootNode", true)
.WithParameter("useNestedDynamicNodeRecursion", false)
.WithParameter(
(p, c) => p.Name == "xmlSource",
(p, c) => c.ResolveNamed<IXmlSource>("xmlSource1"));
builder.RegisterType<ReflectionSiteMapNodeProvider>()
.Named<ISiteMapNodeProvider>("reflectionSiteMapNodeProvider1")
.WithParameter("includeAssemblies", includeAssembliesForScan)
.WithParameter("excludeAssemblies", new string[0]);
builder.RegisterType<CompositeSiteMapNodeProvider>()
.Named<ISiteMapNodeProvider>("siteMapNodeProvider1")
.WithParameter(
(p, c) => p.Name == "siteMapNodeProviders",
(p, c) => new[]
{
c.ResolveNamed<ISiteMapNodeProvider>("xmlSiteMapNodeProvider1"),
c.ResolveNamed<ISiteMapNodeProvider>("reflectionSiteMapNodeProvider1")
});
// Register the sitemap builders
builder.RegisterType<SiteMapBuilder>()
.Named<ISiteMapBuilder>("siteMapBuilder1")
.WithParameter(
(p, c) => p.Name == "siteMapNodeProvider",
(p, c) => c.ResolveNamed<ISiteMapNodeProvider>("siteMapNodeProvider1"));
// Configure the builder sets
builder.RegisterType<SiteMapBuilderSet>()
.Named<ISiteMapBuilderSet>("builderSet1")
.WithParameter("instanceName", "default")
.WithParameter("securityTrimmingEnabled", SecurityTrimmingEnabled)
.WithParameter("enableLocalization", EnableLocalization)
.WithParameter(
(p, c) => p.Name == "siteMapBuilder",
(p, c) => c.ResolveNamed<ISiteMapBuilder>("siteMapBuilder1"))
.WithParameter(
(p, c) => p.Name == "cacheDetails",
(p, c) => c.ResolveNamed<ICacheDetails>("cacheDetails1"));
builder.RegisterType<SiteMapBuilderSetStrategy>()
.As<ISiteMapBuilderSetStrategy>()
.WithParameter(
(p, c) => p.Name == "siteMapBuilderSets",
(p, c) => c.ResolveNamed<IEnumerable<ISiteMapBuilderSet>>("builderSet1"));
}
}
}
我們有一個動態節點提供商加入幾百個節點(如果我們把它關掉它比較快,但不顯著左右)
public class LocationsDynamicNodeProvider : DynamicNodeProviderBase
{
private List<Country> countries;
/// <summary>
/// Lazy loading of countries. Only create the graph when we actually need it.
/// Previously it was in the constructor, but for lightweight object composition we must
/// not do any work in the constructor.
/// </summary>
/// <returns></returns>
private List<Country> GetCountries()
{
if (countries == null)
{
var countryRepository = DependencyResolver.Current.GetService<ICountryRepository>();
countries = countryRepository.AllWithLocations().ToList();
}
return countries;
}
public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node)
{
countries = GetCountries();
foreach (var country in countries)
{
var countrynode = new DynamicNode
{
Title = country.Name,
Controller = "Assets",
Action = "Index",
Area = "OnboardAsset",
RouteValues = new RouteValueDictionary
{
{ "countryname", country.Name },
{ "locationname", "" },
{ "sitename", "" }
},
ParentKey = "All Assets",
Key = "countrynode_" + country.CountryId
};
yield return countrynode;
foreach (var site in country.Sites)
{
var sitenode = new DynamicNode
{
Title = site.Name,
Controller = "Assets",
Action = "Index",
Area = "OnboardAsset",
RouteValues =
new RouteValueDictionary()
{
{ "countryname", country.Name },
{ "sitename", site.Name },
{ "locationname", "" }
},
ParentKey = "countrynode_" + country.CountryId,
Key = "sitenode_" + site.SiteId
};
yield return sitenode;
foreach (var location in site.Locations)
{
var locationNode = new DynamicNode
{
Title = location.Name,
Controller = "Assets",
Action = "Index",
Area = "OnboardAsset",
RouteValues =
new RouteValueDictionary
{
{ "countryname", country.Name },
{ "sitename", site.Name },
{ "locationname", location.Name }
},
ParentKey = "sitenode_" + site.SiteId
};
yield return locationNode;
}
}
}
}
}
}
地圖配置:
<mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0" xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0 MvcSiteMapSchema.xsd">
<mvcSiteMapNode title="Home" controller="HomePage" action="Index" key="Home">
<mvcSiteMapNode title="People" key="PeopleTop" controller="People" action="Index" area="OnboardTeam" >
<mvcSiteMapNode title="All People" key="PeopleIndex" controller="People" action="Index" area="OnboardTeam" visibility="hideChildren" />
</mvcSiteMapNode>
<mvcSiteMapNode title="Assets" key="Assets" controller="Home" action="Index" area="OnboardAsset">
<mvcSiteMapNode title="All Assets" key="All Assets" controller="Assets" action="Index" route="AllAssets">
<mvcSiteMapNode title="LocationNodes" dynamicNodeProvider="Onboard.Web.Infrastructure.Menu.LocationsDynamicNodeProvider, OnboardWeb" />
</mvcSiteMapNode>
</mvcSiteMapNode>
<mvcSiteMapNode title="Jobs" controller="Jobs" action="Index" area="Core" key="Jobs" visibility="hideChildren" />
<mvcSiteMapNode title="Reports" key="Report" clickable="false">
<mvcSiteMapNode title="Certifications" key="Report_Certifications" clickable="false" />
</mvcSiteMapNode>
<mvcSiteMapNode title="CRM" controller= "CRM" area="CRM" key="CRM" action="Index">
</mvcSiteMapNode>
<mvcSiteMapNode title="PO" key="PO" action="GeneralList" controller= "PurchaseOrders">
<mvcSiteMapNode title="Purchase Orders" action="GeneralList" controller= "PurchaseOrders" area="PO" key="PO_List" />
</mvcSiteMapNode>
<mvcSiteMapNode title="Training" key="OnboardTraining" controller="PersonTrainingBookings" action="Index" />
<mvcSiteMapNode title="Document Store" key="Documents" area="Documents" controller="DocumentStore" action="Browse" />
<mvcSiteMapNode title="Admin" key="Admin" roles="Administrator" clickable="false">
<mvcSiteMapNode title="Competence" key="Competences" area="OnboardTeam" controller="Competences" action="Index" />
<mvcSiteMapNode title="Certification" key="Certifications" area="OnboardTeam" controller="Certification" action="Index" />
<mvcSiteMapNode title="Supporting Entities" key="LookupTable" clickable="false" />
<mvcSiteMapNode title="Entity Types" key="LookupTypes" clickable="false" />
<mvcSiteMapNode title="Users and Teams" key="UsersAndTeams" area="Core" controller="UserManagement" action="Index" clickable="false" />
<mvcSiteMapNode title="Companies" key="Organisations" area="Core" controller="Companies" action="Index" clickable="false" />
<mvcSiteMapNode title="Geographic Data" key="Geographic" area="Core" controller="Countries" action="Index" clickable="false" />
</mvcSiteMapNode>
</mvcSiteMapNode>
</mvcSiteMap>
其餘節點正在使用屬性添加控制器操作
我們在釋放模式
你們中的大多數已經張貼是專門通過請求高速緩存以提高性能的方法。你可以發佈你的節點配置(包括動態節點提供者)和你的Autofac模塊嗎?另外,如果禁用安全修整,性能如何比較? – NightOwl888
已更新。看起來似乎有很多行代碼被執行。更新配置等。禁用安全修整沒有任何重大差異。 – GraemeMiller
事實上,你接到這麼多的電話是非常不尋常的,我懷疑它與你的配置中的某些東西有關。您可以將您的設置與MvcMusicStore demo @ GitHub進行比較,該演示演示瞭如何與數百個動態節點和Autofac(Autofac的編譯符號集)一起工作。但最好的選擇是構建一個小型的演示項目,重現行爲,使其可以下載,並開啓一個新的問題@ GitHub。你甚至可以在構建演示時解決它。 – NightOwl888