c# - 有没有办法用 WebAPI 生成 Urls?

标签 c# asp.net-mvc model-view-controller asp.net-web-api

编辑如下

我们无法弄清楚为什么 UrlHelper 在从 WebApi Controller 的上下文中使用时返回空字符串。

我们已经完成了必要的调试,但我们无法找出为什么会发生这种情况,RouteData 中有路由,但它似乎不起作用。

在大多数情况下,我们使用 RenderViewToString 函数,它加载包含调用 Url.RouteUrl(routeName) 的 View 。

已尝试创建自定义 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;
            }
        }
    }

最佳答案

此问题已通过构建自定义 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);
    }
}

关于c# - 有没有办法用 WebAPI 生成 Urls?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33688710/

相关文章:

c# - Jquery Accordion : How do I get rid of these scroll bars for good?

c# - 这是什么字符? 65279 ''

asp.net-mvc - Bootstrap 3 Glyphicons 在 window mobile 中不起作用

model-view-controller - 游戏逻辑应该位于 JavaFx 应用程序中的哪个位置?

javascript - 绑定(bind)在 ng-repeat 内的嵌套元素中不起作用

java - 哪些 MVC 框架可用于 Java 桌面/winform 应用程序?

c# - 笔相对于 x 和 y 客户端位置的绘制位置

c# - 如何跳转到 PrintDocument 中的下一页?

asp.net-mvc - 如何防止页面刷新?

c# - 将动态创建的元素绑定(bind)到 View 中的复杂 mvc 模型