asp.net-core-5.0

Warning CS0618: 'ComplexTypeModelBinder' is obsolete


In .NET Core 3 I extended ComplexTypeModelBinder class to create custom model binder for a specific class.

Main target was to override creation of model instance via CreateModel method.

public MyModelBinder: ComplexTypeModelBinder
{
    // Constructor here...
    
    protected override object CreateModel(ModelBindingContext bindingContext)
    {
        // Create model instance based on custom condition.
    }

}

After an upgrade to .NET 5, I'm receiving a compilation warning to replace ComplexTypeModelBinder with ComplexObjectModelBinder:

warning CS0618: 'ComplexTypeModelBinder' is obsolete: 'This type is obsolete and will be removed in a future version. Use ComplexObjectModelBinder instead.'

The problem is that ComplexObjectModelBinder is sealed class and CreateModel method is internal, so subclass approach cannot work any more.


Solution

  • The solution I settled for is to create class MyModelBinder which implement IModelBinder interface and acts as a wrapper around ComplexObjectModelBinder. ComplexObjectModelBinder is passed in MyModelBinder as constructor parameter.

    Same approach is used for MyModelBinderProvider and ComplexObjectModelProvider.

    Later, instead of overriding CreateMethod of ComplexObjectModelBinder, which is not possible in .NET 5, just assign bindingContext.Model in the wrapper method BindAsyncModel of MyModelBinder, before passing the bindingContext to ComplexObjectModelBinder's BindAsyncModel. This will make ComplexObjectModelBinder use model that is passed in, instead of creating default new instance.

    public class MyModelBinder: IModelBinder
    {
        private readonly ComplexObjectModelBinder _binder;
        public MyModelBinder(ComplexObjectModelBinder binder)
        {
            _binder = binder;
        }
    
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            MyModel myModel = // custom instantiation logic here
            bindingContext.Model = myModel;
            return _binder.BindModelAsync(bindingContext);
        }
    }
    

    For the registration of the custom model binder provider, first we find existing, automatically registered ComplexObjectBinderProvider, use it in costructor of MyModelBinderProvider and then insert MyModelBinderProvider in front of ComplexObjectBinderProvider.

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews(options => {
            // more configurations here...
    
            var bindingProvider = options.ModelBinderProviders.First(provider =>
                provider is ComplexObjectModelBinderProvider) as ComplexObjectModelBinderProvider;
    
            var indexOf = options.ModelBinderProviders.IndexOf(bindingProvider);
    
            options.ModelBinderProviders.Insert(indexOf, new MyModelBinderProvider(bindingProvider));
        }
    }