安全修剪功能依赖于为每个节点创建一个控制器实例,以确定当前用户上下文是否具有访问权限。
这种缓慢的最可能原因是您的控制器(或其基类)在构造函数中发生了过多的繁重处理。
public class HomeController
{
public HomeController() {
// Lots of heavy processing
System.Threading.Thread.Sleep(300);
};
}
上面的示例将为HomeController 中表示操作方法的每个节点增加 300 毫秒的页面加载时间。如果您的其他控制器在实例化期间也有繁重的处理,它们也会为每个页面加载增加额外的时间。
当遵循 DI 最佳实践时,这不是问题,因为在创建控制器实例后,外部服务中会进行繁重的处理。
public interface IHeavyProcessingService
{
IProcessingResult DoSomethingExpensive();
}
public class HeavyProcessingService : IHeavyProcessingService
{
public HeavyProcessingService() {
}
public IProcessingResult DoSomethingExpensive() {
// Lots of heavy processing
System.Threading.Thread.Sleep(300);
}
}
public class HomeController
{
private readonly IHeavyProcessingService heavyProcessingService;
// The constructor does no heavy processing. It is deferred until after
// the instance is created by HeavyProcessingService.
// The only thing happening here is assignment of dependencies.
public HomeController(IHeavyProcessingService heavyProcessingService) {
if (heavyProcessingService == null)
throw new ArgumentNullException("heavyProcessingService");
this.heavyProcessingService = heavyProcessingService;
};
public ActionResult Index()
{
var result = this.heavyProcessingService.DoSomethingExpensive();
// Do something with the result of the heavy processing
return View();
}
public ActionResult About()
{
return View();
}
public ActionResult Contact()
{
return View();
}
}
注意到在上面的例子中,构造函数中没有进行繁重的处理吗?这意味着创建HomeController 的实例非常便宜。这也意味着不需要进行繁重处理的操作方法(如示例中的About() 和Contact())不会受到Index() 所需的繁重处理的影响。
如果不使用 DI,MVC 仍然需要为每个请求创建一个新的控制器实例(控制器实例永远不会在用户或操作方法之间共享)。但是,在这种情况下,每个用户的情况并不明显,因为每个用户只创建了一个实例。基本上,MvcSiteMapProvider 正在放慢速度,因为您的应用程序存在预先存在的问题(您现在可以修复)。
即使您不使用 DI,最好将繁重的处理推迟到创建控制器实例之后。
public class HomeController
{
private readonly IHeavyProcessingService heavyProcessingService;
public HomeController() {
this.heavyProcessingService = new HeavyProcessingService();
};
public ActionResult Index()
{
var result = this.heavyProcessingService.DoSomethingExpensive();
// Do something with the result of the heavy processing
return View();
}
}
但是,如果不能将繁重的处理转移到应用程序的外部服务中,您仍然可以通过将处理转移到另一种方法来推迟处理直到需要处理,这样创建控制器实例的成本不会太高。
public class HomeController
{
public HomeController() {
};
private IProcessingResult DoSomethingExpensive() {
// Lots of heavy processing
System.Threading.Thread.Sleep(300);
}
public ActionResult Index()
{
var result = this.DoSomethingExpensive();
// Do something with the result of the heavy processing
return View();
}
}