这是 JSON.NET 或实体框架中的错误,还是我在尝试使用 JSON.NET 序列化异常列表时做错了什么?

2023-12-11

尝试序列化一组错误时出现此错误:

“ISerialized 类型‘System.Data.Entity.Infrastruct.DbUpdateConcurrencyException’没有有效的构造函数。要正确实现 ISerialized,应存在采用 SerializationInfo 和 StreamingContext 参数的构造函数。”

构造函数实际上存在于基类中,但它是一个protected member.

有人要求查看 JSON:

{
    "$type": "System.Data.Entity.Infrastructure.DbUpdateConcurrencyException, EntityFramework",
    "ClassName": "System.Data.Entity.Infrastructure.DbUpdateConcurrencyException",
    "Message": "Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.",
    "Data": {
        "$type": "System.Collections.ListDictionaryInternal, mscorlib"
    },
    "InnerException": {
        "$type": "System.Data.Entity.Core.OptimisticConcurrencyException, EntityFramework",
        "ClassName": "System.Data.Entity.Core.OptimisticConcurrencyException",
        "Message": "Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.",
        "Data": {
            "$type": "System.Collections.ListDictionaryInternal, mscorlib"
        },
        "InnerException": null,
        "HelpURL": null,
        "StackTraceString": "   at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.ValidateRowsAffected(Int64 rowsAffected, UpdateCommand source)\r\n   at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()\r\n   at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.<Update>b__2(UpdateTranslator ut)\r\n   at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update[T](T noChangesResult, Func`2 updateFunction)\r\n   at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update()\r\n   at System.Data.Entity.Core.Objects.ObjectContext.<SaveChangesToStore>b__35()\r\n   at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)\r\n   at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)\r\n   at System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClass2a.<SaveChangesInternal>b__27()\r\n   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)\r\n   at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction)\r\n   at System.Data.Entity.Core.Objects.ObjectContext.SaveChanges(SaveOptions options)\r\n   at System.Data.Entity.Internal.InternalContext.SaveChanges()",
        "RemoteStackTraceString": null,
        "RemoteStackIndex": 0,
        "ExceptionMethod": "8\nValidateRowsAffected\nEntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\nSystem.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator\nVoid ValidateRowsAffected(Int64, System.Data.Entity.Core.Mapping.Update.Internal.UpdateCommand)",
        "HResult": -2146233087,
        "Source": "EntityFramework",
        "WatsonBuckets": null
    },
    "HelpURL": null,
    "StackTraceString": "   at System.Data.Entity.Internal.InternalContext.SaveChanges()\r\n   at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()\r\n   at System.Data.Entity.DbContext.SaveChanges()\r\n   at REDACTED FOR DISPLAY ON STACKOVERFLOW",
    "RemoteStackTraceString": null,
    "RemoteStackIndex": 0,
    "ExceptionMethod": "8\nSaveChanges\nEntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\nSystem.Data.Entity.Internal.InternalContext\nInt32 SaveChanges()",
    "HResult": -2146233087,
    "Source": "EntityFramework",
    "WatsonBuckets": null,
    "SafeSerializationManager": {
        "$type": "System.Runtime.Serialization.SafeSerializationManager, mscorlib",
        "m_serializedStates": {
            "$type": "System.Collections.Generic.List`1[[System.Object, mscorlib]], mscorlib",
            "$values": [
                {
                    "$type": "System.Data.Entity.Infrastructure.DbUpdateException+DbUpdateExceptionState, EntityFramework",
                    "InvolvesIndependentAssociations": false
                }
            ]
        }
    },
    "CLR_SafeSerializationManager_RealType": "System.Data.Entity.Infrastructure.DbUpdateConcurrencyException, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
}

下面是抛出异常的示例代码:

var serializationSettings = new JsonSerializerSettings() {
    DateFormatHandling = DateFormatHandling.IsoDateFormat,
    DateParseHandling = DateParseHandling.DateTime,
    DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind,
    DefaultValueHandling = DefaultValueHandling.Include,
    TypeNameHandling = TypeNameHandling.All,
    TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,
    ObjectCreationHandling = ObjectCreationHandling.Replace, //Necessary for subclassing list types
    ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
};

var json = JsonConvert.SerializeObject( new System.Data.Entity.Infrastructure.DbUpdateConcurrencyException( "hi" ), serializationSettings );
if (json == null)
    return null;
var err = JsonConvert.DeserializeObject<System.Data.Entity.Infrastructure.DbUpdateConcurrencyException>( json, serializationSettings ); //throws error

这变得更加奇怪,因为正如一个答案指出的那样,这是一个特殊的类,因为它不直接实现具有预期签名的构造函数。相反,反编译该类显示了某种不实现预期构造函数的、非常字面的“理由”......

/// <summary>
/// Exception thrown by <see cref="T:System.Data.Entity.DbContext" /> when the saving of changes to the database fails.
/// Note that state entries referenced by this exception are not serialized due to security and accesses to the
/// state entries after serialization will return null.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors",
    Justification = "SerializeObjectState used instead")]
[Serializable]
public class DbUpdateException : DataException
{
    /// <summary>
    /// Holds exception state that will be serialized when the exception is serialized.
    /// </summary>
    [Serializable]
    private struct DbUpdateExceptionState : ISafeSerializationData
    {

根据 Json.net文档,

可序列化

实现 ISerialized 的类型被序列化为 JSON 对象。序列化时,仅使用从 ISerialized.GetObjectData 返回的值;该类型的成员将被忽略。反序列化时,将调用具有 SerializationInfo 和 StreamingContext 的构造函数,并传递 JSON 对象的值。

在不需要此行为的情况下,可以将 JsonObjectAttribute 放置在实现 ISerialized 的 .NET 类型上,以强制将其序列化为普通 JSON 对象。

既然你不欠DbUpdateConcurrencyException类,解决方法可能是创建一个派生自的自定义异常类DbUpdateConcurrencyException并用属性标记它JsonObject.

    [JsonObject]
    class CustomException : DbUpdateConcurrencyException
    {
        public CustomException(string message) : base(message) { }
    }

     // Serialize the new customException
     var json = JsonConvert.SerializeObject(
         new CustomException("hi"), serializationSettings);

     //shall not throw error now
     DbUpdateConcurrencyException err = 
          JsonConvert.DeserializeObject<DbUpdateConcurrencyException>(json, serializationSettings); 

这只是一个 POC,我试图让它适用于 JSON.Net。为所有继承的类型创建自定义类是没有意义的ISerializable并且没有必需的构造函数。也许你可以尝试创建 Castle 核心DynamicProxy生成器来包装抛出的异常,其中ISerializable并将它们标记为JsonObject在序列化它们之前即时属性。

你是对的。 Json.net 无法找到受保护的构造函数,因为继承就像

DbUpdateConcurrencyException <- DbUpdateException <- DataException 

And 数据异常类具有 json.net 正在寻找的 Protected 构造函数。 .Net框架中的每个异常类都派生自SystemException将此构造函数作为受保护的构造函数,但是DbUpdateException&&DbUpdateConcurrencyException没有它。所以你现在可以猜到该怪谁了(IMO EF)。

以下是我发现的类,它们缺少标准可序列化构造函数,并且在反序列化期间会抛出异常。

  • EntitySqlException
  • 属性约束异常
  • DbUpdateConcurrencyException
  • 数据库更新异常
  • 工具异常
  • 数据库实体验证异常
  • 命令行异常

我把这个问题写给EF团队在这里.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

这是 JSON.NET 或实体框架中的错误,还是我在尝试使用 JSON.NET 序列化异常列表时做错了什么? 的相关文章

随机推荐