2015-11-13 222 views
4

POST EDITED低於有沒有辦法用WebAPI生成Url?

我們無法弄清楚從的WebAPI控制器的情況下使用時,爲什麼UrlHelper將返回空字符串。

我們已經完成了必要的調試,但我們無法找出爲什麼發生這種情況,RouteData中有路由,但似乎沒有工作。

大多數情況下,我們使用RenderViewToString函數,該函數加載包含調用Url.RouteUrl(routeName)的視圖。

已經嘗試過的東西是創建一個自定義UrlHelper(但無濟於事),並用UrlHelper(MVC/HTTP)進行調試。

屬性路由與路線名稱使用,隨處可見。

用法示例代碼:

public class WebApiController : BaseApiController 
    { 
     [HttpPost] 
     [ResponseType(typeof(string))] 
     [Route("cart/get/checkout", Name = "api.cart.get.checkout")] 
     public IHttpActionResult GetCheckOutShoppingCart([FromBody] string data) 
     { 
       return Ok(RenderViewToString("CartController", "_CheckOutCartPartial", new ShoppingCartModel(Auth.IsAuthenticated ? Auth.GetCustomer().DefaultShippingInfo.CountryId : 148) 
       { 
        AddInsurance = false, 
        InsuredShipping = insuredShipping, 
        CurrentDeliveryMethodId = deliveryMethodId, 
        CurrentPaymentMethodId = paymentMethodId 
       })); 
     } 
    } 

BaseApiController類:

public class BaseApiController : ApiController 
    { 
     public static string RenderViewToString(string controllerName, string viewName) 
     { 
      return RenderViewToString(controllerName, viewName, new Dictionary<string, object>()); 
     } 

     public static string RenderViewToString(string controllerName, string viewName, object model) 
     { 
      using (var writer = new StringWriter()) 
      { 
       var routeData = new RouteData(); 
       routeData.Values.Add("controller", controllerName); 
       var fakeControllerContext = 
        new ControllerContext(
         new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://google.com", null), 
          new HttpResponse(null))), routeData, new FakeController()); 
       var razorViewEngine = new RazorViewEngine(); 
       var razorViewResult = razorViewEngine.FindView(fakeControllerContext, viewName, "", false); 
       var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, 
        new ViewDataDictionary(model), new TempDataDictionary(), writer); 
       razorViewResult.View.Render(viewContext, writer); 
       return writer.ToString(); 
      } 
     } 

     public static string RenderViewToString(string controllerName, string viewName, Dictionary<string, Object> data) 
     { 
      using (var writer = new StringWriter()) 
      { 
       var viewData = new ViewDataDictionary(); 
       foreach (var kv in data) 
       { 
        viewData[kv.Key] = kv.Value; 
       } 

       var routeData = new RouteData(); 
       routeData.Values.Add("controller", controllerName); 
       var fakeControllerContext = 
        new ControllerContext(
         new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://google.com", null), 
          new HttpResponse(null))), routeData, new FakeController()); 
       var razorViewEngine = new RazorViewEngine(); 
       var razorViewResult = razorViewEngine.FindView(fakeControllerContext, viewName, "", false); 
       var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, viewData, 
        new TempDataDictionary(), writer); 
       razorViewResult.View.Render(viewContext, writer); 
       return writer.ToString(); 
      } 
     } 

     private class FakeController : ControllerBase 
     { 
      protected override void ExecuteCore() 
      { 
      } 
     } 
    } 

編輯

我們已經組建了一個類應在理論的工作,但它不。 RouteData具有集合中的MVC和API路由。

public static class Url 
    { 
     public static bool IsWebApiRequest() 
     { 
      return 
       HttpContext.Current.Request.RequestContext.HttpContext.CurrentHandler is 
        System.Web.Http.WebHost.HttpControllerHandler; 
     } 

     public static string RouteUrl(string routeName, object routeValues = null) 
     { 
      var url = String.Empty; 
      try 
      { 
       if (IsWebApiRequest()) 
       { 
        var helper = new System.Web.Http.Routing.UrlHelper(); 
        url = helper.Link(routeName, routeValues);    
       } 
       else 
       { 
        var helper = new System.Web.Mvc.UrlHelper(); 
        url = helper.RouteUrl(routeName, routeValues);    
       } 

       return url; 
      } 
      catch 
      { 
       return url; 
      } 
     } 

     public static string HttpRouteUrl(string routeName, object routeValues = null) 
     { 
      var url = String.Empty; 
      try 
      { 
       if (IsWebApiRequest()) 
       { 
        var helper = new System.Web.Http.Routing.UrlHelper(); 
        url = helper.Link(routeName, routeValues); 
       } 
       else 
       { 
        var helper = new System.Web.Mvc.UrlHelper(); 
        url = helper.HttpRouteUrl(routeName, routeValues); 
       } 

       return url; 
      } 
      catch 
      { 
       return url; 
      } 
     } 
    } 

