ActionContext.RouteData.Routers empty causes ArgumentOutOfRangeException in UrlHelper (Regression from 2.1)
See original GitHub issueDescribe 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
Issue Analytics
- State:
- Created 5 years ago
- Comments:17 (8 by maintainers)
Top Results From Across the Web
Trying to Test a Controller with a UrlHelper
The helper is trying to access actionContext.RouteData.Values which was not provided in the original example.
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
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.”Perfect! Thanks. I’ll take a look at how this works and see if it is a suitable replacement for what I was doing.