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

Using routing data to generate links? #953

Closed
alastairtree opened this issue Feb 22, 2021 · 2 comments
Closed

Using routing data to generate links? #953

alastairtree opened this issue Feb 22, 2021 · 2 comments

Comments

@alastairtree
Copy link

alastairtree commented Feb 22, 2021

DESCRIPTION

Following on from the useful discussion in PR #949 I have implemented a custom ILinkBuilder that uses the MVC routing data to help generate links rather than just string building from static config.

Use cases where this is required:

  • Your app uses a global path base such as in startup.Configure app.UsePathBase(new PathString("/api"))
    If the path base is a fixed string then json api users must also configure the JsonApiOptions.Namespace option to prefix all links, but with the route aware link builder, this option is no longer required and all links will include path base by default
  • Your app is using some custom routing convention, such as the multi-tenant setup described in task: make [Attr] and RequestDeserializer.SetAttributes open to extension #949 like GET /api/{tenantId}/books. The current LinkBuilder cannot see/understand the path before the resourceName, so all links start /books rather than the complete link. I have also used other weird routing setups that mess up the links such as /{controller}/{routeParam1}/{routeParam2}.

To generate complete links that are "routing aware" you need to use MVC LinkGenerator to generate the url of the Get endpoint of the correct controller, in the current http context.

I will paste the code I used below. Any thoughts on the approach? Is there any interest in a PR to either change the current link builder, or add an option to use this version? And if not no worries, folks can easily steal my class below and apply it using the dependency injection framework with services.AddScoped<ILinkBuilder, RoutingLinkBuilder>();

RoutingLinkBuilder.cs gist

(The main change is adding this method, and calling it everywhere to generate a link to the /{resource}/{id?} endpoint)

private string GetResourceLink(ResourceContext resourceContext, string resource, string resourceId = null)
{
    // if current request has any route params specified we need to fetch them here to reuse them,
    // and append/set the id of the resource we are routing to
    var routeData =
        new RouteValueDictionary(_httpContextAccessor.HttpContext.Request.RouteValues) { ["id"] = resourceId };

    var controllerName = routeData["controller"]?.ToString() ?? resource;

    var link = _linkGenerator.GetPathByAction(
        _httpContextAccessor.HttpContext, action: GetResourceByIdActionName
        , controllerName, routeData);

    return link;
}
@bart-degreed
Copy link
Contributor

This looks like a great improvement to me. I'd welcome a PR that replaces the existing logic, so it can be run against our test suite. @maurei thoughts?

@bart-degreed
Copy link
Contributor

Closing, we're tracking this at #956, which links to here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants