如何仅从uri

时间:2015-11-01 14:09:01

标签: .net asp.net-web-api asp.net-web-api-routing

为简单起见,请考虑人员资源,例如

{"name":"Fred Flintston",
"worksAt":
   {"href":"api/sites?cn=Slate%20Rock%20and%20Gravel%20Company"}
}

当我在POST上收到PeopleController时,我需要从worksAt.href获取站点资源。

我想要做的是在SitesController上调用正确的GET,利用已经知道如何解析uri并调用正确方法的路由引擎。

我看到一个似乎相当沉重的建议here,而且我完全不确定如何允许已经发生的授权继续执行。

2 个答案:

答案 0 :(得分:6)

您可以尝试以下方法,但如果您详细描述了您想要实现的目标,我们可能会找到更好的解决方案。它是基于MVC的,但也适用于Web API。

var baseUrl = string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority, Url.Content("~"));
var requestUrl = new Uri(baseUrl + "Home/Index?i=42");

//get method info
var httpContext = new HttpContextWrapper(new HttpContext(new HttpRequest("/", requestUrl.AbsoluteUri, ""), new HttpResponse(new StringWriter())));
var requestContext = new RequestContext(httpContext, RouteTable.Routes.GetRouteData(httpContext));
var controllerType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(x => x.Name == requestContext.RouteData.Values["controller"].ToString() + "Controller");
var controllerContext = new ControllerContext(requestContext, Activator.CreateInstance(controllerType) as ControllerBase);
var controllerDescriptor = new ReflectedControllerDescriptor(controllerType);
var actionDescriptor = controllerDescriptor.FindAction(controllerContext, controllerContext.RouteData.Values["action"].ToString());
var methodInfo = (actionDescriptor as ReflectedActionDescriptor).MethodInfo;

//parse the query string
var qscoll = HttpUtility.ParseQueryString(requestUrl.Query);
//and use the only item in it as an int when calling the action
var ret = methodInfo.Invoke(Activator.CreateInstance(controllerType), new object[] { int.Parse(qscoll[0]) });

现在烘焙参数传递,因此您需要根据参数名称和类型创建正确排序的参数数组。

答案 1 :(得分:0)

我建议您使用动作过滤器,以获得干净通用的解决方案, 如果要在响应中传递href属性并将用户重新路由到其他操作,则可以使用reroute属性。

public class RerouteAttribute : ActionFilterAttribute
{
   public override void OnActionExecuted(HttpActionExecutedContextb actionExecutedContext)
        {
           // using the code of Tamas above me to invoke the action 
           var response = ((ObjectContent)(actionExecutedContext.Response.Content)).Value.Href;
           //get method info
          var httpContext = new HttpContextWrapper(new HttpContext(new HttpRequest("/", response.AbsoluteUri, ""), new HttpResponse(new StringWriter())));
          var requestContext = new RequestContext(httpContext, RouteTable.Routes.GetRouteData(httpContext));
          var controllerType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(x => x.Name == requestContext.RouteData.Values["controller"].ToString() + "Controller");
          var controllerContext = new ControllerContext(requestContext, Activator.CreateInstance(controllerType) as ControllerBase);
          var controllerDescriptor = new ReflectedControllerDescriptor(controllerType);
          var actionDescriptor = controllerDescriptor.FindAction(controllerContext, controllerContext.RouteData.Values["action"].ToString());
          var methodInfo = (actionDescriptor as ReflectedActionDescriptor).MethodInfo;

          //parse the query string
          var qscoll = HttpUtility.ParseQueryString(requestUrl.Query);
          //and use the only item in it as an int when calling the action
          var ret = methodInfo.Invoke(Activator.CreateInstance(controllerType), new object[] { int.Parse(qscoll[0]) });

        }
    }
值得深思的是,你为什么需要这样做? 也许你的应用程序架构不正确, 考虑一下 - 不是在某个控制器中调用不同的动作,为什么不在控制器外部的某些服务中调用一个方法来完成需要完成的工作? 这需要你把核心逻辑放在控制器之外,而逻辑服务里面则是你应用程序的核心业务逻辑, 在某个服务中的一个函数中显式使用对于查看者来说更加简单优雅和清晰。

我建议您阅读有关-lean控制器,胖模型和软件开发中的3层架构的原理,

祝你好运。