C# 有没有办法用WebAPI生成URL?
在下面进行后期编辑 我们无法理解为什么从WebApi控制器的上下文使用时,C# 有没有办法用WebAPI生成URL?,c#,asp.net-mvc,model-view-controller,asp.net-web-api,C#,Asp.net Mvc,Model View Controller,Asp.net Web Api,在下面进行后期编辑 我们无法理解为什么从WebApi控制器的上下文使用时,UrlHelper返回空字符串 我们已经做了必要的调试,但我们无法找出为什么会发生这种情况,RouteData中有路由,但它似乎不起作用 在大多数情况下,我们使用RenderViewToString函数,该函数加载由调用Url.RouteUrl(routeName)组成的视图 已经尝试过的方法是创建一个自定义的UrlHelper(但没有效果)并使用UrlHelper(MVC/HTTP)进行调试 属性路由与路由名称一起使用
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()
{
}
}
}
试试Uri.Link(routeName,object)
如果属性名称与路由参数匹配,这将把给定对象的属性注入路由。WebApi不是MVC。尽管看起来很相似,但这是一个完全不同的系统 UrlHelper(即MVC)将查看MVC路由表,并忽略任何WebApi路由
尝试用硬方法创建路由,本质上是将控制器和操作名称硬编码到视图中:-(好的,根据您的评论,您似乎试图从MVC layout.cshtml文件中调用
Url.RouteUrl(string routeName,object routeValues=null)
或Url.HttpRouteUrl(string routeName,object routeValues=null)
如果是这种情况,则Url.IsWebApiRequest()
将返回false
,因为layout.cshtml文件仅作为处理MVC请求的一部分进行处理,而不是WebAPI。这将导致Url生成方法使用MVC路由集合而不是WebAPI集合
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;
}
}
}
更改Url
类,使RouteUrl
始终构建WebAPI Url,而HttpRouteUrl
仅构建MVC Url,然后在布局文件中根据特定上下文中需要的Url类型使用适当的方法
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;
}
}
}
这个问题已经通过构建一个定制的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);
}
}
恐怕我们也试过了,但没有效果,大多数Url都是在布局文件中动态生成的。Url.Link只能在WebApicController的上下文中使用。我们已经检查了RouteData集合,它包含MVC和API路由。很好的实现对我帮助很大。
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);
}
}