MVC Api Action&System.Web.Http.AuthorizeAttribute - 如何获取帖子参数?

时间:2022-09-25 14:43:31

I have the following API Controller:

我有以下API控制器:

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

And the following is my basic APIAuthorizeAttribute.

以下是我的基本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);
    }
}

The problem that I'm having is that folderId is coming out null in the onAuthorize method. (I based the fetcher on this code).

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

It seems to me that this should be working, but I cannot seem to get it to. Any ideas on what I am doing wrong and how I should go about getting the posted parameter?

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

Edit: I tried reading the post data directly with the following:

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

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

Which gets me the post data in JSON format which I could then parse, but then my call never makes it though. I get the following exception in the Response:

这让我得到了JSON格式的帖子数据然后我可以解析,但是我的呼叫从来没有成功。我在Response中得到以下异常:

  <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)"}

EDIT: In the end, it seems like this could possibly be a bug with the combination of ApiController, System.Web.Http.AuthorizeAttribute and HttpPost (it does work when using HttpGet). A bug report has been submitted.

编辑:最后,似乎这可能是ApiController,System.Web.Http.AuthorizeAttribute和HttpPost组合的一个错误(它在使用HttpGet时确实有效)。已提交错误报告。

4 个解决方案

#1


7  

The AuthorizeAttribute should have an AuthorizationContext parameter rather than a HttpActionContext one, from that you should be able to access the RouteData e.g.

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

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

Update

Noticed you are using ApiController and as such using Http.AuthorizeAttribute (explains why you don't have an AuthorizationContext). In that case, you can get the RouteData via the action context e.g.

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

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

#2


1  

I have also encountered this problem.

我也遇到过这个问题。

To work around it I wrote the following method which I call from within the OnAuthorization method:

为了解决这个问题,我编写了以下方法,我在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);
}

This code makes the following assumptions:

此代码做出以下假设:

  • The key you are extracting matches an argument name on the action method.

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

  • The parameter type you are obtaining will have a converter valid for the type.

    您获得的参数类型将具有对该类型有效的转换器。

  • You are not using any custom binding or formatting on the parameter.

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

In the scenario that I am using the code I am only expecting simple types such as Guid, Boolean, String etc and could be customised as per your requirements.

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

The extension method GetQueryNameValuePairs is part of the System.Net.Http.HttpRequestMessageExtensions class and will read querystring / form data.

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

Example use:

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

#3


0  

You can give this extension method a try: (this is an excerpt of working code)

您可以尝试使用此扩展方法:(这是工作代码的摘录)

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];
}

I agree with James' answer, you have to access the request context via the actionContext in this scenario.

我同意James的回答,您必须通过此场景中的actionContext访问请求上下文。

#4


0  

If the request's contenttype is application/json;charset=utf-8

如果请求的contenttype是application / json; charset = utf-8

The API action can retrieve the Post Data as follow:

API操作可以检索发布数据,如下所示:

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);

#1


7  

The AuthorizeAttribute should have an AuthorizationContext parameter rather than a HttpActionContext one, from that you should be able to access the RouteData e.g.

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

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

Update

Noticed you are using ApiController and as such using Http.AuthorizeAttribute (explains why you don't have an AuthorizationContext). In that case, you can get the RouteData via the action context e.g.

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

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

#2


1  

I have also encountered this problem.

我也遇到过这个问题。

To work around it I wrote the following method which I call from within the OnAuthorization method:

为了解决这个问题,我编写了以下方法,我在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);
}

This code makes the following assumptions:

此代码做出以下假设:

  • The key you are extracting matches an argument name on the action method.

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

  • The parameter type you are obtaining will have a converter valid for the type.

    您获得的参数类型将具有对该类型有效的转换器。

  • You are not using any custom binding or formatting on the parameter.

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

In the scenario that I am using the code I am only expecting simple types such as Guid, Boolean, String etc and could be customised as per your requirements.

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

The extension method GetQueryNameValuePairs is part of the System.Net.Http.HttpRequestMessageExtensions class and will read querystring / form data.

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

Example use:

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

#3


0  

You can give this extension method a try: (this is an excerpt of working code)

您可以尝试使用此扩展方法:(这是工作代码的摘录)

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];
}

I agree with James' answer, you have to access the request context via the actionContext in this scenario.

我同意James的回答,您必须通过此场景中的actionContext访问请求上下文。

#4


0  

If the request's contenttype is application/json;charset=utf-8

如果请求的contenttype是application / json; charset = utf-8

The API action can retrieve the Post Data as follow:

API操作可以检索发布数据,如下所示:

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);