前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何将一个 .NET 对象序列化为 HTTP GET 的请求字符串

如何将一个 .NET 对象序列化为 HTTP GET 的请求字符串

作者头像
walterlv
发布2023-10-22 10:47:43
2820
发布2023-10-22 10:47:43
举报
文章被收录于专栏:walterlv - 吕毅的博客

HTTP GET 请求时携带的参数直接在 URL 中,形式如 ?key1=value&key2=value&key3=value。如果是 POST 请求时,我们可以使用一些库序列化为 json 格式作为 BODY 发送,那么 GET 请求呢?有可以直接将其序列化为 HTTP GET 请求的 query 字符串的吗?


HTTP GET 请求

一个典型的 HTTP GET 请求带参数的话大概是这样的:

于是我们将一个类型序列化为后面的参数:

1 2 3 4 5 6 7 8 9 10 11 12

DataContract public class Foo { DataMember(Name = "key1") public string? Key1 { get; set; } DataMember(Name = "key2") public string? Key2 { get; set; } DataMember(Name = "key3") public string? Key3 { get; set; } }

库?

可能是这个需求太简单了,所以并没有找到单独的库。所以我就写了一个源代码包放到了 nuget.org 上。

在这里下载源代码包:

你不需要担心引入额外的依赖,因为这是一个源代码包。关于源代码包不引入额外依赖 dll 的原理,可以参见:

方法

我们需要做的是,将一个对象序列化为 query 字符串。假设这个对象的局部变量名称是 query,于是我们需要:

  1. 取得此对象所有可获取值的属性
    • query.GetType().GetProperties()
  2. 获取此属性值的方法
    • property.GetValue(query, null)
  3. 将属性和值拼接起来
    • string.Join("&", properties)

然而真实场景可能比这个稍微复杂一点:

  1. 我们需要像 Newtonsoft.Json 一样,对于标记了 DataContract 的类,按照 DataMember 来序列化
  2. URL 中的值需要进行转义

所以,我写出了下面的方法:

1 2 3 4 5 6 7 8 9

var isContractedType = query.GetType().IsDefined(typeof(DataContractAttribute)); var properties = from property in query.GetType().GetProperties() where property.CanRead && (isContractedType ? property.IsDefined(typeof(DataMemberAttribute)) : true) let memberName = isContractedType ? property.GetCustomAttribute<DataMemberAttribute>().Name : property.Name let value = property.GetValue(query, null) where value != null && !string.IsNullOrWhiteSpace(value.ToString()) select memberName + "=" + HttpUtility.UrlEncode(value.ToString()); var queryString = string.Join("&", properties); return string.IsNullOrWhiteSpace(queryString) ? "" : prefix + queryString;

完整的代码如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.Serialization; using System.Web; namespace Walterlv.Web.Core { internal class QueryString { return: NotNullIfNotNull("query") public static string? Serialize(object? query, string? prefix = "?") { if (query is null) { return null; } var isContractedType = query.GetType().IsDefined(typeof(DataContractAttribute)); var properties = from property in query.GetType().GetProperties() where property.CanRead && (isContractedType ? property.IsDefined(typeof(DataMemberAttribute)) : true) let memberName = isContractedType ? property.GetCustomAttribute<DataMemberAttribute>().Name : property.Name let value = property.GetValue(query, null) where value != null && !string.IsNullOrWhiteSpace(value.ToString()) select memberName + "=" + HttpUtility.UrlEncode(value.ToString()); var queryString = string.Join("&", properties); return string.IsNullOrWhiteSpace(queryString) ? "" : prefix + queryString; } } }

你可能会遇到 [return: NotNullIfNotNull("query")] 这一行编译不通过的情况,这个是 C# 8.0 带的可空引用类型所需要的契约类。

你可以将它删除,或者安装我的另一个 NuGet 包来获得更多可空引用类型契约的支持,详见:

本文会经常更新,请阅读原文: https://blog.walterlv.com/post/serialize-object-to-http-get-query-string.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected])

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-12-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • HTTP GET 请求
  • 库?
  • 方法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档