问题
I'm creating a custom model binder for a view model, implementing IModelBinder
I have a lot of properties in my view model, the majority of which do not need any custom binding. Rather than explicitly set all of the property values on my model individually from the ModelBindingContext
, I would to be able to get the framework to bind the model for me, then I would carry out any custom binding:
public class ApplicationViewModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
// get .net core to bind values on model
// Cary out any customization of the models properties
bindingContext.Result = ModelBindingResult.Success(bindingContext.Model);
return Task.CompletedTask;
}
}
Basically I want to carry out the default model binding, then apply custom binding, similar to the approach taken in this SO post but for .NET Core, not framework.
I assumed applying the default binding would be straight forward, but haven't been able to find out how to do so. I believe the solution would involve ComplexTypeModelBinder
and ComplexTypeModelBinderProvider
classes, but can't seem to find out how to go about it.
I know I could just make any changes when the POST request hits my controller method, but this seem the wrong place and wrong time to do so.
回答1:
For custom ComplexTypeModelBinder
, you could inherit from ComplexTypeModelBinder
.
Model
public class BinderModel { public int Id { get; set; } public string Name { get; set; } public string BinderValue { get; set; } }
Controller Action
[HttpPost] public void Post([FromForm]BinderModel value) { }
CustomBinder
public class CustomBinder : ComplexTypeModelBinder { private readonly IDictionary<ModelMetadata, IModelBinder> _propertyBinders; public CustomBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders) : base(propertyBinders) { _propertyBinders = propertyBinders; } protected override Task BindProperty(ModelBindingContext bindingContext) { if (bindingContext.FieldName == "BinderValue") { bindingContext.Result = ModelBindingResult.Success("BinderValueTest"); return Task.CompletedTask; } else { return base.BindProperty(bindingContext); } } protected override void SetProperty(ModelBindingContext bindingContext, string modelName, ModelMetadata propertyMetadata, ModelBindingResult result) { base.SetProperty(bindingContext, modelName, propertyMetadata, result); } }
CustomBinderProvider
public class CustomBinderProvider : IModelBinderProvider { public IModelBinder GetBinder(ModelBinderProviderContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (context.Metadata.IsComplexType && !context.Metadata.IsCollectionType) { var propertyBinders = new Dictionary<ModelMetadata, IModelBinder>(); for (var i = 0; i < context.Metadata.Properties.Count; i++) { var property = context.Metadata.Properties[i]; propertyBinders.Add(property, context.CreateBinder(property)); } //var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>(); //return new ComplexTypeModelBinder(propertyBinders, loggerFactory); return new CustomBinder(propertyBinders); } return null; } }
Inject provider
public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { options.ModelBinderProviders.Insert(0, new CustomBinderProvider()); }); }
来源:https://stackoverflow.com/questions/51921074/net-core-custom-and-default-binding-combined