【问题标题】:C# - WebApi2 - Post and Get - Post is not converting x-www-form-urlencoded to objectC# - WebApi2 - Post and Get - Post 没有将 x-www-form-urlencoded 转换为对象
【发布时间】:2017-03-09 20:53:46
【问题描述】:

我正在尝试在 WebApi2 中创建两个方法,它们会将数据放入一个对象并返回一个令牌。

Get 命令完美运行。

    [HttpGet]
    [Route("refresh")]
    public HttpResponseMessage refresh([FromUri] oAuthTokenRequest tokenItem)
    {
        var device = new ConnectedDevices();
        var AuthString = device.getAuthorization(Request.Headers.Authorization.Parameter);
        var serviceKey = new ServiceKeyManagement();
        var accessToken = new oAuthAccessResponse();
        var response = Request.CreateResponse(HttpStatusCode.Forbidden, "Unknown", "application/json");
        var clientID = AuthString[0];
        var errorResponse = new oAuthErrorResponse();
        var oauth = new oAuthAuthenticationCode();
        String email = String.Empty;
        var tokenRequest = new oAuthTokenRequest();

        Log.Debug("oAuth REST API GET: Refresh: Authorization Parameter: " + Request.Headers.Authorization.Parameter, this);
        Log.Debug("oAuth REST API GET: Refresh: clientID: " + clientID, this);
        Log.Debug("oAuth REST API GET: Refresh: Request: " + Request.RequestUri, this);

        if (!serviceKey.isValidServiceKey(clientID, AuthString[1]))
        {
            errorResponse.error = oAuthCodes.ErrorCodes.unauthorized_client.ToString();
            errorResponse.error_description = "Invalid Service Key";
            errorResponse.error_uri = String.Empty;
            response = Request.CreateResponse(HttpStatusCode.Forbidden, errorResponse, "application/json");
            response.ReasonPhrase = "refresh: Invalid Login Request.";
        }           // end of if (!serviceKey.isValidServiceKey(clientID, AuthString[1]))
        else
        {
            Log.Debug("oAuth REST API GET: Refresh: NameValuePairs: " + tokenItem.grant_type, this);

            tokenRequest.redirect_url = tokenItem.redirect_url;
            tokenRequest.code = tokenItem.code;
            tokenRequest.grant_type = tokenItem.grant_type;
            tokenRequest.clientID = clientID;
            response = tokenValidation(tokenRequest, clientID);
        }           // end else for  if (!serviceKey.isValidServiceKey(clientID, AuthString[1]))
        return response;
    }           // end of public HttpResponseMessage Login(ConnectedDeviceViewModel login)

这会从 URI 中读取变量,然后将它们解析为对象。

Post 命令没有这样做:

    [HttpPost]
    [Route("refresh")]
    public HttpResponseMessage refreshPost([FromBody] oAuthTokenRequest tokenItem)
    {
        var device = new ConnectedDevices();
        var AuthString = device.getAuthorization(Request.Headers.Authorization.Parameter);
        var serviceKey = new ServiceKeyManagement();
        var accessToken = new oAuthAccessResponse();
        var response = Request.CreateResponse(HttpStatusCode.Forbidden, "Unknown", "application/json");
        var clientID = AuthString[0];
        var errorResponse = new oAuthErrorResponse();
        var oauth = new oAuthAuthenticationCode();
        String email = String.Empty;
        var tokenRequest = new oAuthTokenRequest();

        Log.Debug("oAuth REST API: Refresh POST: Authorization Parameter: " + Request.Headers.Authorization.Parameter, this);
        Log.Debug("oAuth REST API: Refresh POST: clientID: " + clientID, this);
        Log.Debug("oAuth REST API: Refresh POST: Request: " + Request.RequestUri, this);

        if (!serviceKey.isValidServiceKey(clientID, AuthString[1]))
        {
            errorResponse.error = oAuthCodes.ErrorCodes.unauthorized_client.ToString();
            errorResponse.error_description = "Invalid Service Key";
            errorResponse.error_uri = String.Empty;
            response = Request.CreateResponse(HttpStatusCode.Forbidden, errorResponse, "application/json");
            response.ReasonPhrase = "refresh: Invalid Login Request.";
        }           // end of if (!serviceKey.isValidServiceKey(clientID, AuthString[1]))
        else
        {
            Log.Debug("oAuth REST API POST: Refresh: NameValuePairs: " + String.Join(" : ", Request.GetQueryNameValuePairs().ToList()), this);

            tokenRequest.redirect_url = tokenItem.redirect_url;
            tokenRequest.code = tokenItem.code;
            tokenRequest.grant_type = tokenItem.grant_type;
            tokenRequest.clientID = clientID;
            response = tokenValidation(tokenRequest, clientID);
        }           // end else for  if (!serviceKey.isValidServiceKey(clientID, AuthString[1]))
        return response;
    }

