1

Ich habe eine Helfer-Erweiterung erstellt, die mir stark getippte Ausdrücke mit UrlHelper in MVC Rasierer haben kann. Dies funktioniert sehr gut zum Auflösen von URIs für meine MVC-Controller mit Ansichten.Resolve WebApi Aktion Url aus MVC View mit MVC.UrlHelper

<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" })) {...}  

Ich habe jetzt einen Blick, wo ich Knockout zu verwenden, ich versuche, einige Daten zu meiner Web-api zu schreiben und müssen in der Lage so etwas wie dieses

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

so dass ich don zu tun Ich muss meine URLs hart codieren (Magic strings)

Meine aktuelle Implementierung meiner Erweiterungsmethode zum Abrufen der Web-API-URL ist wie folgt definiert.

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 inspiziert die Expression und erzeugt ein RouteValueDictionary, das verwendet wird, um die URL zu erzeugen.

Problem ist, dass meine route immer null zurückgibt. Frühere Fragen zu SO und Blogs gefunden haben angezeigt, dass durch die Einbeziehung der httproute in das Wörterbuch würde die Möglichkeit, WebApi URLs von MVC.UrlHelper Route Sammlung erhalten.

Bis jetzt scheint keine der angenommenen Antworten für mich zu arbeiten, da ich Attribut-Routing ohne Routenname verwende.

+0

FYI, es gibt bereits eine Open-Source-Bibliothek, um das [hier] (https://github.com/ploeh/Hyprlinkr) zu tun. – NightOwl888

+0

Ich greife schon durch die Quelle, um zu sehen, wie es dort gemacht wird – Nkosi

Antwort

0

Da beim Generieren von Links zu Web-API-Routen immer eine RouteName benötigt wird, um dies zu funktionieren, entschied ich mich für eine Konvention.

Die Helfererweiterung mit bestimmen Sie den RouteName durch Kombination des Controllernamens und Aktion Name.

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

Jetzt, da, wenn Extraktion Informationen aus dem Ausdruck von denen Controller-Namen und Aktionsnamen enthalten sind, wurden sie auch in der URL angezeigt wird. nicht sehr hübsch.

/api/tests/1/2?controller=TestsApi&amp;action=Get 

so wurden sie aus den Routenwerten entfernt.

routeValues.Remove("controller"); 
routeValues.Remove("action"); 

Das Update-Extension-Methode sieht nun wie folgt

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; 
} 

Und ich brauche jetzt nur noch dafür zu sorgen, dass, wenn ich meine Aktion wollen für url/Link-Generierung von MVC oder Web-API zugänglich zu sein, ein RouteName muss angewendet werden, dass die Konvention "{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 }; 
    } 
} 

Arbeiten zum größten Teil so weit folgt, wenn ich es

testen
@section Scripts { 
    <script type="text/javascript"> 
     var url = '@(Url.HttpRouteUrl<TestsApiController>(c => c.Get(1,2)))'; 
     alert(url); 
    </script> 
} 

Ich bekomme /api/tests/1/2, was ich wollte.