我的项目正在使用以下代码为给定的routeName
和routeValues
生成MVC路由的URL:
public class RouteBuilder
{
public string GetUrl(string routeName, object routeValues)
{
return RouteTable.Routes.GetVirtualPath(
new RequestContext(new MockHttpContextBase(string.Empty), new RouteData()),
routeName,
new RouteValueDictionary(routeValues)
)?.VirtualPath;
}
}
例如,给定以下路由定义:
public MyController : Controller
{
[Route("Foo", "{bar}/{quux}")]
public IActionResult MyControllerMethod(MyModel model) { }
}
我们称之为:
// yields "zod/baz"
var routedUrl = RouteBuilder.GetUrl("Foo", new
{
bar = "zod",
quux = "baz",
});
问题来自传递给GetUrl
的路由值对象。出于必要,它可以是任何类型的对象,包括示例中演示的匿名对象。但这是有问题的,因为如果对象的定义中有错别字,则路由模板将不匹配,URL也将不会建立:
// yields null!
var routedUrl = RouteBuilder.GetUrl("Foo", new
{
baz = "zod", // oops, typo in 1st param name!
quux = "baz",
});
这甚至是一个问题,因为它只能在运行时捕获。
可能的解决方法是:
public class MyControllerMethodRouteParameters
{
string bar { get; set; }
string quux { get; set; }
}
public MyController : Controller
{
[Route("Foo", "{" + nameof(MyControllerMethodRouteParameters.bar) + "}/{" + nameof(MyControllerMethodRouteParameters.quux ) + "}")]
public IActionResult MyControllerMethod(MyModel model) { }
}
public class RouteBuilder
{
private string GetUrl(string routeName, object routeValues) { /* as before */ }
public string GetUrl(MyControllerMethodRouteParameters params)
{
return GetUrl(GetRouteNameFor(params.GetType(), params));
}
}
但是在开发人员方面,它有一个很大的缺点:添加新的控制器方法时,还必须记住添加一个路由参数类,一个GetUrl
重载和一个routename => route参数类型映射。容易忘记,而且由于RouteAttribute
中已经定义了所有必需的参数及其类型,因此感觉像是不必要的重复。
所以我的想法是通过T4模板生成所需的代码,方法是对程序集进行反射,抓取所有RouteAttribute
并从中提取路由名称和模板,然后解析属性名称的模板路线参数类别。这是我要经历的最后一个障碍,因为虽然我知道我可能可以编写一个正则表达式来匹配并从模板中提取路由参数,但我还是希望使用现有功能来做到这一点。
问题是,我找不到任何能为我完成的任务。最接近的似乎是内部类System.Web.Mvc.Routing.InlineRouteTemplateParser
,但是我对其进行的实验并不是特别有效。有什么我可以或应该用来实现这一目标的东西,还是我应该屈服于黑暗的正则表达式之神?