首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >自定义ModelBinding与Asp.net核心控制器的问题

自定义ModelBinding与Asp.net核心控制器的问题
EN

Stack Overflow用户
提问于 2022-08-02 23:01:47
回答 1查看 94关注 0票数 0

我遇到了一个问题的多福菲模型绑定。

我尝试了一种不同的ModelBinder,但没有成功。

有时,我会使用DefaultModelBuilder进行无限循环,如文档中所描述的。有时,我在BodyModelBinding中得到了不受支持的类型。

我分享我的代码。也许以前有人试过解决这个问题

代码语言:javascript
复制
public class CustomOptionTypeCreateDtoModelBinderProvider : IModelBinderProvider
{
    private readonly Collection<IInputFormatter> _formatters;
    private readonly IHttpRequestStreamReaderFactory _readerFactory;
    private BodyModelBinderProvider _defaultProvider;
    private ILoggerFactory loggerFactory;
    public CustomOptionTypeCreateDtoModelBinderProvider(Collection<IInputFormatter> optionsInputFormatters, 
        IHttpRequestStreamReaderFactory readerFactory, ILoggerFactory _loggerFactory)
    {
        _formatters = optionsInputFormatters;
        _readerFactory = readerFactory;
        _defaultProvider = new BodyModelBinderProvider(optionsInputFormatters, readerFactory);
        loggerFactory = _loggerFactory;
    }

    public IModelBinder? GetBinder(ModelBinderProviderContext context)
    {
        if (context.Metadata.ModelType != typeof(DemoOptionValueBaseDto))
        {
            return null;
        }

        var subclasses = new[] { typeof(DemoTextOptionValueCreateDto), typeof(DemoTextSwatchOptionValueCreateDto), };

        var binders = new Dictionary<Type, (ModelMetadata, IModelBinder)>();
        foreach (var type in subclasses)
        {
            var modelMetadata = context.MetadataProvider.GetMetadataForType(type);
            binders[type] = (modelMetadata, context.CreateBinder(modelMetadata));
        }
        return new CustomOptionTypeCreateDtoModelBinder(binders, _formatters, _readerFactory, _defaultProvider,loggerFactory);
    }
}

自定义ModelBinder

代码语言:javascript
复制
public class CustomOptionTypeCreateDtoModelBinder : IModelBinder
{
    private Dictionary<Type, (ModelMetadata, IModelBinder)> binders;
    private readonly IList<IInputFormatter> formatters;
    private readonly IHttpRequestStreamReaderFactory readerFactory;
    private BodyModelBinderProvider _defaultProvider;
    private ILoggerFactory loggerFactory;
    public CustomOptionTypeCreateDtoModelBinder(Dictionary<Type, (ModelMetadata, IModelBinder)> _binders,
        IList<IInputFormatter> inputFormatters,
        IHttpRequestStreamReaderFactory httpRequestStreamReaderFactory,
        BodyModelBinderProvider defaultProvider, ILoggerFactory _loggerFactory)
    {
        formatters = inputFormatters;
        readerFactory = httpRequestStreamReaderFactory;
        _defaultProvider = defaultProvider;
        binders = _binders;
        loggerFactory = _loggerFactory;
    }


    public async Task BindModelAsync(ModelBindingContext bindingContext)
    {
        bindingContext.BindingSource = BindingSource.Form;
        var modelKindName =
            ModelNames.CreatePropertyModelName(bindingContext.ModelName, nameof(OptionValueType));
        var modelTypeValue = bindingContext.ValueProvider.GetValue(modelKindName);

      
        IModelBinder modelBinder = default!;
        ModelMetadata modelMetadata = default!;
        if (Enum.TryParse(modelTypeValue.FirstValue, out OptionValueType type))
        {
            if (type == OptionValueType.TextSwatchOptionValue)
            {
                (modelMetadata, modelBinder) = binders[typeof(DemoTextSwatchOptionValueCreateDto)];
            }
        
            if (type == OptionValueType.TextOptionValue)
            {
                (modelMetadata, modelBinder) = binders[typeof(DemoTextOptionValueCreateDto)];
            }
        }
        else
        {
            bindingContext.Result = ModelBindingResult.Failed();
            return;
        }
        
        var newBindingContext = DefaultModelBindingContext.CreateBindingContext(
            bindingContext.ActionContext,
            bindingContext.ValueProvider,
            modelMetadata,
            bindingInfo: null,
            bindingContext.ModelName);

        await modelBinder.BindModelAsync(newBindingContext);
        bindingContext.Result = newBindingContext.Result;

        if (newBindingContext.Result.IsModelSet)
        {
            // Setting the ValidationState ensures properties on derived types are correctly 
            bindingContext.ValidationState[newBindingContext.Result] = new ValidationStateEntry
            {
                Metadata = modelMetadata,
            };
        }

    }

模型

代码语言:javascript
复制
public class DemoVariantOptionCreateDto : DemoOptionCreateDto
{

}

public abstract class DemoOptionCreateDto
{
    // [ModelBinder(typeof(CustomOptionTypeCreateDtoModelBinder))]
    public IEnumerable<DemoOptionValueBaseDto>? Values { get; set; } = default!;
}

public abstract class DemoOptionValueBaseDto 
{
    public bool IsDefault { get; set; } = false;
    public abstract OptionValueType OptionValueType { get; set; }
}

public class DemoTextOptionValueCreateDto : DemoOptionValueBaseDto
{
    public string Value { get;  set; } = default!;

    public override OptionValueType OptionValueType { get; set; }= OptionValueType.TextOptionValue;
}

public class DemoTextSwatchOptionValueCreateDto : DemoOptionValueBaseDto
{
    public string ColorName { get;   set; } = default!;
    public override OptionValueType OptionValueType { get; set; }  = OptionValueType.TextSwatchOptionValue;
}

在控制器内部

代码语言:javascript
复制
public async Task<IActionResult> AddSharedVariantOption(
        [FromForm, SwaggerParameter("variant options are required", Required = true)]
        DemoVariantOptionCreateDto dto)
    {
        return Ok();          
    }

服务

代码语言:javascript
复制
services.AddControllers(options =>
        {
            var readerFactory = services.BuildServiceProvider().GetRequiredService<IHttpRequestStreamReaderFactory>();
            var loggerFactory = services.BuildServiceProvider().GetRequiredService<ILoggerFactory>();
            options.ModelBinderProviders.Insert(0,
                new CustomOptionTypeCreateDtoModelBinderProvider(options.InputFormatters, readerFactory, loggerFactory));
        })

邮递员

EN

回答 1

Stack Overflow用户

发布于 2022-08-03 19:36:55

发现我只需要改变这部分定制的活页夹

代码语言:javascript
复制
   else
        {
            **bindingContext.Result = ModelBindingResult.Failed();**
            return;
        }

代码语言:javascript
复制
  else
            {
                return;
            }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73214632

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档