Our solution hierarchy is as follows:
ControllerCategoryView
Ex:
ControllersDataAnalysisDataRetrieve
Now I'd like to map the routing so that when the user just types the name of the view in the url, it automatically maps the url to the corresponding controller
I.E: localhost:1234DataAnalysisDataRetrieve
Should map to
ViewDataAnalysisDataRetrieveIndex.cshtml
Similarly, any url requests including the action should retrieve the corresponding view
I.E: localhost:1234DataAnalysisDataRetrieveTestAction
Should map to
ViewDataAnalysisDataRetrieveTestAction.cshtml
Currently, we're using the default routing
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 }
);
}
Which means if I type the URL shown above, it ignores the category and fails to return the view.
Is there a way to customize routing to get the behavior above?
--Edit
To clarify my question based on the comments, here's a screenshot of my solution explorer
Now if I call localhost:12346/DataAnalysis/DataRetrieve, this should take me to the index. Routing this isn't a problem as I can do something like this:
routes.MapRoute(
name: "ExampleRouting",
url: "{category}/{controller}/{action}"
);
But here's the issue. I'd also like to organize my file structure like this:
By default, when I try to retrieve the index of dataretrieve, it looks under ViewsDataRetrieveIndex not ViewsDataAnalysisDataRetrieveIndex.
How can I change this behavior?
Edit2------------------------
Based on the answer, I've added a custom view engine, registered it in Application_Start, updated my routing. Still having an identical issue.
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 (Custom View Engine)
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));
}
}
See Question&Answers more detail:
os