【问题标题】:MVC Api Action & System.Web.Http.AuthorizeAttribute - How to get post parameters?MVC Api Action & System.Web.Http.AuthorizeAttribute - 如何获取发布参数?
【发布时间】:2012-08-26 08:13:07
【问题描述】:

我有以下 API 控制器:

public class TestController : ApiController
{
    [HttpPost]
    [APIAuthorizeAttribute]
    public IQueryable<Computers> ListOfComputersInFolder(Guid folderId)
    {
        return GetListOfComputersForFolder(folderId);
    } // End of ListOfComputersInFolder
} // End of TestController 

以下是我的基本APIAuthorizeAttribute

public class APIAuthorizeAttribute : System.Web.Http.AuthorizeAttribute
{
    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        var Request = System.Web.HttpContext.Current.Request;
        var folderId = Request.RequestContext.RouteData.Values["folderId"] ?? Request.Params["folderId] as string;
        if(null == folderId)
        {
            folderId = actionContext.ControllerContext.RouteData.Values["folderId"];
        }

        base.OnAuthorization(actionContext);
    }
}

我遇到的问题是 folderId 在 onAuthorize 方法中为空。 (我的提取器基于this 代码)。

在我看来这应该可行,但我似乎无法做到。关于我做错了什么以及我应该如何获取发布的参数的任何想法?

编辑:我尝试使用以下内容直接读取帖子数据:

using (StreamReader inputStream = new StreamReader(request.InputStream))
{
    output = inputStream.ReadToEnd();
}
request.InputStream.Position = 0;

这让我得到了 JSON 格式的帖子数据,然后我可以对其进行解析,但是我的调用却始终没有成功。我在响应中得到以下异常:

  <h2>500 - Internal server error.</h2>
  <h3>There is a problem with the resource you are looking for, and it cannot be displayed.

at System.Json.JXmlToJsonValueConverter.JXMLToJsonValue(Stream jsonStream, Byte[] jsonBytes)\u000d\u000a   at System.Net.Http.Formatting.JsonMediaTypeFormatter.<>c__DisplayClass7.<OnReadFromStreamAsync>b__6()\u000d\u000a   at System.Net.Http.Internal.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)"}

编辑: 最后,这似乎可能是ApiControllerSystem.Web.Http.AuthorizeAttributeHttpPost 组合的错误(使用HttpGet 时确实有效)。已提交错误报告。

【问题讨论】:

    标签: c# asp.net-mvc post controller


    【解决方案1】:

    AuthorizeAttribute 应该有一个AuthorizationContext 参数而不是一个HttpActionContext 参数,您应该可以从中访问RouteData,例如

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var folderId = filterContext.RouteData.Values["folderId"];
        ...
    }
    

    更新

    注意到您正在使用ApiController,因此使用Http.AuthorizeAttribute(解释为什么您没有AuthorizationContext)。在这种情况下,您可以通过操作上下文获取RouteData,例如

    var folderId = actionContext.Request.GetRouteData().Values["folderId"];
    

    【讨论】:

    • 请注意,因为这是APIController 而不是Controller,所以我使用System.Web.Http.AuthorizeAttribute 而不是System.Web.Mvc.AuthorizeAttribute。我尝试访问它的 `ControllerContext.RouteData.Values["folderId"] 并且它仍然返回 null。
    • 谢谢我也看了这个,但还是没有运气。 actionContext.Request 类是 HttpRequestMessage 并且不包含 GetRouteData 方法。另外,如果我查看:actionContext.ControllerContext.RouteData.Values 它只包含两个键:控制器和操作。我认为我最好的选择是从 inputStream 中读取发布数据。我试了一下,确认我可以看到我的帖子数据,但似乎有点 hacky,所以我现在要继续寻找。
    • @Zenox GetRouteDataHttpRequestMessage 的扩展方法,请确保包含对System.Web.Http 命名空间的引用。
    • 啊,谢谢。添加命名空间确实添加了扩展方法,但keys 属性仅包含“控制器”和“操作”。从我所看到的情况来看,我认为必须在框架填充其余值之前调用 OnAuthorization 方法。
    • 你在使用HttpPost吗?只是为了测试,我切换到HttpGet,现在我可以通过System.Web.HttpContext.Current.Request["folderId"]获取数据。
    【解决方案2】:

    我也遇到过这个问题。

    为了解决这个问题,我编写了以下从 OnAuthorization 方法中调用的方法:

    private static object GetValueFromActionContext(HttpActionContext actionContext, string key)
    {
        var queryNameValuePairs = actionContext.Request.GetQueryNameValuePairs();
    
        var value = queryNameValuePairs
            .Where(pair => pair.Key.Equals(key, StringComparison.OrdinalIgnoreCase))
            .Select(pair => pair.Value)
            .FirstOrDefault();
    
        var methodInfo = ((ReflectedHttpActionDescriptor) (actionContext.ActionDescriptor)).MethodInfo;
        var parameters = methodInfo.GetParameters();
        var parameterType =
            parameters.Single(p => p.Name.Equals(key, StringComparison.OrdinalIgnoreCase)).ParameterType;
    
        var converter = TypeDescriptor.GetConverter(parameterType);
    
        return converter.ConvertFromString(value);
    }
    

    这段代码做了以下假设:

    • 您提取的键与操作方法上的参数名称匹配。

    • 您获取的参数类型将有一个对该类型有效的转换器。

    • 您没有在参数上使用任何自定义绑定或格式。

    在我使用代码的场景中,我只期望简单的类型,例如 Guid、Boolean、String 等,并且可以根据您的要求进行自定义。

    扩展方法 GetQueryNameValuePairs 是 System.Net.Http.HttpRequestMessageExtensions 类的一部分,将读取查询字符串/表单数据。

    使用示例:

    object folderId = GetValueFromActionContext(actionContext, "folderId");
    

    【讨论】:

      【解决方案3】:

      如果请求的内容类型是application/json;charset=utf-8

      API 操作可以检索 Post Data,如下所示:

      Stream stream = actionContext.Request.Content.ReadAsStreamAsync().Result;
      Encoding encoding = Encoding.UTF8;
      stream.Position = 0;
      string responseData = "";
      
      using (StreamReader reader = new StreamReader(stream, encoding))
      {
          responseData = reader.ReadToEnd().ToString();
      }
      
      var dic = JsonConvert.DeserializeObject<IDictionary<string, string>>(responseData);
      

      【讨论】:

        【解决方案4】:

        你可以试试这个扩展方法:(这是工作代码的摘录)

        public static string GetParameter(this RequestContext requestContext, string key)
        {
            if (key == null) throw new ArgumentNullException("key");
        
            var lowKey = key.ToLower();
        
            return requestContext.RouteData.Values.ContainsKey(lowKey) &&
                   requestContext.RouteData.Values[lowKey] != null
                       ? requestContext.RouteData.Values[lowKey].ToString()
                       : requestContext.HttpContext.Request.Params[lowKey];
        }
        

        我同意 James 的回答,在这种情况下,您必须通过 actionContext 访问请求上下文。

        【讨论】:

          猜你喜欢
          • 2011-09-11
          • 1970-01-01
          • 2014-03-18
          • 2014-01-22
          • 2016-11-20
          • 2017-04-29
          • 1970-01-01
          • 2015-02-13
          • 2013-10-25
          相关资源
          最近更新 更多