【问题标题】:Is there a utility to serialise an object as HTTP content type "application/x-www-form-urlencoded"?是否有将对象序列化为 HTTP 内容类型“application/x-www-form-urlencoded”的实用程序?
【发布时间】:2017-04-02 00:10:42
【问题描述】:

我以前从来没有这样做过,因为它一直只是我作为该内容类型发布的实际表单,但最近我不得不发布三个这样的变量,并且我使用了一个肮脏的连接&=:

var content = new StringContent("grant_type=password&username=" + username + "&password=" + password.ToClearString(), Encoding.UTF8,
    "application/x-www-form-urlencoded");

我确信必须有一个实用方法可以做到这一点,并且做得更好,并使用任何必要的编码。那会是什么?

【问题讨论】:

    标签: http asp.net-web-api http-post content-type dotnet-httpclient


    【解决方案1】:

    如果这是一个 POCO 并且只使用 Newtonsoft 库,您也可以使用它:

    public static class FormUrlEncodedContentExtension
    {
        public static FormUrlEncodedContent ToFormUrlEncodedContent(this object obj)
        {
            var json = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
    
            var keyValues = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
    
            var content = new FormUrlEncodedContent(keyValues);
    
            return content;
        }
    
    }
    

    示例用法如下:

    var myObject = new MyObject {Grant_Type = "TypeA", Username = "Hello", Password = "World"};
    
    var request = new HttpRequestMessage(HttpMethod.Post, "/path/to/post/to")
    {
        Content = myObject.ToFormUrlEncodedContent()
    };
    var client = new HttpClient {BaseAddress = new Uri("http://www.mywebsite.com")};
    var response = await client.SendAsync(request);
    

    【讨论】:

      【解决方案2】:

      使用反射获取属性名称和值,然后使用它们创建System.Net.Http.FormUrlEncodedContent

      public static class FormUrlEncodedContentExtension {
      
          public static FormUrlEncodedContent ToFormUrlEncodedContent(this object obj) {
              var nameValueCollection = obj.GetType()
                  .GetProperties()
                  .ToDictionary(p => p.Name, p => (p.GetValue(obj) ?? "").ToString());
      
              var content = new FormUrlEncodedContent(nameValueCollection);
      
              return content;
          }
      
      }
      

      从那里调用对象的扩展方法将其转换为FormUrlEncodedContent是一件简单的事情

      var model = new MyModel {
          grant_type = "...",
          username = "...",
          password = "..."
      };
      
      var content = model.ToFormUrlEncodedContent();
      

      【讨论】:

        【解决方案3】:

        您应该能够为此使用字符串插值。比如:

        var content = new StringContent($"grant_type=password&username={username}&password={password}", Encoding.UTF8, "application/x-www-form-urlencoded");
        

        或者将其包装在一个辅助/工厂方法中:

        public static class StringContentFactory
        {
            public static StringContent Build(string username, string password)
            {
                return new StringContent($"grant_type=password&username={username}&password={password}", Encoding.UTF8, "application/x-www-form-urlencoded");
            }
        }
        

        【讨论】:

        • 这意味着我必须知道对象中每个属性的名称,使代码仅对一个类有用,并且必须为要序列化的每个对象重写它。老实说,这是一个非常糟糕的解决方案。
        • 对不起,我误解了这个问题。我认为这是针对提供的那段代码的特定内容。因此,该解决方案并不是真正打算成为可以处理具有不同属性的对象的通用解决方案。
        • 如果只是那一段代码,为什么还要写一个方法来编码呢?我不妨按原样使用代码。方法的基本原则是通用性。
        猜你喜欢
        • 2020-04-21
        • 1970-01-01
        • 1970-01-01
        • 2015-04-02
        • 2021-02-03
        • 1970-01-01
        • 2019-09-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多