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)
UrlHelperrelies onIRouterand will not work when endpoint routing is enabled. There is anEndpointRoutingUrlHelperthat 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
UrlHelperthrows when there is no router? Something like: “No router could be found. Use LinkGenerator instead.”