c# MVC Site Map - very slow when using roles - very slow

后端 未结 2 1500
感情败类
感情败类 2021-01-28 18:53

I\'ve installed MVC Site Map Provider for MVC5 and just used everything out of the the box. It works fine. Now I want to implement roles based menu trimming so assuming my contr

相关标签:
2条回答
  • 2021-01-28 19:05

    Although there is a bug posted for Route values not preserved correctly in v4?

    But looks like it was fixed in version 4 next release.

    Another Workaround to fix this problem is cache here is a related article.

    MVC siteMap provider cache

    0 讨论(0)
  • 2021-01-28 19:20

    The security trimming feature relies on creating a controller instance for every node in order to determine if the current user context has access.

    The most likely cause of this slowness is that your controllers (or their base class) have too much heavy processing happening in the constructor.

    public class HomeController
    {
        public HomeController() {
            // Lots of heavy processing
            System.Threading.Thread.Sleep(300);
        };
    }
    

    The above example will add 300 ms to the page load time for every node that represents an action method in the HomeController. If your other controllers also have heavy processing during instantiation, they will also add additional time to each page load.

    When following DI best practices, this is not an issue because heavy processing takes place in external services after the controller instance is created.

    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();
        }
    }
    

    Notice in the above example that no heavy processing happens in the constructor? This means that creating an instance of HomeController is very cheap. It also means that action methods that don't require the heavy processing to happen (as in About() and Contact() in the example) won't take the hit of heavy processing required by Index().

    If not using DI, MVC still requires that a new controller instance be created for each request (controller instances are never shared between users or action methods). Although, in that case it is not as noticeable on a per user basis because only 1 instance is created per user. Basically, MvcSiteMapProvider is slowing down because of a pre-existing issue with your application (which you can now fix).

    Even if you are not using DI, it is still a best practice to defer heavy processing until after the controller instance is created.

    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();
        }
    }
    

    But if moving heavy processing into external services in your application is not an option, you can still defer processing until its needed by moving the processing into another method so it is not too expensive to create controller instances.

    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();
        }
    }
    
    0 讨论(0)
提交回复
热议问题