Skip to content

Make link creation typesafe using expressions #14665

@mariusGundersen

Description

@mariusGundersen

Currently there is no refactor-safe way to create links to actions or pages, it has to be done using magic strings that the compiler doesn't understand. For example, I have an AboutController with an Index action, then I can create a link using Url.Action("Index", "About"). But if I rename the action or controller then this will lead to a runtime exception, not a compile time exception. I could use Url.Action(nameof(AboutController.Index), "About"), but using nameof() only works for the action, not the controller, since it expects me to specify the name of the controller without the Controller suffix. This is further a problem for actions that take query parameters, where they are specified using an anonymous class with no type safety at all. That is, there is no verification that Url.Action("Index", "Search", new {name, title, query}) will create a link that sends the correct query parameters to the SearchController.Index method.

My proposal is therefore a method that takes an expression, so that it can look like this:

//Given this controller...
public class AboutController
{
  public IActionResult Index()
  {
    //...
  }

  public IActionResult Search(string name, string title, string query)
  {
    //...
  }

  [HttpPost]
  public IActionResult Submit(string id, [FromBody] Model input)
  {
    //...
  }
}

//Get url to action in another controller
Url.Action<AboutController>(c => c.Index()); // => /About/Index

//Inside a controller there would be an overload that is not generic, using the current controller as the basis
Url.Action(c => c.Index()); // => /About/Index

//Actions that have query parameters would also work
Url.Action<AboutController>(c => c.Search(name, title, query)); // => /About/Search?name=test&title=blabla&query=*

//For actions that work with Post or Put and take in a body, the body is ignored so we can pass in null values for the Post parameters
Url.Action<AboutController>(c => c.Submit(id, null)); // =>/About/Submit/1234

The UrlHelper.Action method would be defined as public static string Action<TC>(this IUrlHelper helper, Expression<Func<TC, object>> expression) or something similar, and based on the expression passed into it enough information should be able to be gathered to create a url.

Metadata

Metadata

Assignees

No one assigned

    Labels

    affected-mediumThis issue impacts approximately half of our customersarea-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesenhancementThis issue represents an ask for new feature or an enhancement to an existing onefeature-routingseverity-majorThis label is used by an internal tool

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions