CustomModelBinder on properties of a Dto class

151 Views Asked by At

I have a DtoClass which has properties of a specific class, I don't want to have a CustomModelBinder for the DtoClass but for the class of its properties; I am using asp.net core 3.1.

My ModelBinder Class is:

public class SessionIdModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        Guard.Against.Null(bindingContext, nameof(bindingContext));

        var modelName = bindingContext.ModelName;
        var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);

        if (valueProviderResult == ValueProviderResult.None)
            return Task.CompletedTask;

        var sessionId = SessionId.Parse(valueProviderResult.FirstValue);
        if (sessionId.IsFailure)
        {
            bindingContext.ModelState.AddModelError(modelName, sessionId.Errors.First().Message);
            bindingContext.Result = ModelBindingResult.Failed();
            return Task.CompletedTask;
        }

        bindingContext.Result = ModelBindingResult.Success(sessionId.Data);
        return Task.CompletedTask;
    }
}

The Dto class is like:

public class MergeSessionsDto
{
    [ModelBinder(BinderType = typeof(SessionIdModelBinder), Name = nameof(OldSession))]
    public SessionId OldSession { get; set; }
        
    [ModelBinder(BinderType = typeof(SessionIdModelBinder), Name = nameof(NewSession))]
    // [BindProperty(BinderType = typeof(SessionIdModelBinder), Name = nameof(NewSession))]
    public SessionId NewSession { get; set; }
}

The action in my controller is:

public async Task<IActionResult> MergeSessions([FromBody] MergeSessionsDto dto)
{
    var result = DoTheMerge(dto.OldSession, dto.NewSession);
    return result;
}

in the startup class I also registered the ModelBinderProvider :

services.AddControllers(options=> options.ModelBinderProviders.Insert(0, new MyCustomModelBinderProvider()))

which is like:

public sealed class MyCustomModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        Guard.Against.Null(context, nameof(context));

        if (context.Metadata.ModelType == typeof(SessionId))
            return new BinderTypeModelBinder(typeof(SessionIdModelBinder));

        return null;
    }
}

No matter which approach I am using, either [ModelBinder], [BindProperty] attributes, or global registration, SessionModelBinder is not called, and I am getting this error:

Exception: Invalid error serialization: 'The dto field is required.'
0

There are 0 best solutions below