【问题标题】:Resolve WebApi action Url from within MVC View using MVC.UrlHelper使用 MVC.UrlHelper 从 MVC 视图中解析 WebApi 操作 Url
【发布时间】:2016-04-10 19:23:18
【问题描述】:

我创建了一个辅助扩展,它允许我在 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" })) {...}    

我现在有一个视图,我正在尝试使用敲除将一些数据发布到我的 web api 并且需要能够执行类似的操作

var targetUrl = '@(Url.HttpRouteUrl<TestsApiController>(c => c.TestAction(null)))';

这样我就不必硬编码我的网址(魔术字符串)

我当前用于获取 Web 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 总是返回null。以前关于 SO 和博客的问题表明,通过在字典中包含 httproute 将允许从 MVC.UrlHelper 路由集合中获取 WebApi Urls。

到目前为止,由于我正在使用没有路由名称的属性路由,因此似乎没有一个被接受的答案对我有用。

【问题讨论】:

  • 仅供参考,已经有一个开源库可以做到这一点here
  • 我已经在挖掘源代码,看看它是如何完成的

标签: c# asp.net-mvc asp.net-mvc-4 asp.net-web-api asp.net-web-api-routing


【解决方案1】:

在生成指向 Web API 路由的链接时,必须始终需要 RouteName 才能使其正常工作,因此我决定应用一个约定。

辅助扩展通过结合控制器名称和动作名称来确定 RouteName。

var routeName = string.Join("_", controllerName, actionName);

现在,因为当从包含控制器名称和动作名称的表达式中提取信息时,它们也会显示在 url 中。不是很漂亮。

/api/tests/1/2?controller=TestsApi&amp;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/链接,则必须应用遵循约定 "{controller}_{action}"RouteName

[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,这正是我想要的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-26
    • 1970-01-01
    • 2016-05-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多