如果这是正在发送的 JSON,则该帖子可以完美运行。我已经尝试过各种方式的签名:

    [HttpPost]
    [Route("refresh")]
    public HttpResponseMessage refreshPost([FromBody] oAuthTokenRequest tokenItem)

    [HttpPost]
    [Route("refresh")]
    public HttpResponseMessage refreshPost(oAuthTokenRequest tokenItem)

    [HttpPost]
    [Route("refresh")]
    public HttpResponseMessage refreshPost(FormDataFormat oAuthTokenRequest tokenItem)

在每种情况下,如果我尝试发送以下请求:

POST /api/TokenAuthorization/refresh HTTP/1.1
Host: localhost.www.bissell.com
Authorization: Basic U21hcnRDbGVhbkFsZXhhOlJOWFpfaEFQWUhBVHpVTTc1STVrdDVQcmlEUkkzV0VtdG5FX1dCS0ZiaUEtVGRBVXZtMWZzNldKRV9ZOFJXajVicEVnbmxpdmp2eWJsNkRYelhEYmR1SXB0d0VGV2IwbDRWbXpBWFI3d1VxX2twaklzLTQ4SDRfTnc2Q2YtNy1ZaVpWcU9RSGlBNjFmUWI0MWJoNU1vUjVFd0hMMExZam8tVkszWXJRa3RabWlPb0pTSXVNdWtRazJ2Tjl3MFFmdF9YTWRuUHY5eDNXRFBtMlB0TURSV2VhMVZOUXpDeVFzd0xJRFhtaU1ZbmVhNFBQZ2V3cHp0UmNFU2RjVVlMY0puQVZ5SF90TS01TUg5ZVcwOWRFNmtjMV9BSWRDc3FUcHQwTHB5V1ltVFpjVEVGcGtkdlBwSWJ1N21Od3ZWb0tCU2hZZ0RabEdpQ1dzNVVoM25DbGVVVE5FdXVNaVJiVUdsUWJIVEJKdmtWUmNQbk9qZzJSRHA5ZjBwTml3ZU1fOEthazlQRU1pNXNuSkFMaFo5bWFQTmRVTVNMaXQ1T1VkbVZYVDhuckU5eVdWN1cyS1J2bDh0ZnFsX0Z0OVVNWWFfRjI3TTlGV2dFdm9FbndZV3RyVlgxYkxPdWk1QUlFNVU3OGhzd3loYk5TMkJzRnN2Sk5YaU9icExRa2NESWNrN3g4OWVCaUdsUGNSbGkxdDRBbEVfWER6ZDFzcVNwcURWdjR2NGJwRklYUFRaWXh6MzlhSFl1akdaXzhmMW5QRjYzN3d4WFNDcU52SkpublZYRWR1T1Ey
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
Postman-Token: 434aa7f2-a3d2-ce43-d300-001d61be4562

grant_type=authorization_code&code=20620A62853B45B9BEEA6E67C7587BC1%3AC0DB652683B5ACB67797A42D3DDB4D03ABA0561100137DB812602C57E17736E72D6E1E35D5A56C7F67B1760EA33A539D932C7A96A1853E4E103118F41D004D7E&redirect_url=abc&clientID=abc&clientSecret=abc

我收到以下错误

"ExceptionMessage": "This method or property is not supported after HttpRequest.Form, Files, InputStream, or BinaryRead has been invoked.

我的 WebApiConfig.cs 如下所示:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;

        config.Formatters.Remove(config.Formatters.XmlFormatter);
    }
}

我在互联网上高高在上,他们所说的一切都是我在做的。所以,我猜我缺少一些基本的东西,很可能是在 WebApiConfig 中。任何帮助将不胜感激。

