ASP.NET MVC routing options not working with scopes

I am currently playing around with scopes and routing within them. What I am trying to achieve is to have a url that looks like this:

PracticeAdmin/Practice/[Practice Name]

      

after which I could add things like Edit and Delete to the end.

I have achieved this in the past when not working with scopes by adding this annotation to the action

[Route("PracticeAdmin/Practices/{practiceName}")]
public ActionResult Details(string practiceName)

      

this will bring up the urls that I would like. The problem I'm running into is that when I try to do this while using scopes, I get links that look like this:

PracticeAdmin/Practices?practiceName=Practice1

      

which is not what I am looking for.

The code I am using to try and accomplish this with

PracticeAdminAreaRegistration.cs

using System.Web.Mvc;

namespace TrainingPortal.Areas.PracticeAdmin
{
    public class PracticeAdminAreaRegistration : AreaRegistration 
    {
        public override string AreaName 
        {
            get 
            {
                return "PracticeAdmin";
            }
        }

        public override void RegisterArea(AreaRegistrationContext context) 
        {
            context.MapRoute(
                "PracticeAdmin_default",
                "PracticeAdmin/{controller}/{action}/{id}",
                new { action = "Index", id = UrlParameter.Optional },
                new[] { "TrainingPortal.Areas.PracticeAdmin.Controllers" }
            );
        }
    }
}

      

RouteConfig.cs

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

            routes.MapMvcAttributeRoutes();

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

      

I named MapMvcAttributeRoutes here, which I believe should mean that routes are registered even within areas. I also tried to put the required code in PracticeAdminAreaRegistration to do the same without effect.

PracticeAdminController.cs

namespace TrainingPortal.Areas.PracticeAdmin.Controllers
{
    public partial class PracticesController : Controller
    {
        private TpContext db = new TpContext();

        // GET: PracticeAdmin/Practices
        public virtual ActionResult Index()
        {
            return View(db.Practices.ToList());
        }

        [Route("PracticeAdmin/Practice/{practiceName}")]
        public virtual ActionResult Details(string practiceName)
        {
            if (string.IsNullOrWhiteSpace(practiceName))
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Practice practice = db.Practices.FirstOrDefault(m => m.PracticeName.ToLower() == practiceName);
            if (practice == null)
            {
                return HttpNotFound();
            }
            return View(practice);
        }
        ...

      

Obviously this happens with other methods, but they all follow the same approach as this one.

index.cshtml snippet

@Html.ActionLink("Delete", MVC.PracticeAdmin.Practices.Delete(item.PracticeName))
@Html.ActionLink("Delete2", "Delete", new { practiceName = item.PracticeName })

      

As part of PracticeAdminArea / Views / Practices / Index.cshtml I tried to use both T4MVC and the normal ActionLink approach, which generate the exact same link (no surprise).

Summary

I have no idea why the Routes I have given do not show up when I try to create an ActionLink in the scope, so I was wondering if anyone could point me to how I can fix this and get the url to see how I do you like it?

+3


source to share


1 answer


After a little game, I was able to get it to work. The way I ended up fixing it was calling AreaRegistration.RegisterAllAreas()

from RouteConfig.RegisterRoutes()

after callingMapMvcAttributeRoutes()

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

        routes.MapMvcAttributeRoutes();

        AreaRegistration.RegisterAllAreas();

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

      

Since you are not allowed to call this method twice (or ASP.NET is very frustrated that you registered the same route names twice), I removed the call AreaRegistration.RegisterAllAreas()

from Global.asax, leaving it looking like this:

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

      

Unfortunately this alone did not solve the problem, I also had to make a couple of changes to the controller. Change is to add attributes RoutePrefix

and RouteArea

to the controller, for example:

[RouteArea("PracticeAdmin")]
[RoutePrefix("Practice")]
public partial class PracticesController : Controller
{

      



This had the added benefit of specifying a route for a specific action using an attribute, Route

you no longer needed to specify these parts, so initially the action signature would look like this:

// GET: PracticeAdmin/Practices/{practiceName}/Members
[Route("PracticeAdmin/Practices/{practiceName}/Members")]
public virtual ActionResult Members(string practiceName)
{

      

it will now look like this:

// GET: PracticeAdmin/Practices/{practiceName}/Members
[Route("{practiceName}/Members")]
public virtual ActionResult Members(string practiceName)
{

      

After making all these changes, the website behaves as expected.

+5


source







All Articles