17

I'm currently trying to do something that was dead simple and straight forward in ASP.NET 4 however this ins't the case now in ASP.NET 5.

Previously to use the UrlHelper it was dead simple:

var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);

However I can't for the life of me wrap my head around how to use the new UrlHelper. I'm looking at the test cases and either I'm completely daft or I'm missing something and I can't seem to figure it out. Any help here in clearing up this would be great.

Marqueone
  • 1,165
  • 2
  • 14
  • 33

5 Answers5

20

Update - Post RC2

As @deebo mentioned, you no longer can get an IUrlHelper directly from DI. Instead you need to inject an IUrlHelperFactory and an IActionContextAccessor into your class and use them to get the IUrlHelper instance as in:

public MyClass(IUrlHelperFactory urlHelperFactory, IActionContextAccessor actionAccessor)
{
    this.urlHelperFactory = urlHelperFactory;
    this.actionAccessor = actionAccessor;
}

public void SomeMethod()
{
    var urlHelper = this.urlHelperFactory.GetUrlHelper(this.actionAccessor.ActionContext);
}

You need to also register the in your startup class (IUrlHelperFactory is already registered by default):

services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();

Bear in mind this will only work as long as the code where you get the actionContext is running after the MVC/routing middleware! (Otherwise actionAccessor.ActionContext would be null)


I have retrieved the IUrlHelper using the IServiceProvider in HttpContext.RequestServices.

Usually you will have an HttpContext property at hand:

  • In a controller action method you can do:

    var urlHelper = this.Context.RequestServices.GetRequiredService<IUrlHelper>();
    ViewBag.Url = urlHelper.Action("Contact", "Home", new { foo = 1 });
    
  • In a filter you can do:

    public void OnActionExecuted(ActionExecutedContext context)
    {
        var urlHelper = context.HttpContext.RequestServices.GetRequiredService<IUrlHelper>();
        var actionUrl = urlHelper.Action("Contact", "Home", new { foo = 1 });
        //use actionUrl ...
    }
    

Another option would be taking advantage of the built-in dependency injection, for example your controller could have a constructor like the following one and at runtime an IUrlHelper instance will be provided:

private IUrlHelper _urlHelper;
public HomeController(IUrlHelper urlHelper)
{
    _urlHelper = urlHelper;
}
Daniel J.G.
  • 34,266
  • 9
  • 112
  • 112
  • *facepalm* I was unaware that I could get a url helper via dependancy injection as I was under the impression that this was something that had to be added to the services. – Marqueone Jun 07 '15 at 22:50
15

Thought I would share for the upcoming RC2 since the current answer won't work anymore then.

From RC 2 you will need to explicitly register IActionContextAccessor and IUrlHelperFactory

services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddSingleton<IUrlHelperFactory, UrlHelperFactory>();

Then use the DI/service locator:

public EmailTagHelper(IUrlHelperFactory urlHelperFactory, IActionContextAccessor actionContextAccessor)
{
  _urlHelper = urlHelperFactory.GetUrlHelper(actionContextAccessor.ActionContext);
}

I blogged about it here with regard to TagHelpers: http://devonburriss.me/asp-net-5-tips-urlhelper

Devon Burriss
  • 2,497
  • 1
  • 19
  • 21
  • Aside from registering IUrlHelper in the startup config as you mentioned I'm not sure I understand why or how it's now different than the original solution? A better question is why do I need to register it to begin with. It seems like a lot more work now. – Marqueone Jan 19 '16 at 07:33
  • The only difference is that it should work in RC2. The current answer is correct currently. I was messing around with RC2 and ran into an issue as described in the blog post linked. Also mentioned there is this link git commit https://github.com/aspnet/Mvc/commit/9fc3a800562c866850d7c795cf24db7fa0354af6 that seems to indicate a design decission to remove a dependency on IActionContextAccessor. Maybe @davidfowl or someone else from aspnet team can explain – Devon Burriss Jan 19 '16 at 09:12
5

In Startup.cs

   services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
   services.AddSingleton<IUrlHelperFactory, UrlHelperFactory>();
   services.AddScoped(it => it.GetService<IUrlHelperFactory>()
                    .GetUrlHelper(it.GetService<IActionContextAccessor>().ActionContext));

Alternatively

PM> Install-Package AspNetCore.IServiceCollection.AddIUrlHelper 

In Startup.cs

services.AddUrlHelper();
tchelidze
  • 8,050
  • 1
  • 29
  • 49
2

If you just need the UrlHelper.Link method like I did, you don't even need the UrlHelper any more, just use Url.Link

Sean
  • 14,359
  • 13
  • 74
  • 124
1

A shorter version without constructing special Factory class

services.AddSingleton<IActionContextAccessor, ActionContextAccessor>()
            .AddScoped<IUrlHelper>(sp => new UrlHelper(sp.GetRequiredService<IActionContextAccessor>().ActionContext));
Vitaly
  • 2,064
  • 19
  • 23