使用MVC.UrlHelper从MVC View中解析WebApi操作Url

时间:2016-04-10 19:23:19

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

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

我现在有一个视图,我试图使用knockout将一些数据发布到我的web api,并且需要能够做这样的事情

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

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

我目前用于获取Web API网址的扩展方法的实现定义如下。

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检查表达式并生成将用于生成网址的RouteValueDictionary

问题是我的route始终返回null。之前关于SO和博客的问题表明,通过在字典中包含httproute,可以从MVC.UrlHelper路径集合中获取WebApi Urls。

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

1 个答案:

答案 0 :(得分:0)

在生成指向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 / link,那么必须在RouteName之后应用"{controller}_{action}" < / p>

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