Sonarcube does not like my implementation of serializable exception class
Asked Answered
U

2

20

SonarCube shows me error "Update this implementation of 'ISerializable' to conform to the recommended serialization pattern" for the following exception implementation:

[Serializable]
public class UnrecoverableException : Exception, ISerializable
{
    public bool Ignore { get; }

    public UnrecoverableException()
    {
    }

    public UnrecoverableException(string message, Exception innerException)
        : base(message, innerException)
    {
    }

    protected UnrecoverableException(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
        Ignore= info.GetBoolean(nameof(Ignore));
    }

    public UnrecoverableException(string message, bool ignore= false) : base(message)
    {
        Ignore= ignore;
    }

    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue(nameof(Ignore), Ignore);
        base.GetObjectData(info, context);
    }
}

not sure what's wrong here as to me it seems totally following rules described here https://rules.sonarsource.com/csharp/tag/pitfall/RSPEC-3925

This rules raises an issue on types that implement ISerializable without following the serialization pattern recommended by Microsoft.

  • The System.SerializableAttribute attribute is missing.

  • Non-serializable fields are not marked with the System.NonSerializedAttribute attribute.

  • There is no serialization constructor.

  • An unsealed type has a serialization constructor that is not protected.

  • A sealed type has a serialization constructor that is not private.

  • An unsealed type has a ISerializable.GetObjectData that is not both public and virtual.

  • A derived type has a serialization constructor that does not call the base constructor.

  • A derived type has a ISerializable.GetObjectData method that does not call the base method.

  • A derived type has serializable fields but the ISerializable.GetObjectData method is not overridden.

Utricle answered 20/2, 2020 at 2:13 Comment(6)
I think the problem might be with this "An unsealed type has a serialization constructor that is not protected" condition. However what if I need throw this type of exception directly and hove other exceptions derived from itUtricle
I think it doesn't like the backing field for the auto-property. I bet it isn't decorated with a serialization attribute. What happens if you remove the property, or change it to one with an explicit backing field decorated per the rules?Bosh
issue was with protected vs public member indeedUtricle
Cool, you figured it out? I'm interested in what the answer is.Bosh
I just made 2 separate exception classes derived from it instead of using 1 parent and 1 derived class, and made constructors protectedUtricle
You can answer your own question below, you know?Bosh
Z
64

All I had to do to pass Sonarqube's analysis was add the [Serializable] attribute to the class and add a protected constructor. i.e.:

[Serializable]
public class BadRequestException : Exception
{
    public BadRequestException(string message) : base(message)
    {

    }

    protected BadRequestException(SerializationInfo info, StreamingContext context) : base(info, context)
    {

    }
}
Zerlina answered 17/12, 2020 at 12:2 Comment(5)
Thank you! It helps. This answer should've more upvotes.Silicle
I get analysis warnings about non-nullable properties being uninitialized in the protected constructor. This only happens when I have nullable reference types enabled. Unfortunately, I won't have appropriate information to initialize these properties in this specific constructor. And I don't want to make them nullable because that changes the semantics of the class and affects calling code. How should I resolve?Whatsoever
You are fortunate. I ran into this today, and what worked for you no longer works. I have no idea what Sonarlint wants.Rochelle
Yes, but then how to add a unit test so that SonarQube doesn't give you a coverage error?Mosemoseley
Warning : SYSLIB0051: 'Exception.Exception(SerializationInfo, StreamingContext)' is obsolete: 'This API supports obsolete formatter-based serialization. It should not be called or extended by application code.'Impediment
U
0

From .Net documentation standpoint, for custom exception, all we need to do is derive from Exception class and they further recommend to add empty, message and message + inner exception constructors.

However, Sonar cloud raises warning S3925 for this implementation in .Net 8. Further investigation into this requires implementing a protected constructor and override of GetObjectData as seen below. Apparently, these are now marked obsolete in .Net 8.

Finally this worked for me:

[Serializable]
public class MyException : Exception
{
    public MyException() { }
    public MyException(string message) : base(message) { }
    public MyException(string message, Exception? innerException) : base(message, innerException) { }

    [Obsolete("", DiagnosticId = "SYSLIB0051")]
    protected MyException(SerializationInfo info, StreamingContext context) : base(info, context) { }

    [Obsolete("", DiagnosticId = "SYSLIB0051")]
    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
    }
}
Unsociable answered 5/1 at 11:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.