我正在构建一个带有angularjs前端和ASP.NET后端的应用程序。为了使我的角度服务能够发出请求,我需要构造一个给定ASP.NET控制器和操作列表的URL模板列表,然后将其发送给客户端。
我正在寻找的结果类似于以下内容:
[RoutePrefix("my-controller")]
public class MyController : ControllerBase
{
[Route("my-action/{arg1}/{arg2}")]
public ActionResult MyAction(int arg1, string arg2) {
// ...
}
}
// Elsewhere in my code
GetRouteTemplate("MyController", "MyAction") // => "my-controller/my-action/{arg1}/{arg2}"
我不希望将这些代码硬编码到前端,因为对路由的任何更改都会破坏角度代码,因此我正在寻找一种生成它们的方法。
我的第一个尝试是使用反射来获取所有action方法,然后调用Url.Action来获取url。我把它放在我的基本控制器类中:
protected Dictionary<String, String> GetUrlTemplates()
{
var controllerName = this
.GetType()
.Name;
var actionNames = this
.GetType()
.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
.Where(m => !m.IsDefined(typeof(NonActionAttribute), false))
.Select(m => m.Name)
.Distinct()
.ToList();
return actionNames
.ToDictionary(
actionName => actionName,
actionName => Url.Action(actionName, controllerName));
}
对于不需要参数但没有返回正确路径的任何操作,这都是可以的。
我的下一个尝试是尝试将模板直接从RouteTable中拉出:
protected Dictionary<String, String> GetUrlTemplates()
{
var controllerName = this
.GetType()
.Name;
var actions = this
.GetType()
.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
.Where(m => !m.IsDefined(typeof(NonActionAttribute), false))
.Select(m => m.Name)
.Distinct()
.ToList();
return RouteTable.Routes
.OfType<LinkGenerationRoute>()
.Select(lgr => new {
url = lgr.Url,
routeAction = lgr.DataTokens["MS_DirectRouteActions"][0]
})
.Where(o => o.routeAction.ControllerDescriptor.ControllerName == controllerName
&& actions.Contains(o.routeAction.ActionName))
.ToDictionary(
o => o.routeAction.ActionName,
o => o.url);
}
这是行不通的,因为LinkGenerationRoute是一个内部类,因此,除非有另一种方法来访问路由表中的这些值,否则这似乎是一个死胡同。
这两种尝试都有些丑陋,似乎是错误的方法,但是我看不到其他解决方法。确保为前端生成url模板是一项常见的任务-在ASP.NET中是否有“正确”的方法来获取url模板?我是从根本上以错误的方式解决了这个问题吗?谢谢。
答案 0 :(得分:0)
最后,我决定直接从RoutePrefix和Route属性中提取路由模板,这对本项目来说很好,因为所有路由都以这种方式配置。我仍然觉得应该有一个更简单/较不脆弱的解决方案-如果有人回答更好,我会接受的。
这是我添加到基本控制器中的方法:
protected Dictionary<String, String> GetRouteTemplates(Type controllerType, params String[] actions)
{
var routePrefix = controllerType
.GetCustomAttribute<RoutePrefixAttribute>()
.Prefix;
var routeTemplates = controllerType
.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
.Where(m => !actions.Any() || actions.Contains(m.Name))
.Where(m => !m.IsDefined(typeof(NonActionAttribute), false) && m.IsDefined(typeof(RouteAttribute), false))
.Select(m => new {m.Name, m.GetCustomAttribute<RouteAttribute>().Template})
.ToDictionary(r => r.Name, r => $"/{routePrefix}/{r.Template}");
return routeTemplates;
}
在任何控制器上我都想返回网址模板:
[Route("urls")]
public JsonResult Urls(Int32 organisationId)
{
var routeTemplates = GetRouteTemplates(GetType());
return Json(routeTemplates);
}