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?
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.