I've read multiple posts and blogs similar to
Delegate-based strongly-typed URL generation in ASP.NET MVC
But none of them really quite do what I'd like to do. Currently I have a hybrid approach like:
// shortened for Brevity
public static Exts
{
public string Action(this UrlHelper url,
Expression<Func<T, ActionResult>> expression)
where T : ControllerBase
{
return Exts.Action(url, expression, null);
}
public string Action(this UrlHelper url,
Expression<Func<T, ActionResult>> expression,
object routeValues)
where T : ControllerBase
{
string controller;
string action;
// extension method
expression.GetControllerAndAction(out controller, out action);
var result = url.Action(action, controller, routeValues);
return result;
}
}
Works great if you're controller methods don't have any parameters:
public class MyController : Controller
{
public ActionResult MyMethod()
{
return null;
}
public ActionResult MyMethod2(int id)
{
return null;
}
}
Then I can:
Url.Action<MyController>(c => c.MyMethod())
But if my method takes a parameter, then I have to pass a value (that I would never use):
Url.Action<MyController>(c => c.MyMethod2(-1), new { id = 99 })
So the question is there a way to change the extension method to still require the first parameter to be a method defined on type T
that does check to make sure the return parameter is an ActionResult
without actually specifying a parameter, something like:
Url.Action<MyController>(c => c.MyMethod2, new { id = 99 })
So this would pass a pointer to the method (like a reflection MethodInfo
) instead of the Func<>
, so it wouldn't care about parameters. What would that signature look like if it was possible?
c.MyMethod2
you're pointing to a method group, any of which can return something else... But I'm fairly sure I've seen libraries that enable this. Perhaps you can do some reflection magic and check inGetControllerAndAction
that the method of the group matching the provided parameters does indeed returnActionResult
. This will not exactly give you the compile-time safety you're looking for, but you shouldn't have non-actionmethods as public methods in your controller anyway. – Iridisc => c.MyMethod2
can't be cast fromMethod Group
to non-delegate typeActionResult
. – Rigbyc => c.MyMethod2(99)
instead (usingMethodCallExpression.Arguments
to get the arguments)? – Iridisc => c.MyMethod(99), new { id = 98 }
... but maybe I don't need route values at that point... I'm trying to think of a reason I would need a route value... – Rigby