Reputation: 3024
I have this folder structure for my new Area
This is how I set it up in my startup:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "areas",
template: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
);
});
This is how I created my basecontroller
namespace App.Areas.Applications.Controllers
{
[Area("Applications")]
[Authorize]
public abstract class ApplicationsBaseController : Controller
{
}
}
My ApplicationsController then inherits the BaseController
However, when I set a link like this
<li class="nav-item"><a asp-area="Applications" asp-controller="Applications" asp-action="Index" class="nav-link">Applications</a></li>
This is the link that shows up in my url https://localhost:44338/Applications?area=Applications and I get a page cannot be found.
What did I miss when setting up my Area?
EDIT:
When I add [Route("Applications/[controller]")] after my [Area("Applications")], I get this error
An unhandled exception occurred while processing the request. AmbiguousActionException: Multiple actions matched. The following actions matched route data and had all constraints satisfied:
App.Areas.Applications.Controllers.ApplicationsController.Index (App) App.Areas.Applications.Controllers.ApplicationsController.Create (App) App.Areas.Applications.Controllers.ApplicationsController.NewRole (App)
Upvotes: 4
Views: 7794
Reputation: 1874
you can use simple solation
Extension
public static class AreaExtension
{
public static string AreaUrl(this IHtmlHelper helper, string action, params string[] parameters)
{
var viewContext = helper.ViewContext.RouteData.Values;
string controller = (string)viewContext["controller"],
area = (string)viewContext["area"];
return GenerateUrl(action, controller, area, parameters);
}
public static string AreaUrl(this IHtmlHelper helper, string action, string controller, params string[] parameters)
{
var viewContext = helper.ViewContext.RouteData.Values;
string area = (string)viewContext["area"];
return GenerateUrl(action, controller, area, parameters);
}
public static string AreaUrl(this IHtmlHelper helper, string action, string controller, string area, params string[] parameters)
=> GenerateUrl(action, controller, area, parameters);
private static string GenerateUrl(string action, string controller, string area, params string[] parameters)
{
if (action == null)
throw new ArgumentNullException(nameof(controller));
if (controller == null)
throw new ArgumentNullException(nameof(action));
string urlParams = string.Empty;
if (parameters != null && parameters.Length > 0)
urlParams = "?" + string.Join("&", parameters);
return "/" + string.Join("/", area, controller, action) + urlParams;
}
}
Usage
Incluse namespase AreaExtension
in _ViewImports.cshtml
<li class="nav-item"><a href="@Html.AreaUrl("Index", "Applications","Applications")" class="nav-link">Applications</a></li>
This AreaExtension have 3 overload
Upvotes: 0
Reputation: 41
There is another option which does bring some clarification in terms of meta data of the code:
Using MapAreaRoute extension method in Namespace: Microsoft.AspNetCore.Builder
Here is an example:
routes.MapAreaRoute(
name: "AdminArea",
areaName: "Admin",
template: Admin/{controller=Home}/{action=Index}/{id?}");
It is available from .NET Core 1.0
Upvotes: 0
Reputation: 3024
I realized what the issue was. In each controller, I needed to declare [Area="AreaName"] in the top before anything else so that the routing worked.
Thank you everyone for your help.
Upvotes: 0
Reputation: 29986
IMO, you should create Controller
folder to the specific views. Otherwise, it will fail when there are multiple controllers in the Applications
area.
Anyway, for returning the views just in Views Folder
, try to configure the AreaViewLocationFormats
to specify the views search location.
public void ConfigureServices(IServiceCollection services)
{
//rest services
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1).AddSessionStateTempDataProvider();
services.Configure<RazorViewEngineOptions>(o =>
{
o.AreaViewLocationFormats.Add("/Areas/{2}/{0}" + RazorViewEngine.ViewExtension);
});
}
Upvotes: 0
Reputation: 1147
Put it before the default route... like this
app.UseMvc(routes =>
{
routes.MapRoute(
name: "areas",
template: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
);
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
Upvotes: 12