c# - PropertyInfo getProperty() 方法的问题
问题描述
request.Data
{
"jurisdictionCode": "California",
"claimId": 123654,
"claimGroupID": 12,
"claimXref": "32145",
"serviceXref": "Test",
"claimStart": "2021-07-30T13:20:15.338Z",
"claimEnd": "2021-07-30T13:20:15.338Z",
"status": 5,
"creationTimestamp": "2021-07-30T13:20:15.338Z",
"touchTimestamp": "2021-07-30T13:20:15.338Z",
"filingSource": 7,
"userName": "test",
"exportTs": "2021-07-30T13:20:15.338Z",
"payerXref": "test",
"dtbatchExportTs": "2021-07-30T13:20:15.338Z"
}
public class scaffolded_model
{
[Key]
[StringLength(10)]
public string JurisdictionCode { get; set; }
[Key]
public long ClaimID { get; set; }
public long ClaimGroupID { get; set; }
[Required]
[StringLength(64)]
public string ClaimXRef { get; set; }
[Required]
[StringLength(64)]
public string ServiceXRef { get; set; }
[Column(TypeName = "datetime")]
public DateTime ClaimStart { get; set; }
[Column(TypeName = "datetime")]
public DateTime ClaimEnd { get; set; }
public int Status { get; set; }
[Column(TypeName = "datetime")]
public DateTime CreationTimestamp { get; set; }
[Column(TypeName = "datetime")]
public DateTime TouchTimestamp { get; set; }
public int FilingSource { get; set; }
[Required]
[StringLength(256)]
public string UserName { get; set; }
[Key]
[Column(TypeName = "datetime")]
public DateTime ExportTS { get; set; }
[Required]
[StringLength(64)]
public string PayerXRef { get; set; }
[Column(TypeName = "datetime")]
public DateTime DTBatchExportTS { get; set; }
}
代码:
var data = JsonSerializer.Serialize(request.Data);
Dictionary<string, JsonElement> result = (Dictionary<string, JsonElement>)JsonSerializer.Deserialize(data, typeof(Dictionary<string, JsonElement>));
foreach (var item in result)
{
PropertyInfo pi = scaffolded_model
.GetType()
.GetProperty(item.Key, BindingFlags.Instance | BindingFlags.Public);
if (pi == null)
{
_logger.LogInformation("Bad Field");
continue;
}
pi.SetValue(scaffolded_model, item.Value);
}
我一直在使用 GetProperty() 方法来匹配和填充来自作为 request.Data 的 json 请求和一个名为 scaffolded_model 的空模型的值。据我所知,两组数据都设置正确。代码应该遍历请求中的每个值,在空模型中通过 item.key 对其进行匹配,并使用该值填充匹配的键。item.key 每次都是空的。我尝试了不同的绑定等。如果我将第一个 item.key 硬编码为 JurisdictionCode,它会获取该值并正确填充它。所以一切正常,如果 item.key 会填充。
感谢您寻找并提供所有帮助。
[ApiVersion("1.0")]
[HttpPost("v{version:apiVersion}/Submitclaim")]
[Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public Task<IActionResult> Submitclaim(ClaimModel request)
{
var source = MethodBase.GetCurrentMethod().Name;
IActionResult actionResult = null;
using (LogContext.PushProperty("jx", request.JurisdictionCode))
{
try
{
//var claim_data = JsonSerializer.Serialize(request);
//Dictionary<string, JsonElement> result = (Dictionary<string, JsonElement>)JsonSerializer.Deserialize(claim_data, typeof(Dictionary<string, JsonElement>));
API.CRUD.Claims.Model.Claim scaffolded_model = new API.CRUD.Claims.Model.Claim();
JsonSerializer.Deserialize<scaffolded_model>(request);
//foreach (var item in result)
//{
// PropertyInfo pi = scaffolded_model
// .GetType()
// .GetProperty(
// item.Key,
// BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
// if (pi == null)
// {
// _logger.LogInformation("Bad Field");
// continue;
// }
// pi.SetValue(
// scaffolded_model,
// Convert.ChangeType(item.Value.ToString(), pi.PropertyType));
//}
}
catch (Exception ex)
{
_logger.LogError($"Exception failed: {ex.Message}");
actionResult = Problem("Exception failed");
}
}
return Task.FromResult(actionResult);
}
解决方案
如果您有充分的理由通过反射实现自定义 JSON 解析,而不是使用标准 System.Text.Json 或 Newtonsoft.Json 库,那么有几个问题需要解决:
- Type.GetProperty 区分大小写。默认情况下,它不会将
jurisdictionCode
属性名称与JurisdictionCode
属性匹配。该BindingFlags.IgnoreCase
标志应该解决这个问题。
PropertyInfo pi = scaffolded_model
.GetType()
.GetProperty(
item.Key,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
- 第二个问题与类型转换有关。
PropertyInfo.SetValue
不执行任何类型转换。需要设置的值必须与属性类型匹配,否则TargetException
会被抛出。此时问题中的代码始终将item.Value.ToString()
方法返回的字符串值设置为所有属性。它不适用于long
或DateTime
属性。要解决此问题,该Convert.ChangeType
方法可用作处理类中定义的属性类型的最简单选项scaffolded_model
。
pi.SetValue(
scaffolded_model,
Convert.ChangeType(item.Value.ToString(), pi.PropertyType));
通过这两个更改,可以解析 Json 表单示例。
但是当前的代码有一些限制:
它不处理空值。在字符串属性的情况下,空字符串值将被分配给属性,而不是原始的空值。根本不支持可空值类型(例如 long?)。要解决此问题,可以调整当前逻辑以检查
JsonElement.ValueKind
属性的JsonValueKind.Null
值。另一个问题是
DateTime
类型。在当前实现中,所有DateTime
值都将调整为本地时区,并且Convert.ChangeType
方法不提供任何控制它的能力。替换DateTime
时间DateTimeOffset
将不起作用,因为Convert.ChangeType
方法不支持它。只能选择检查属性类型并使用例如DateTime.Parse
方法而不是Convert.ChangeType
.
这个列表可以继续。所以在一般情况下,最好使用标准库来解析 Json。
推荐阅读
- datetime - 为日期时间字段设置默认时间 odoo 11
- java - 初始化并填充 Maps Maps
- wordpress - 使用 WordPress add_rewrite_rule() 更改帖子 URL
- php - 在windows中哪里可以找到vs代码目录/var/www/html/
- html - 根据类数更改css
- unity3d - 使用刚体速度进行 Unity 2D 跳跃感觉不好
- security - 保护从公共计算机到服务器的用户 ID 传输
- youtube-api - Youtube V3 API 搜索有时不返回或返回不同的结果
- php - PHP 总是只在从 HTML 表中获取时获取最后的结果
- css - 闪烁文本 N 次