【问题标题】:The JSON value could not be converted to System.Nullable`1[System.DateTime]JSON 值无法转换为 System.Nullable`1[System.DateTime]
【发布时间】:2020-10-05 00:18:20
【问题描述】:

在 Azure DevOps 发布管道中使用 Powershell,我正在尝试将参数转换为 json 格式,然后再发布到 asp netcore 端点。其中一个参数是日期时间。

我收到以下 DateTime 类型的错误:

"errors":{"$.CreatedDate":["The JSON value could not be converted to System.Nullable`1[System.DateTime].

这是 Powershell 脚本。变量$(RELEASE.DEPLOYMENT.STARTTIME)是DevOps变量,输出日期格式2020-06-15 10:00:46Z

$params = @{   
   Name = "Test"
    CreatedDate = $(RELEASE.DEPLOYMENT.STARTTIME) 
}

Invoke-WebRequest -Uri https://mynetcoreendpoint -Method POST -Body ($params | ConvertTo-Json) -ContentType "application/json" -UseBasicParsing

json 在端点侧进行评估。这是 NetCore 端点

[HttpPost]
public ActionResult<ReleaseDTO> CreateRelease(ReleaseDTO release)
 {
    // Do some stuff
 }

 // Where ReleaseDTO has the property 

 public DateTime? CreatedDate { get; set; }

【问题讨论】:

  • 你希望你的约会通过什么?作为你发布的字符串或整数(unix时间戳)或其他东西?
  • 但是错误不是由提供的代码抛出的,对吗?在评估收到的 JSON 时发生错误。你能发布评估代码吗?
  • @doorman 当$(RELEASE.DEPLOYMENT.STARTTIME) 被扩展时,它是否包括封闭引号?也许您需要自己提供这些报价。
  • @doorman 如果在 NetCore 代码中将 CreatedDate 替换为 DateTime.Parse(CreatedDate, System.Globalization.CultureInfo.InvariantCulture) 会发生什么?
  • doorman:如果扩展的宏值没有用引号括起来并且您自己没有提供它们,$params = ... 语句将中断[datetime] '2020-06-15 10:00:46Z' 之类的演员 确实 工作,所以也许你的价值有隐藏的字符? @Thomas 的隐含问题也值得探讨——隐式 JSON 反序列化层期望什么格式?我已取消删除我的答案,并添加了一些通用指针。

标签: json powershell azure-devops


【解决方案1】:

确保作为 to-JSON 转换基础的哈希表包含一个[datetime] 实例,而不仅仅是一个字符串

# !! This may work in PowerShell [Core, v6+] only, not in Windows PowerShell.
$params = @{   
  Name = "Test"
  # Note the cast to [datetime] and the need to enclose the
  # Azure macro in quotes.
  CreatedDate = [datetime] '$(RELEASE.DEPLOYMENT.STARTTIME)'
}

这样,时间戳的 JSON 表示应该在端点的基于 C# 的代码中正确反序列化 - 假设序列化代码和反序列化代码使用相同的基于字符串的约定来表示 [datetime] 实例[1]


如果您使用的是 Windows PowerShell(最高版本为 v5.1)并且 Web 服务端点使用 .NET Core / Json.NET,则约定为 mismatched,因此您需要根据 Web 服务端点的要求手动创建时间戳的字符串表示形式

$params = @{   
  Name = "Test"
  # Note the cast to [datetime] and the need to enclose the
  # Azure macro in quotes.
  CreatedDate = ([datetime] '$(RELEASE.DEPLOYMENT.STARTTIME)').ToString('o')
}

继续阅读以获得解释。


不幸的是,.NET 世界中关于时间戳在 JSON 中的表示方式存在不同的约定:

  • 在 PowerShell 端(使用 @{ dt = [datetime]::now } | ConvertTo-Json 验证):

    • Windows PowerShellConvertTo-Json 使用"\/Date(&lt;epochTimeMs&gt;)\/" 的约定,其中&lt;epochTimeMs&gt; 是以毫秒为单位的 Unix 纪元时间戳。

      • 示例:@{ dt = [datetime]::now } | ConvertTo-Json -Compress 产量
        {"dt":"\/Date(1592309341640)\/"}
    • PowerShell [Core, v6+],截至 7.0 版:ConvertTo-Json 在后台使用 Json.NET,它使用与 ISO 8601 兼容的标准往返日期/时间字符串格式模式( "o") 可以传递给[datetime] 实例的.ToString() 方法;例如,[datetime]::now.ToString('o') 产生类似:
      "2020-06-15T11:54:06.114098-04:00"

      • 示例:@{ dt = [datetime]::now } | ConvertTo-Json -Compress
        产量{"dt":"2020-06-16T08:07:50.356321-04:00"}
  • 在 C# (.NET) 方面:

    • 似乎至少在 ASP.NET 世界的某个时候使用了旧的 Windows PowerShell 约定。

    • Json.NET 以及新的 .NET-native System.Text.Json 类型使用 PowerShell [Core] 中也使用的新约定。


[1] 请注意,JSON standard 确实没有为日期/时间实例定义值类型,因此使用 string 表示时间戳的 JSON 值,作为 约定;或者,numeric 表示(例如刻度)也是一种选择,但只有字符串表示允许您推断预期的数据类型(在没有架构信息的情况下) .
因此,为了正确传递时间戳,JSON 序列化程序和 JSON 反序列化程序都必须遵守相同的约定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-12
    • 2017-05-05
    • 2020-05-09
    • 1970-01-01
    • 1970-01-01
    • 2019-05-19
    • 2015-04-19
    • 2015-07-09
    相关资源
    最近更新 更多