回答

3

這個問題已經通過建立一個自定義UrlHelper類,看起來到RouteTable,然後返回替換爲模式的URL解決。

public static class Link 
{ 
    public static string RouteUrl(string routeName, object routeValues = null) 
    { 
     var url = String.Empty; 
     try 
     { 
      var route = (Route)RouteTable.Routes[routeName]; 
      if (route == null) 
       return url; 

      url = "~/".AbsoluteUrl() + route.Url; 
      url = url.Replace("{culture}", System.Threading.Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName.ToLower()); 

      if (routeValues == null) 
       return url; 

      var values = routeValues.GetType().GetProperties(); 
      Array.ForEach(values, pi => url = Regex.Replace(url, "{" + pi.Name + "}", pi.GetValue(routeValues, null).ToString())); 

      return url; 
     } 
     catch 
     { 
      var newUrl = RouteUrl("403"); 
      if(newUrl == String.Empty) 
       throw; 

      return newUrl; 
     } 
    } 

    public static string HttpRouteUrl(string routeName, object routeValues = null) 
    { 
     return RouteUrl(routeName, routeValues); 
    } 
} 
+0

偉大的實施,大大幫助我。 – BastanteCaro

1

嘗試Uri.Link(routeName,對象)

var uri = Url.Link("api.cart.get.checkout", new { id = 1 }); 

如果屬性名稱的路由參數匹配這將注入給定對象的屬性到路線。

+0

恐怕我們也試過這個,並且它不起作用,大多數url都是在佈局文件中隨時產生的。 Url.Link只能在WebApiController的上下文中使用。 – NullBy7e

1

WebApi不是MVC。儘管看起來非常相似,但它是一個完全不同的系統。

UrlHelper(即MVC)將查看MVC路由表,並忽略任何WebApi路由。

嘗試創建難度較大的路線,本質上是將控制器和動作名稱硬編碼到視圖中。 :-(

+0

我們已經檢查了RouteData集合,它包含了MVC和API路線。 – NullBy7e

1

OK,根據您的意見,似乎你想打電話給你Url.RouteUrl(string routeName, object routeValues = null)Url.HttpRouteUrl(string routeName, object routeValues = null)從你的MVC layout.cshtml文件。

如果是這樣的情況下,Url.IsWebApiRequest()將返回false因爲layout.cshtml文件作爲處理MVC請求,而不是部分的WebAPI纔會處理。這將導致URL生成方法來使用,而不是收集的WebAPI MVC路由集合。

更改Url類因此RouteUrl始終構建WebAPI url,並且HttpRouteUrl僅構建MVC網址,然後在您的佈局文件中使用基於您在特定上下文中需要哪種網址的適當方法。

public static class Url 
{ 
    public static bool IsWebApiRequest() 
    { 
     return 
      HttpContext.Current.Request.RequestContext.HttpContext.CurrentHandler is 
       System.Web.Http.WebHost.HttpControllerHandler; 
    } 

    public static string RouteUrl(string routeName, object routeValues = null) 
    { 
     var url = String.Empty; 
     try 
     { 
      var helper = new System.Web.Http.Routing.UrlHelper(); 
      return helper.Link(routeName, routeValues);    
     } 
     catch 
     { 
      return url; 
     } 
    } 

    public static string HttpRouteUrl(string routeName, object routeValues = null) 
    { 
     var url = String.Empty; 
     try 
     { 
      var helper = new System.Web.Mvc.UrlHelper(); 
      return helper.HttpRouteUrl(routeName, routeValues); 
     } 
     catch 
     { 
      return url; 
     } 
    } 
} 
相關問題