Search code examples
c#asp.net-mvc-5asp.net-mvc-routingautofac

How to await a service call in routes.MapRoute in MVC5


I am doing a massive overhaul on a custom CMS that I am writing in MVC5. This custom CMS has "pages" that have "urls" stored in a database. For instance if a user requested /stackoverflow in the browser and there was a page in the database with /stackoverflow listed as the url, then I am serving the database content at the specificed CoreCms/Index Controller and view with the database content as a model property. The idea is that I can use this single controller/view to serve up any page in the database.

The rewrite that I am working uses dependency injection and async calls only in the service layer. It seems that I am having a bit of trouble with the RouteConfig RegisterRoutes static method.

Here's some code...

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.IgnoreRoute("FileBrowser/{pathInfo}");

        routes.MapRoute(
            name: "CmsRoutes",
            url: "{*permalink}",
            defaults: new { controller = "CmsCorePage", action = "Index" },
            constraints: new { url = new CmsCoreRouting() }
        );

        routes.MapRoute(
           name: "ArticlesCategoryRoute",
           url: "Articles/{categoryURL}",
           defaults: new { controller = "CmsCoreArticles", action = "Index", categoryURL = UrlParameter.Optional }
        );

        routes.MapRoute(
          name: "ArticlesPostsRoute",
          url: "Articles/{categoryURL}/{postURL}",
          defaults: new { controller = "CmsCoreArticles", action = "ArticlePost", categoryURL = UrlParameter.Optional, postURL = UrlParameter.Optional }
       );

        routes.MapMvcAttributeRoutes();

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }

Note that I am rewriting old code and the constraints: new { url = new CmsCoreRouting() } is code that I intend on altering here I believe.

For reference, here is the CmsCoreRouting class...

public class CmsCoreRouting : IRouteConstraint
{

    private ICoreCmsServices _coreSvc;

    public CmsCoreRouting()
    {
    }

    public CmsCoreRouting(ICoreCmsServices coreSvc)
    {
        _coreSvc = coreSvc;
     }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (httpContext?.Request?.FilePath == null) { return false; }

        string myURL = httpContext.Request.FilePath;

        if (myURL.StartsWith("/"))
        {
            myURL = myURL.Substring(1, myURL.Length - 1);
        }

        myURL = myURL.ToLower();

        var siteId = CoreCms.Core.Settings.CoreCmsSettings.SiteId;

        var cmsPage = AsyncUtility.RunSync(() => _coreSvc.PageService.FindBySiteAndUrlAsync(siteId, myURL));

        if (cmsPage != null)
        {
            return true;
        }

        var cmsArticle = AsyncUtility.RunSync(() => _coreSvc.ArticleService.FindCategoryBySiteAndUrlAsync(siteId, myURL));

        if (cmsArticle != null)
        {
            return true;
        }

        return false;
    }


}

Problem: When MVC starts, it calls the parameterless constructor on CmsCoreRouting (because I told it to in url = new CmsCoreRouting()) but I am not sure how to both use AutoFac's DI so that I don't have to pass around my own instances of the service and repository and DbContext on this RegisterRoutes function.

Any help on this would be great. I would like to do this "right".


Solution

  • Just ask the resolver (AutoFac) to create it for you:

    routes.MapRoute(
            name: "CmsRoutes",
            url: "{*permalink}",
            defaults: new { controller = "CmsCorePage", action = "Index" },
            constraints: new { url =  DependencyResolver.Current.GetService<CmsCoreRouting>() }
        );