-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
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/1234The 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.