aspnetcore: ActionContext.RouteData.Routers empty causes ArgumentOutOfRangeException in UrlHelper (Regression from 2.1)
Describe the bug
- ActionContext.RouteData.Routers is empty collection with CompabilityVersion.Version_2_2
- UrlHelper uses direct access to zero-element, instead calling .First() or .FirstOrDefault() with emergency return of ie. NullRouter
protected IRouter Router => ActionContext.RouteData.Routers[0];
- This causes ArgumentOutOfRangeException while using UrlHelper
To Reproduce
Steps to reproduce the behavior:
- Using this version of ASP.NET Core ‘2.2’
- Run this code:
Generate new WebApi project In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddRouting(opt => opt.LowercaseUrls = true);
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddScoped<IUrlHelper>(implementationFactory =>
{
var actionContext = implementationFactory.GetService<IActionContextAccessor>().ActionContext;
return new UrlHelper(actionContext);
});
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
TestController.cs
using Microsoft.AspNetCore.Mvc;
[Route("api/test")]
public class TestController : Controller
{
protected IUrlHelper UrlHelper {get;set;}
public TestController(IUrlHelper urlHelper)
{
UrlHelper = urlHelper;
}
[HttpGet]
public IActionResult ListAsync()
{
var res = UrlHelper.Action(nameof(ListAsync));
return Ok(res);
}
}
- Execute action GET /api/test
- See error:
ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
System.Collections.Generic.List<T>.get_Item(int index)
Microsoft.AspNetCore.Mvc.Routing.UrlHelper.get_Router()
Microsoft.AspNetCore.Mvc.Routing.UrlHelper.GetVirtualPathData(string routeName, RouteValueDictionary values)
Microsoft.AspNetCore.Mvc.Routing.UrlHelper.Action(UrlActionContext actionContext)
Microsoft.AspNetCore.Mvc.UrlHelperExtensions.Action(IUrlHelper helper, string action, string controller, object values, string protocol, string host, string fragment)
Microsoft.AspNetCore.Mvc.UrlHelperExtensions.Action(IUrlHelper helper, string action)
TestController.ListAsync() in TestController.cs
var res = UrlHelper.Action(nameof(ListAsync));
- Switch CompabilityVersion to
CompatibilityVersion.Version_2_1
- Watch action run as expected
Expected behavior
Action should return /api/test
No ArgumentOutOfRangeException should be thrown
Additional context
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 17 (8 by maintainers)
UrlHelper
relies onIRouter
and will not work when endpoint routing is enabled. There is anEndpointRoutingUrlHelper
that is used for backwards compatibility reasons but is internal.Instead of injecting
UrlHelper
, you should change your code to useLinkGenerator
. It is designed to be resolved from DI and is registered by default in 2.2Use
LinkGenerator.GetPathByAction
: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-2.2#url-generation@rynowak Do you think we should improve the exception
UrlHelper
throws when there is no router? Something like: “No router could be found. Use LinkGenerator instead.”