Маршрутизация с настраиваемым представлением ASP.NET MVC

Наша иерархия решений выглядит следующим образом:

Контроллер \ Категория \View

Пример: Контроллеры \ Анализ данных \DataRetrieve

Теперь я хотел бы отобразить маршрутизацию так, чтобы, когда пользователь просто вводил имя представления в URL, он автоматически отображал URL на соответствующий контроллер.

IE: localhost:1234\DataAnalysis\DataRetrieve

Должен отображаться на

Просмотр \DataAnalysis\DataRetrieve\Index.cshtml

Аналогично, любые URL-запросы, включая действие, должны получать соответствующее представление.

IE: localhost:1234\DataAnalysis\DataRetrieve\TestAction

Должен отображаться на

Просмотр \DataAnalysis\DataRetrieve\TestAction.cshtml

В настоящее время мы используем маршрутизацию по умолчанию

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

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

Это означает, что если я введу URL-адрес, показанный выше, он игнорирует категорию и не возвращает представление.

Есть ли способ настроить маршрутизацию, чтобы получить поведение выше?

--Редактировать

Чтобы уточнить мой вопрос на основе комментариев, вот скриншот моего обозревателя решений

введите описание изображения здесь

Теперь, если я вызову localhost:12346/DataAnalysis/DataRetrieve, это приведет меня к индексу. Маршрутизация это не проблема, так как я могу сделать что-то вроде этого:

        routes.MapRoute(
            name: "ExampleRouting",
            url: "{category}/{controller}/{action}"
        );

Но вот в чем проблема. Я также хотел бы организовать мою файловую структуру следующим образом:

введите описание изображения здесь

По умолчанию, когда я пытаюсь получить индекс передачи данных, он выглядит в представлениях \DataRetrieve \ Index, а не Views \ DataAnalysis \DataRetrieve \ Index.

Как я могу изменить это поведение?

Edit2 ------------------------

Основываясь на ответе, я добавил пользовательский механизм просмотра, зарегистрировал его в Application_Start, обновил мою маршрутизацию. По-прежнему возникают идентичные проблемы.

Global.asax

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        ViewEngines.Engines.Add(new SPCViewEngine());

        BundleConfig.RegisterBundles(BundleTable.Bundles);
        AuthConfig.RegisterAuth();
    }
}

RouteConfig.cs

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


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

SPCViewEngine (механизм пользовательского просмотра)

public class SPCViewEngine : RazorViewEngine
{
    public SPCViewEngine()
        : base()
    {
        ViewLocationFormats = new[] {
            "~/Views/{1}/%1/{0}.cshtml",
            "~/Views/{1}/%1/{0}.vbhtml",
            "~/Views/Shared/{0}.cshtml",
            "~/Views/Shared/{0}.vbhtml"
        };

         PartialViewLocationFormats = new[] {
            "~/Views/%1/{1}/{0}.cshtml",
            "~/Views/%1/{1}/{0}.vbhtml",
            "~/Views/Shared/{0}.cshtml",
            "~/Views/Shared/{0}.vbhtml"
        };
    }

    protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
    {
        var categoryName = controllerContext.RouteData.Values["category"].ToString();
        return base.CreatePartialView(controllerContext, partialPath.Replace("%1", categoryName));
    }

    protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
    {
        var categoryName = controllerContext.RouteData.Values["category"].ToString();
        return base.CreateView(controllerContext, viewPath.Replace("%1", categoryName), masterPath);
    }

    protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
    {
        var categoryName = controllerContext.RouteData.Values["category"].ToString();
        return base.FileExists(controllerContext, virtualPath.Replace("%1", categoryName));
    }
}

1 ответ

Решение

Если я правильно понял ваш вопрос, вы можете создать свой собственный движок представления, который разрешает местоположение представления во время выполнения и подключается к вашему приложению.

Создайте свой собственный механизм просмотра.

    public class MyViewEngine : RazorViewEngine
{
    public MyViewEngine()
        : base()
    {
        ViewLocationFormats = new[] {
        "~/Views/{1}/%1/{0}.cshtml",
        "~/Views/{1}/%1/{0}.vbhtml",
        "~/Views/Shared/{0}.cshtml",
        "~/Views/Shared/{0}.vbhtml"
    };

    PartialViewLocationFormats = new[] {
        "~/Views/%1/{1}/{0}.cshtml",
        "~/Views/%1/{1}/{0}.vbhtml",
        "~/Views/Shared/{0}.cshtml",
        "~/Views/Shared/{0}.vbhtml"
    };
    }

    protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
    {
        var catagoryName = controllerContext.RouteData.Values["category"].ToString();
        return base.CreatePartialView(controllerContext, partialPath.Replace("%1", catagoryName));
    }

    protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
    {
        var catagoryName = controllerContext.RouteData.Values["category"].ToString();
        return base.CreateView(controllerContext, viewPath.Replace("%1", catagoryName),masterPath);
    }

    protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
    {
        var catagoryName = controllerContext.RouteData.Values["category"].ToString();
        return base.FileExists(controllerContext, virtualPath.Replace("%1", catagoryName));
    }

}

И зарегистрируйся здесь

protected void Application_Start()
{   
   AreaRegistration.RegisterAllAreas();

   RegisterGlobalFilters(GlobalFilters.Filters);
   RegisterRoutes(RouteTable.Routes);


   //Register your View Engine Here.
   ViewEngines.Engines.Add(new MyViewEngine());
}

Обновление конфигурации маршрута, по умолчанию должно быть

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{category}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", category = "DefaultCategoryName", id = UrlParameter.Optional }
        );
Другие вопросы по тегам