簡體   English   中英

DTO的自定義屬性類型中的C#WebApi ModelBinding Validation

[英]C# WebApi ModelBinding Validation in custom property type of DTO

我在控制器中有一條路線,並轉移了一些模型。 此模型 (DTO) 包含自定義類型屬性(例如,密碼、郵政編碼……)。 我想添加一個像這里描述的模型綁定器( https://docs.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-6.0 )到屬性類型(密碼)。 !不是整個DTO!

生成的模型 (DTO) 定義應如下所示:

namespace UserService.Models.DTO
{
    public class UserRegisterDto
    {
        public string Firstname { get; set; }
        public string Lastname { get; set; }
        public string Email { get; set; }
        public Password Password { get; set; }
    }
}

現在傳輸 JSON(例如,見下文)時,應自動驗證 Password 屬性。

{
    "firstname": "John",
    "lastname": "Doe",
    "email": "johndoe@mail.com",
    "password": "Test12345!"
}

路由實現應如下所示:

namespace UserService.Controllers
{
    [ApiController]
    [Route("/api/user/")]
    public class AuthController : ControllerBase
    {
        [HttpPost("register")]
        public async Task<ActionResult> Register(UserRegisterDto request)
        {
            User? user = await this._userService.Register(request);

            if (user == null)
            {
                return BadRequest();
            }

            return Ok(user);
        }
    }
}

起初我以為我可以實現以下內容,但驗證根本不起作用......

namespace UserService.Models
{
    [ModelBinder(typeof(PasswordEntityBinder))]
    public class Password
    {
        private const string PasswordRegex = "(?=^.{8,}$)(?=.*\\d)(?=.*[!@#$%&?*\\\"§$\\/()=~]+)(?![.\\n])(?=.*[A-Z])(?=.*[a-z]).*$";

        #region Properties
        public string Value { get; set; }

        public override string ToString() => Value;

        public static implicit operator string(Password e) => e.Value;

        public static bool TryParse(ReadOnlySpan<char> s, out Password? result)
        {
            result = null;
            if (string.IsNullOrWhiteSpace(s.ToString()))
                return false;

            if (!Regex.IsMatch(s.ToString(), PasswordRegex))
                return false;

            result = new Password()
            {
                Value = s.ToString(),
            };

            return true;
        }
    }
}

有誰知道是否有可能實現對用作模型(DTO)中的屬性的類型的模型綁定?

由於我對使用某些 3rd 方庫不滿意,因此我正在進一步尋找我的問題。 我找到了一個合適的解決方案,它允許我使用自定義復雜類型,例如 int 同時進行驗證和轉換。 此解決方案適用於 asp.net net6.0。 我用:

  • System.Text.Json JSON 自定義轉換器
  • IValidatableObject

json 密碼首先使用 JSON 轉換器進行轉換,然后進行驗證。

下面顯示了示例,它可以應用於任何類型:

// Password.cs

namespace UserService.Models
{
    [JsonConverter(typeof(PasswordJsonConverter))]
    public class Password : IValidatableObject
    {
        private const string PasswordRegex = "(?=^.{8,}$)(?=.*\\d)(?=.*[!@#$%&?*\\\"§$\\/()=~]+)(?![.\\n])(?=.*[A-Z])(?=.*[a-z]).*$";

        public string Value { get; set; } = "";

        public override string ToString() => Value;
        public static implicit operator string(Password e) => e.Value;

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (string.IsNullOrWhiteSpace(this.Value))
            {
                yield return new ValidationResult("Password may not be empty");
                yield break;
            }

            if (!Regex.IsMatch(this.Value, PasswordRegex))
                yield return new ValidationResult("Password invalid formatted");

        }
    }
}
// PasswordJsonConverter.cs

namespace UserService.Converter
{
    public class PasswordJsonConverter : JsonConverter<Password>
    {
        public override bool CanConvert(Type typeToConvert)
        {
            return (typeToConvert == typeof(Password));
        }

        public override Password? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            Password pw = new Password();
            string? pw_string;

            try
            {
                pw_string = reader.GetString();
            }catch(InvalidOperationException)
            {
                return null;
            }

            if (pw_string == null)
                return null;

            pw.Value = pw_string;
            return pw;
        }

        public override void Write(Utf8JsonWriter writer, Password value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.ToString());
        }
    }
}

這使我可以像使用任何基本類型一樣在 DTO 中使用 Password 對象。 例如:

// RegisterDto.cs

namespace UserService.Models.DTO
{
    public class UserRegisterDto
    {
        public string Firstname { get; set; }
        public string Lastname { get; set; }
        public string Email { get; set; }
        public Password Password { get; set; }
    }
}

輸入 json 看起來像:

{
    "firstname": "John",
    "lastname": "Doe",
    "email": "johndoe@mail.com",
    "password": "Test12345!"
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM