Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make it easy to configure a host/scheme for absolute URLs with LinkGenerator #14192

Open
RehanSaeed opened this issue Sep 20, 2019 · 13 comments
Open
Labels
affected-few This issue impacts only small number of customers area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates enhancement This issue represents an ask for new feature or an enhancement to an existing one feature-routing severity-minor This label is used by an internal tool
Milestone

Comments

@RehanSaeed
Copy link
Contributor

RehanSaeed commented Sep 20, 2019

Is your feature request related to a problem? Please describe.

LinkGenerator

LinkGenerator requires the HttpContext to generate a full absolute URL which also contains the scheme, hostname and optional port. Outside of the controller, this means I have to also inject the IHttpContextAccessor into my constructor and pass it in like so:

this.linkGenerator.GetUriByRouteValues(
    this.httpContextAccessor.HttpContext,
    "GetPage",
    new() { First = 1, Last = 10 });

This requires a lot of ceremony and additional noise.

IUrlHelper

IUrlHelper does not require the HttpContext if you add this code to the Startup. We use the IActionContextAccessor and IUrlHelperFactory to register IUrlHelper into the IoC container.

services
    .AddSingleton<IActionContextAccessor, ActionContextAccessor>()
    .AddScoped(x => x
        .GetRequiredService<IUrlHelperFactory>()
        .GetUrlHelper(x.GetRequiredService<IActionContextAccessor>().ActionContext))

Then if you use the following extension method to create your URL's:

public static string AbsoluteRouteUrl(
    this IUrlHelper urlHelper,
    string routeName,
    object routeValues = null) =>
    urlHelper.RouteUrl(routeName, routeValues, urlHelper.ActionContext.HttpContext.Request.Scheme);

Here is the usage:

this.urlHelper.AbsoluteRouteUrl("GetPage", new() { First = 1, Last = 10 });

I think you'll agree this is much nicer.

Describe the solution you'd like

I would like a way to generate URL's without having to inject the IHttpContextAccessor and LinkGenerator just to generate a single URL. Or a way to use IUrlHelper without all the setup code to get it working nicely.

@mkArtakMSFT mkArtakMSFT added the area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates label Sep 20, 2019
@FilipVanBouwel
Copy link

I agree. This should be less cumbersome. I don't care if it's IUrlHelper or IUrlGenerator, as long as it is fully setup by the DI system as part of ASP.NET.

@rynowak
Copy link
Member

rynowak commented Sep 20, 2019

LinkGenerator requires the HttpContext to generate a URL.

This is not true. LinkGenerator is specifically designed to work without an HTTP context.

See: https://github.com/aspnet/AspNetCore/blob/master/src/Mvc/Mvc.Core/src/Routing/ControllerLinkGeneratorExtensions.cs#L84 and similar methods.

@rynowak rynowak added this to the Discussions milestone Sep 20, 2019
@RehanSaeed
Copy link
Contributor Author

RehanSaeed commented Sep 21, 2019

As far as I can work out this is not true for absolute URL's containing the scheme, host and port. Using this code:

this.linkGenerator.GetPathByRouteValues("GetPage", new { First = 1, Last = 10 });

Outputs:

/foo?first=1&last=10

@rynowak
Copy link
Member

rynowak commented Sep 23, 2019

@RehanSaeed - can you provide some more information? I'm not sure how I'm supposed to draw a conclusion from that.

@RehanSaeed
Copy link
Contributor Author

I want to generate absolute URL's with the full scheme, host and optionally a port i.e. https://example.com/foo?bar=1. Why? Well, one reason is that in API's a full URL is much easier to consume from JavaScript.

Today, if you want to do this, you have to have the HttpContext and pass it into the LinkGenerator or IUrlHelper as I've shown in my code samples above. This is used to pull the scheme and host from the current request and stick it into the URL.

That's all well and good in a controller where you have easy access to the HttpContext. However, if I'm outside of the controller and want to generate a URL, then if I use LinkGenerator, then I am forced to also inject IHttpContextAccessor or if I'm using IUrlHelper, it's possible to avoid injecting IHttpContextAccessor but you have to add some additional setup in Startup and use an extension method. All code is shown above.

Both of these solutions are noisy and require extra work, just to get an absolute URL. Ideally, I'd want a method that does all of that for me and allows me to generate URL's without all the extra noise and ceremony.

Does that clear things up?

@FilipVanBouwel
Copy link

