System.Text.Json.JsonReaderException 未在命名空间中找到

System.Text.Json.JsonReaderException isn't found in namespace

我正在将 .NET Framework 4.5 项目转换为 .NET Core 3.1。我的测试过去常常使用 Newtonsoft.Json 来检查 json 是否有效,现在我想用内置的 System.Text.Json 来实现同样的功能。看来

JsonElement values = JsonDocument.Parse(json).RootElement;

抛出 System.Text.Json.JsonReaderException,但我无法捕获它,因为指向此异常会导致错误

The type or namespace name 'JsonReaderException' does not exist in the namespace 'System.Text.Json' (are you missing an assembly reference?)

我只是想了解如何抛出实际上似乎不存在的东西。

更新 #1: 堆栈跟踪:

   at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
   at System.Text.Json.Utf8JsonReader.ReadSingleSegment()
   at System.Text.Json.Utf8JsonReader.Read()
   at System.Text.Json.JsonDocument.Parse(ReadOnlySpan`1 utf8JsonSpan, Utf8JsonReader reader, MetadataDb& database, StackRowStack& stack)
   at System.Text.Json.JsonDocument.Parse(ReadOnlyMemory`1 utf8Json, JsonReaderOptions readerOptions, Byte[] extraRentedBytes)
   at System.Text.Json.JsonDocument.Parse(ReadOnlyMemory`1 json, JsonDocumentOptions options)
   at System.Text.Json.JsonDocument.Parse(String json, JsonDocumentOptions options)
   at Anonymized..ctor(String json) in Anonymized.cs:line 182
   at Anonymized.<>c__DisplayClass12_0.<TestCreateLogEntryFromJson_IllegalValues>b__0() in Anonymized.cs:line 206
   at NUnit.Framework.Assert.Throws(IResolveConstraint expression, TestDelegate code, String message, Object[] args)

更新 #2: 我去看看是否会有一些我遗漏的 nugets。我发现 System.Text.Json 作为一个 nuget(虽然它已经可以访问,但我在测试文件中成功使用了 System.Text.JsonSerializer)。我添加了它,现在我遇到了实际问题:由于其保护级别,它无法访问。

using System.Text.Json;

namespace System.Text.Json
{
    internal sealed class JsonReaderException : JsonException
    {
        public JsonReaderException(string message, long lineNumber, long bytePositionInLine);
    }
}

但这并没有直接解决,我如何在 Assert.Throws<System.Text.Json.JsonReaderException>?

中捕捉到这个

您可以将 Newtonsoft.Json.dll 添加到您的项目引用中将解决您的问题。

事实 System.Text.Json.JsonReaderException is currently internal indicates that Microsoft may modify or remove this type at any time, and users of System.Text.Json should not depend on the continued existence of this class as a subclass of the public JsonException. Indeed, the documentation for Utf8JsonReader 仅说明

When Utf8JsonReader encounters invalid JSON, it throws a JsonException with basic error information like line number and byte position on the line.

以及 JsonReaderException 状态的代码注释:

// This class exists because the serializer needs to catch reader-originated exceptions in order to throw JsonException which has Path information.

而不是,使用Is.InstanceOf<JsonException>()

断言抛出的异常是JsonException
Assert.Throws(Is.InstanceOf<JsonException>(), () => JsonDocument.Parse(json).Dispose());

如果出于某种原因您必须断言抛出的特定异常类型,您可以利用Assert.Throws()这一事实来检查异常的完整类型名称returns 抛出的异常:

Assert.AreEqual("System.Text.Json.JsonReaderException",
                Assert.Throws(Is.InstanceOf<JsonException>(), () => JsonDocument.Parse(json).Dispose()).GetType().FullName);

或者您可以使用 NUnit 的 custom constraint mechanism 并引入一个 FullTypeNameConstraint,如下所示:

using NUnit.Framework;
using NUnit.Framework.Constraints;

public class FullTypeNameConstraint : Constraint
{
    readonly string expectedFullTypeName;

    public FullTypeNameConstraint(string expectedFullTypeName) : base(expectedFullTypeName) => this.expectedFullTypeName = expectedFullTypeName;

    public override string DisplayName => "FullTypeNameOf";

    public override ConstraintResult ApplyTo<TActual>(TActual actual)
    {
        var actualTypeName = actual?.GetType().FullName;
        return new ConstraintResult(this, actualTypeName, actualTypeName == expectedFullTypeName);
    }
}

public class Is : NUnit.Framework.Is
{
    public static FullTypeNameConstraint FullTypeNameOf(string expectedFullTypeName) => new FullTypeNameConstraint(expectedFullTypeName);
}   

public static class CustomConstraintExtensions
{
    public static FullTypeNameConstraint FullTypeNameOf(this ConstraintExpression expression, string expectedFullTypeName)
    {
        var constraint = new FullTypeNameConstraint(expectedFullTypeName);
        expression.Append(constraint);
        return constraint;
    }
}    

然后你将能够做到:

Assert.Throws(Is.FullTypeNameOf("System.Text.Json.JsonReaderException"), () => JsonDocument.Parse(json).Dispose());

但老实说我不推荐它。

顺便说一句,JsonDocument 是一次性的,实际上需要进行处理以释放池内存以供重用。

演示 fiddle 此处:https://dotnetfiddle.net/0dLxeO.

对于 xUnit 可以使用 Assert.ThrowsAny<JsonException>(action)