Как правильно сериализовать исключения в. net 4.7. [X] + и. net Standard 2. [x] + - PullRequest
0 голосов
/ 20 февраля 2020

У меня есть несколько Exception производных типов, которые добавляют дополнительные свойства к Exception. Поиск в Интернете примеров и рекомендаций о том, как обрабатывать сериализацию таких Exception типов, привел к описаниям и образцам кода, которые были довольно старыми. Использование этих примеров всегда приводило к ошибкам безопасности. Чтобы это работало, мне пришлось дополнительно декорировать GetObjectData -Metod с атрибутом System.Security.SecurityCritical.

Интересно, что SecurityPermission -Атрибут, который содержался во всех примерах, но в различных пути, казалось, не нужны. Некоторые примеры только добавили его в GetObjectData, некоторые добавили также в конструктор десериализации. В некоторых примерах использовалось сильное действие SecurityAction.Demand, в большинстве примеров использовалось действие SecurityAction.LinkDemand, в других - SecurityAction.RequestMinimum.

Мой вопрос заключается в том, является ли правильный тип, полученный ниже Exception (для части сериализации), правильным для использования в настоящее время. net frameworks (4.7. [X] +, Core [x] ], Standard2. [X] +) или если чего-то не хватает, или я могу даже удалить некоторые детали? Обратите внимание, что я не хочу запечатывать тип. Другие Exception -типы должны иметь возможность наследования от него.

[Serializable]
public class FooException : Exception{

    readonly int m_fooValue;

    public FooException(string message,int fooValue,Exception innerException=null) : base(message,innerException){
        m_fooValue = fooValue;
    }
    [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)]
    protected FooException(SerializationInfo info, StreamingContext context) : base(info, context) {
        m_fooValue = info.GetInt32(nameof(FooValue));            
    }

    [SecurityCritical]
    [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)]
    public override void GetObjectData(SerializationInfo info, StreamingContext context) {
        if (info == null) throw new ArgumentNullException(nameof(info));
        info.AddValue(nameof(FooValue), m_fooValue);            
        base.GetObjectData(info, context);
    }

    public int FooValue => m_fooValue;
}

Производный тип (FooBarException) дополнительно должен также установить атрибут SecurityCritical в конструкторе deserializung для удовлетворения LinkDemand:

[Serializable] 
public class FooBarException : FooException{

    readonly int m_barValue;

    public FooBarException(string message,int fooValue, int barValue, Exception innerException = null) : base(message, fooValue, innerException) {
        m_barValue = barValue;
    }
    [SecurityCritical] // Additional for satisfying the LinkDemand on the base constructor
    [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)]
    protected FooBarException(SerializationInfo info, StreamingContext context) : base(info, context) {
        m_barValue = info.GetInt32(nameof(BarValue));
    }

    [SecurityCritical]
    [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)]
    public override void GetObjectData(SerializationInfo info, StreamingContext context) {
        if (info == null) throw new ArgumentNullException(nameof(info));
        info.AddValue(nameof(BarValue), m_barValue);
        base.GetObjectData(info, context);
    }

    public int BarValue => m_barValue;


}

Источники
{ ссылка }

https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.iserializable.getobjectdata?view=netframework-4.8

Как правильно создать заказ. NET Сериализуемое исключение?

https://blog.gurock.com/articles/creating-custom-exceptions-in-dotnet/

1 Ответ

1 голос
/ 20 февраля 2020

Пройдя немного глубже, я пришел к следующему шаблону:

[Serializable]
public class FooException : Exception{

    readonly int m_fooValue;

    public FooException(string message, int fooValue, Exception innerException = null) : base(message, innerException) {
        m_fooValue = fooValue;
    }

    [SecuritySafeCritical]
    protected FooException(SerializationInfo info, StreamingContext context) : base(info, context) {
        m_fooValue = info.GetInt32(nameof(FooValue));
    }

    [SecurityCritical]      
    public override void GetObjectData(SerializationInfo info, StreamingContext context) {
        if (info == null) throw new ArgumentNullException(nameof(info));
        info.AddValue(nameof(FooValue), m_fooValue);
        base.GetObjectData(info, context);
    }

    public int FooValue => m_fooValue;
}

[Serializable]
public class FooBarException : FooException
{

    readonly int m_barValue;

    public FooBarException(string message, int fooValue, int barValue, Exception innerException = null) : base(message, fooValue, innerException) {
        m_barValue = barValue;
    }
    [SecuritySafeCritical]        
    protected FooBarException(SerializationInfo info, StreamingContext context) : base(info, context) {
        m_barValue = info.GetInt32(nameof(BarValue));
    }

    [SecurityCritical]        
    public override void GetObjectData(SerializationInfo info, StreamingContext context) {
        if (info == null) throw new ArgumentNullException(nameof(info));
        info.AddValue(nameof(BarValue), m_barValue);
        base.GetObjectData(info, context);
    }

    public int BarValue => m_barValue;


}

Для SecurityAction.LinkDemand части Вопроса это значение больше не должно использоваться (. net 4+ ). Либо следует использовать SecurityAction.Demand, либо даже всю декларацию SecurityPermission можно заменить на SecurityCritical (в зависимости от случая, например, для вышеуказанного случая).

...