I agree with RehanSaeed. I had the need to generate absolute urls in a module that sends out emails to clients (which is outside the web project). I only want the IUrlHelper or LinkGenerator as dependency and don't want to do all the IHttpContextAccessor setup as described above.

@rynowak
Copy link
Member

rynowak commented Sep 25, 2019

I want to generate absolute URL's with the full scheme, host and optionally a port i.e. https://example.com/foo?bar=1. Why? Well, one reason is that in API's a full URL is much easier to consume from JavaScript.

This is something we can work with. Do you actually care about the current request? Or do you just want it to be easier to generate absolute URLs?

I can imagine a feature where you can centrally configure a default scheme and host that will be used in URLs - or it could fallback to the listening address if nothing is configured and there is only one listening address.


There reason I'm making this distinction is that passing in the "current request" does more than just set up scheme/host/pathbase - it also includes ambient route values. Trying to make a service that will magically use ambient values from the current request is a recipe for failure because it's going to do different things depending on which route reached the current thing.

@RehanSaeed
Copy link
Contributor Author

I don't care about the current request at all, I'm just forced to care to generate a URL based on the current requests scheme, host and URL.

I can imagine a feature where you can centrally configure a default scheme and host that will be used in URLs - or it could fallback to the listening address if nothing is configured and there is only one listening address.

I could get behind such a feature. The fallback sounds like the correct default with the option to override it.

@FilipVanBouwel
Copy link

That sounds good to me as well!

@rynowak
Copy link
Member

rynowak commented Sep 25, 2019

Great, I'm sticking this in the 5.0 milestone so it will get looked at.

@rynowak rynowak added enhancement This issue represents an ask for new feature or an enhancement to an existing one and removed question labels Sep 25, 2019
@rynowak rynowak removed their assignment Sep 25, 2019
@rynowak rynowak modified the milestones: Discussions, 5.0.0-preview1 Sep 25, 2019
@rynowak rynowak changed the title LinkGenerator vs IUrlHelper Both Not Ideal Make it each to configure a host/scheme for absolute URLs with LinkGenerator Sep 25, 2019
@RehanSaeed RehanSaeed changed the title Make it each to configure a host/scheme for absolute URLs with LinkGenerator Make it easy to configure a host/scheme for absolute URLs with LinkGenerator Oct 23, 2019
@mkArtakMSFT
Copy link
Member

We've moved this issue to the Backlog milestone. This means that it is not going to happen for the coming release. We will reassess the backlog following the current release and consider this item at that time. However, keep in mind that there are many other high priority features with which it will be competing for resources.

@clawrenceks
Copy link

I have a requirement to use the LinkGenerator to generate links outside of a Web Project, similar to the requirement mentioned by @FilipVanBouwel earlier in this issue.

My requirement is to use the LinkGenerator in a worker process that runs in its own process, with no web host configured.

The only way I have been able to achieve this so far is as follows. Are there any issues with using this method? Is there a simpler approach that I am overlooking?

  1. In the ConfigureServices of the application, register the controllers from the web project with MVC
var apiAssembly = Assembly.GetAssembly(typeof(RouteNames));

services.AddMvcCore()
        .AddApplicationPart(apiAssembly)
            .AddControllersAsServices();
  1. At the end of ConfigureServices I create an application builder and use this to map the controllers with Endpoint Routing. My application does not build a web host, so the endpoints below should never be accessible. I only perform this step as without it I don't believe that the LinkGenerator will be aware of the MVC Routes.
// Map the controllers as endpoints to allow the LinkGenerator to link to controller routes.

var appBuilder = new ApplicationBuilder(serviceProvider);

appBuilder.UseRouting();

appBuilder.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});
  1. I can then inject a LinkGenerator into my HostedService and generator links as follows:
var path = _linkGenerator.GetPathByName("MyRouteName", new { });

@captainsafia captainsafia added affected-few This issue impacts only small number of customers severity-minor This label is used by an internal tool labels Nov 12, 2020
@mkArtakMSFT mkArtakMSFT modified the milestones: Backlog, .NET 8 Planning Sep 28, 2022
@ghost
Copy link

ghost commented Sep 28, 2022

Thanks for contacting us.

We're moving this issue to the .NET 8 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
affected-few This issue impacts only small number of customers area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates enhancement This issue represents an ask for new feature or an enhancement to an existing one feature-routing severity-minor This label is used by an internal tool
Projects
None yet
Development

No branches or pull requests