使用 MVC.UrlHelper 从 MVC 视图中解析 WebApi 操作 Url
Resolve WebApi action Url from within MVC View using MVC.UrlHelper
我创建了一个辅助扩展,它允许我在 MVC razor 中使用 UrlHelper
强类型表达式。这非常适合从视图中解析我的 MVC 控制器的 URI。
<a href="@(Url.Action<HomeController>(c=>c.Index()))">Home</a>
<li>@(Html.ActionLink<AccountController>("Sign in", c => c.Signin(null)))</li>
<li>@(Html.ActionLink<AccountController>("Create an account", c => c.Signup(), htmlAttributes: null))</li>
@using (Html.BeginForm<ToolsController>(c => c.Track(null), FormMethod.Get, htmlAttributes: new { @class = "navbar-form", role = "search" })) {...}
我现在有一个视图,我正在尝试使用敲除 post 一些数据到我的网站 api 并且需要能够做这样的事情
var targetUrl = '@(Url.HttpRouteUrl<TestsApiController>(c => c.TestAction(null)))';
这样我就不必硬编码我的 urls(魔术字符串)
我目前实现的获取网络的扩展方法 API url 定义如下。
private const string HttpRouteKey = "httproute";
public static string HttpRouteUrl<TController>(this UrlHelper urlHelper, Expression<Action<TController>> action)
where TController : System.Web.Http.ApiController {
RouteValueDictionary routeValues = InternalExpressionHelper.GetRouteValues(action);
if (!routeValues.ContainsKey(HttpRouteKey)) {
routeValues.Add(HttpRouteKey, true);
}
var scheme = urlHelper.RequestContext.HttpContext.Request.Url.Scheme;
var route = urlHelper.Action(null, null, rvd, scheme);
//I've also tried
//var route = urlHelper.HttpRouteUrl(null, rvd);
return route;
}
InternalExpressionHelper.GetRouteValues
检查表达式并生成将用于生成 url.
的 RouteValueDictionary
问题是我的 route
总是 returns null
。以前关于 SO 和博客的问题表明,通过在字典中包含 httproute
将允许从 MVC.UrlHelper
路由集合中获取 WebApi Urls。
到目前为止 none 接受的答案似乎对我有用,因为我使用的是没有路由名称的属性路由。
当生成指向 Web API 路由的链接时,必须始终要求 RouteName
才能正常工作,因此我决定应用一个约定。
帮助程序扩展通过组合控制器名称和操作名称来确定 RouteName。
var routeName = string.Join("_", controllerName, actionName);
现在因为当从包含控制器名称和动作名称的表达式中提取信息时,它们也显示在 url 中。不是很漂亮
/api/tests/1/2?controller=TestsApi&action=Get
因此它们已从路由值中删除。
routeValues.Remove("controller");
routeValues.Remove("action");
更新扩展方法现在看起来像这样
private const string HttpRouteKey = "httproute";
public static string HttpRouteUrl<TController>(this UrlHelper urlHelper, Expression<Action<TController>> action)
where TController : System.Web.Http.Controllers.IHttpController {
var routeValues = InternalExpressionHelper.GetRouteValues(action);
if (!routeValues.ContainsKey(HttpRouteKey)) {
routeValues.Add(HttpRouteKey, true);
}
var controllerName = routeValues["controller"] as string;
routeValues.Remove("controller");
var actionName = routeValues["action"] as string;
routeValues.Remove("action");
var routeName = string.Join("_", controllerName, actionName);
var url = urlHelper.HttpRouteUrl(routeName, routeValues);
return url;
}
现在我只需要确保,如果我希望我的操作可以从 MVC 或 Web API 生成 url/link,那么必须应用 RouteName
公约 "{controller}_{action}"
[RoutePrefix("api/tests")]
[AllowAnonymous]
public class TestsApiController : WebApiControllerBase {
[HttpGet]
[Route("{lat:double:range(-90,90)}/{lng:double:range(-180,180)}", Name = "TestsApi_Get")]
public object Get(double lat, double lng) {
return new { lat = lat, lng = lng };
}
}
到目前为止,我测试它时大部分都有效
@section Scripts {
<script type="text/javascript">
var url = '@(Url.HttpRouteUrl<TestsApiController>(c => c.Get(1,2)))';
alert(url);
</script>
}
我得到了/api/tests/1/2
,这就是我想要的。
我创建了一个辅助扩展,它允许我在 MVC razor 中使用 UrlHelper
强类型表达式。这非常适合从视图中解析我的 MVC 控制器的 URI。
<a href="@(Url.Action<HomeController>(c=>c.Index()))">Home</a>
<li>@(Html.ActionLink<AccountController>("Sign in", c => c.Signin(null)))</li>
<li>@(Html.ActionLink<AccountController>("Create an account", c => c.Signup(), htmlAttributes: null))</li>
@using (Html.BeginForm<ToolsController>(c => c.Track(null), FormMethod.Get, htmlAttributes: new { @class = "navbar-form", role = "search" })) {...}
我现在有一个视图,我正在尝试使用敲除 post 一些数据到我的网站 api 并且需要能够做这样的事情
var targetUrl = '@(Url.HttpRouteUrl<TestsApiController>(c => c.TestAction(null)))';
这样我就不必硬编码我的 urls(魔术字符串)
我目前实现的获取网络的扩展方法 API url 定义如下。
private const string HttpRouteKey = "httproute";
public static string HttpRouteUrl<TController>(this UrlHelper urlHelper, Expression<Action<TController>> action)
where TController : System.Web.Http.ApiController {
RouteValueDictionary routeValues = InternalExpressionHelper.GetRouteValues(action);
if (!routeValues.ContainsKey(HttpRouteKey)) {
routeValues.Add(HttpRouteKey, true);
}
var scheme = urlHelper.RequestContext.HttpContext.Request.Url.Scheme;
var route = urlHelper.Action(null, null, rvd, scheme);
//I've also tried
//var route = urlHelper.HttpRouteUrl(null, rvd);
return route;
}
InternalExpressionHelper.GetRouteValues
检查表达式并生成将用于生成 url.
RouteValueDictionary
问题是我的 route
总是 returns null
。以前关于 SO 和博客的问题表明,通过在字典中包含 httproute
将允许从 MVC.UrlHelper
路由集合中获取 WebApi Urls。
到目前为止 none 接受的答案似乎对我有用,因为我使用的是没有路由名称的属性路由。
当生成指向 Web API 路由的链接时,必须始终要求 RouteName
才能正常工作,因此我决定应用一个约定。
帮助程序扩展通过组合控制器名称和操作名称来确定 RouteName。
var routeName = string.Join("_", controllerName, actionName);
现在因为当从包含控制器名称和动作名称的表达式中提取信息时,它们也显示在 url 中。不是很漂亮
/api/tests/1/2?controller=TestsApi&action=Get
因此它们已从路由值中删除。
routeValues.Remove("controller");
routeValues.Remove("action");
更新扩展方法现在看起来像这样
private const string HttpRouteKey = "httproute";
public static string HttpRouteUrl<TController>(this UrlHelper urlHelper, Expression<Action<TController>> action)
where TController : System.Web.Http.Controllers.IHttpController {
var routeValues = InternalExpressionHelper.GetRouteValues(action);
if (!routeValues.ContainsKey(HttpRouteKey)) {
routeValues.Add(HttpRouteKey, true);
}
var controllerName = routeValues["controller"] as string;
routeValues.Remove("controller");
var actionName = routeValues["action"] as string;
routeValues.Remove("action");
var routeName = string.Join("_", controllerName, actionName);
var url = urlHelper.HttpRouteUrl(routeName, routeValues);
return url;
}
现在我只需要确保,如果我希望我的操作可以从 MVC 或 Web API 生成 url/link,那么必须应用 RouteName
公约 "{controller}_{action}"
[RoutePrefix("api/tests")]
[AllowAnonymous]
public class TestsApiController : WebApiControllerBase {
[HttpGet]
[Route("{lat:double:range(-90,90)}/{lng:double:range(-180,180)}", Name = "TestsApi_Get")]
public object Get(double lat, double lng) {
return new { lat = lat, lng = lng };
}
}
到目前为止,我测试它时大部分都有效
@section Scripts {
<script type="text/javascript">
var url = '@(Url.HttpRouteUrl<TestsApiController>(c => c.Get(1,2)))';
alert(url);
</script>
}
我得到了/api/tests/1/2
,这就是我想要的。