DEV Community

M.Usman Rafiq
M.Usman Rafiq

Posted on • Edited on

3 3

How To Bind Model Value FromBody by Custom Binder in Asp.net Core

I encountered a scenario a few days back where I was required to use a custom model binder to transform my received values in a FromBody JSON request. When I implemented the Model Binder It was working fine with FromQuery Attribute but was not working with FromBody, same issue as: https://github.com/aspnet/Mvc/issues/8110.

For in-depth learning, you can also follow my channel on YouTube @usmancode

So after spending some hours on this problem, I came to know that the FromBody attribute will be handled using **BodyModelBinder **class with Formatters and ReaderFactory.

public class MyModelBinder : IModelBinder
{
private BodyModelBinder defaultBinder;
public MyModelBinder(IList formatters, IHttpRequestStreamReaderFactory readerFactory)
{
defaultBinder = new BodyModelBinder(formatters, readerFactory);
}

  public async Task BindModelAsync(ModelBindingContext bindingContext)
  {
      // calling the default body binder
      await defaultBinder.BindModelAsync(bindingContext);
      if (bindingContext.Result.IsModelSet && bindingContext.Result.Model is ResetPasswordModel)
      {
          var inputModel = (ResetPasswordModel)bindingContext.Result.Model;

          // all of your property updates with be listed here
          //
          //
          //

          bindingContext.Result = ModelBindingResult.Success(inputModel);
      }
  }
Enter fullscreen mode Exit fullscreen mode

}
And for this model binder, we will required a model provider which will be like :

public class MyModelBinderProvider : IModelBinderProvider
{
private readonly IList _formatters;
private readonly IHttpRequestStreamReaderFactory _readerFactory;
private BodyModelBinderProvider _defaultProvider;

   public MyModelBinderProvider(IList<IInputFormatter> formatters, IHttpRequestStreamReaderFactory readerFactory)
   {
       _formatters = formatters;
       _readerFactory = readerFactory;
       _defaultProvider = new BodyModelBinderProvider(formatters, readerFactory);
   }

   public IModelBinder GetBinder(ModelBinderProviderContext context)
   {
       IModelBinder modelBinder = _defaultProvider.GetBinder(context);

       // default provider returns null when there is error.So for not null setting our binder
       if (modelBinder != null)
       {
           modelBinder = new ProtectedModelBinder(_formatters, _readerFactory);
       }
       return modelBinder;
   }
Enter fullscreen mode Exit fullscreen mode

}
And we need to register this provide in our startup class inside ConfigureServices method like :

services.AddMvc(config =>
{
var readerFactory = services.BuildServiceProvider().GetRequiredService();
config.ModelBinderProviders.Insert(0, new MyModelBinderProvider(config.InputFormatters, readerFactory));

}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
And at last annotate the model you want to customize the binding of which with a line as below:

[ModelBinder(BinderType = typeof(MyModelBinder))]
public class ResetPasswordModel : UserConfirmationModel
And now if you make a http post api call with content type application/json with your model properties in request body then your custom model binding will work.

You can fork our github repository for all useful and examples code : https://github.com/Usman-uzi/techintalk

For all my blog posts you can visit : https:www.techintalk.com

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay