StringLengthAttribute does not enforce length

27 Views Asked by At

I have a property with StringLength attribute, but I can assign a string of any length to this property. I created the following test program in VB.NET 4.7 Framework:

Imports System.ComponentModel.DataAnnotations

Module Module1

    Class C1
        <StringLength(3)>
        Public Property BufferId As String
    End Class
    Sub Main()
        Dim c1 = New C1
        c1.BufferId = "abcd"
        Console.WriteLine($"c1.BufferId={c1.BufferId}")
        Console.ReadKey()
    End Sub

End Module

Although StringLength=3, I am able to assign a string of length 4.

How can I make the StringLength attribute to throw an exception, when I assign a string of length longer than the specified length?

2

There are 2 best solutions below

2
Marc Gravell On

Attributes are (with a few exceptions for compiler-interpreted attributes) passive annotations; they don't do anything unless some code (usually a library such as an ORM or UI toolkit, or a Roslyn analyzer) looks for them, and makes some decisions based on their existence.

If you want to validate things: a property setter can help. I can't remember much VB, but in C# terms:

private string foo;
public string Foo
{
    get => foo;
    set
    {
        ArgumentNullException.ThrowIfNull(value);
        if (value.Length > 4) throw new ArgumentOutOfRangeException(nameof(Foo));
        foo = value;
    }
}

You can of course write your own utility methods to simplify this, allowing things like

private string foo;
public string Foo
{
    get => foo;
    set => foo = value.AssertLengthAtMost(4);
}
...
internal static class ValidationExtensions
{
    public static string AssertLengthAtMost(this string value, int maxLength,
        [CallerArgumentExpression("value")] string? paramName = null)
    {
        ArgumentNullException.ThrowIfNull(value);
        if (value.Length > maxLength)
        {
            throw new ArgumentOutOfRangeException(paramName ?? nameof(value),
                "Max length exceeded");
        }
        return value;
    }
}
0
Alex On

It is possible to validate the object with:

Validator.ValidateObject(c1, New ValidationContext(c1), True)

Therefore, the program

Imports System.ComponentModel.DataAnnotations

Module Module1

    Class C1
        <StringLength(3)>
        Public Property BufferId As String
    End Class
    Sub Main()
        Try
            Dim c1 = New C1
            c1.BufferId = "abcd"
            Console.WriteLine($"c1.BufferId={c1.BufferId}")
            Validator.ValidateObject(c1, New ValidationContext(c1), True)
        Catch ex As Exception
            Console.WriteLine(ex)
        End Try
        Console.ReadKey()
    End Sub

End Module

produces the following output:

c1.BufferId=abcd
System.ComponentModel.DataAnnotations.ValidationException: The field BufferId must be a string with a maximum length of 3.
   at System.ComponentModel.DataAnnotations.Validator.ValidationError.ThrowValidationException()
   at System.ComponentModel.DataAnnotations.Validator.ValidateObject(Object instance, ValidationContext validationContext, Boolean validateAllProperties)
   at ConsoleApp1.Module1.Main() in c:\temp\ConsoleApp1\ConsoleApp1\Module1.vb:line 14