更新 所以,这不是我想要编写代码的方式,但是,我确实找到了这个解决方案: Is there a way to handle form post data in a Web Api controller?

            var httpctx = (HttpContextWrapper)Request.Properties["MS_HttpContext"];
            tokenRequest.redirect_url = httpctx.Request.Form["redirect_url"] ?? null;
            tokenRequest.code = httpctx.Request.Form["code"] ?? null;
            tokenRequest.grant_type = httpctx.Request.Form["grant_type"] ?? null;
            tokenRequest.clientID = clientID;

【问题讨论】:

  • 您必须以 x-www-form-urlencoded 格式发送数据吗?将 JSON 与 web api 一起使用时,我的运气要好得多。
  • 很遗憾,我必须将它作为 x-www-form-urlencoded 发送。这是为了遵守标准(oAuth)
  • 这部分的 JSON 部分运行良好。
  • 所以,我所做的调整使 x-web-form-urlencode 工作,但现在 JSON 不是。最有可能的。这将需要一些 TLC 的内容

标签: c# asp.net-web-api2


【解决方案1】:

如果您仍在寻找执行此操作的标准方法,则必须扩展 IModelBinder 类

下面是一个示例

public class CustomModelBinder : IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        ObjToPass obj = new ObjToPass();
        var parameter =HttpUtility.ParseQueryString(HttpUtility.UrlDecode(actionContext.Request.Content.ReadAsStringAsync().Result).Remove(0,4));

        var res = parameter.ToString().Split('&');
        obj.Id = Convert.ToInt32(res[0].Split('=')[1]);
        obj.Name = res[1].Split('=')[1];
        bindingContext.Model = obj;
        //obj.Id = Convert.ToInt32(bindingContext.PropertyMetadata.Values[0]);
        return true;
    }
}

public class CustomerOrderModelBinderProvider : ModelBinderProvider
{
    public override IModelBinder GetBinder(System.Web.Http.HttpConfiguration configuration, Type modelType)
    {
        return new CustomModelBinder();
    }
}

然后在你的控制器中添加这个

[HttpPost]
    public void PostValues([ModelBinder(typeof(CustomerOrderModelBinderProvider))] ObjToPass obj)
    { }

我在请求正文中传递值。如果您采用这种方法,则必须根据需要更改 BindModel。我已经硬编码并使用了拆分和数组值。

【讨论】:

    【解决方案2】:

    使用 [FromUri]

    POST api/default?Id=1&Name=Boopathy HTTP/1.1
    Host: localhost:51715
    Connection: keep-alive
    Content-Length: 0
    Postman-Token: 86a69035-eea6-16fe-8ecd-86421336f46d
    Cache-Control: no-cache
    Origin: chrome-extension://aicmkgpgakddgnaphhhpliifpcfhicfo
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
    Content-Type: application/x-www-form-urlencoded
    Accept: */*
    Accept-Encoding: gzip, deflate, br
    Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
    

    【讨论】:

    • 我之前尝试过,但它不起作用。查询字符串在正文中,而不是在 URI 中。
    【解决方案3】:

    所以,我不喜欢这个答案,但它确实有效:

                var httpctx = (HttpContextWrapper)Request.Properties["MS_HttpContext"];
                if (Request.Content.Headers.ContentType.MediaType == "application/x-www-form-urlencoded")
                {
                    tokenRequest.redirect_url = httpctx.Request.Form["redirect_url"] ?? null;
                    tokenRequest.code = httpctx.Request.Form["code"] ?? null;
                    tokenRequest.grant_type = httpctx.Request.Form["grant_type"] ?? null;
                }
                else
                {
                    var bodyText = Request.Content.ReadAsAsync<oAuthTokenRequest>().Result;
                    tokenRequest.redirect_url = bodyText.redirect_url;
                    tokenRequest.code = bodyText.code;
                    tokenRequest.grant_type = bodyText.grant_type;
                }
    

    它将对 form-urlencoded 和 json 的请求分开。

    【讨论】:

      猜你喜欢
      • 2019-03-04
      • 1970-01-01
      • 2021-06-15
      • 1970-01-01
      • 2018-08-18
      • 1970-01-01
      • 2018-06-11
      • 2015-08-16
      • 1970-01-01
      相关资源
      最近更新 更多