首页 > 解决方案 > 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);

    }

标签: c#apipropertiesmappingpropertyinfo

解决方案


如果您有充分的理由通过反射实现自定义 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()方法返回的字符串值设置为所有属性。它不适用于longDateTime属性。要解决此问题,该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。


推荐阅读