是否有将对象序列化为 HTTP 内容类型 "application/x-www-form-urlencoded" 的实用程序?

Is there a utility to serialise an object as HTTP content type "application/x-www-form-urlencoded"?

我以前从来没有这样做过,因为它一直只是我 post 编辑为该内容类型的实际形式,但最近我不得不 post 三个变量就像那样,我求助于 &=:

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

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

您应该能够为此使用字符串插值。类似于:

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

或者将其包装在 helper/factory 方法中:

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

使用反射获取 属性 名称和值,然后使用它们创建 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();

如果这是一个 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);