自定义模型活页夹未从价值提供者那里获取价值

时间:2020-03-12 00:08:53

标签: c# asp.net-core asp.net-core-mvc asp.net-core-1.1

我有一个自定义模型活页夹,它将发布的值转换为另一个模型。 问题是bindingContext.ValueProvider.GetValue(modelName)即使从客户端发布值也不会返回任何内容。

操作方法

[HttpPost]
public ActionResult Update([DataSourceRequest] DataSourceRequest request, 
                           [Bind(Prefix = "models")] AnotherModel items)
{
    return Ok();
}

目标模型类

[ModelBinder(BinderType = typeof(MyModelBinder))]
public class AnotherModel
{
    IEnumerable<Dictionary<string, object>> Items { get; set; }
}

客户模型粘合剂

public class MyModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }

        var modelName = bindingContext.ModelName;

        // ISSUE: valueProviderResult is always None
        var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);

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


        //here i will convert valueProviderResult to AnotherModel


        return Task.CompletedTask;
    }
}

快速观察显示ValueProvider确实具有值

enter image description here

UPDATE1

当我可以通过IFormCollection进行迭代时,在Update操作方法中,Request.Form具有所有的键和值对。不确定为什么模型联编程序无法检索它。

foreach (var f in HttpContext.Request.Form)
{
    var key = f.Key;
    var v = f.Value;
}

2 个答案:

答案 0 :(得分:0)

如果检查MVC CollectionModelBinder的源代码,您会注意到“ name [index]”形式的值将返回ValueProviderResult。无,需要单独处理。

似乎您正在尝试解决错误的问题。我建议绑定到像Dictionary这样的标准集合类。

要么;

public ActionResult Update([DataSourceRequest] DataSourceRequest request, 
                           [Bind(Prefix = "models")] Dictionary<string, RecordTypeName> items)

或者;

public class AnotherModel : Dictionary<string, RecordTypeName> {}

如果您不知道每个字典值在编译时将具有哪种类型,那么可以在其中使用自定义活页夹。

答案 1 :(得分:0)

我的例子

在我的客户端中,我在请求中发送一个标头,该标头是Base64String(Json序列化对象)

对象-> Json-> Base64。

标题不能为多行。使用base64,我们得到1行。

所有这些都适用于Body和其他来源。

标题类

public class RequestHeader : IHeader
{
    [Required]
    public PlatformType Platform { get; set; } //Windows / Android / Linux / MacOS / iOS

    [Required]
    public ApplicationType ApplicationType { get; set; } 

    [Required(AllowEmptyStrings = false)]
    public string UserAgent { get; set; } = null!; 

    [Required(AllowEmptyStrings = false)]
    public string ClientName { get; set; } = null!; 

    [Required(AllowEmptyStrings = false)]
    public string ApplicationName { get; set; } = null!;

    [Required(AllowEmptyStrings = true)]
    public string Token { get; set; } = null!; 


    public string ToSerializedString()
    {
        return JsonConvert.SerializeObject(this);
    }
}

IHeader界面

public interface IHeader
{
}

模型活页夹

public class HeaderParameterModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        StringValues headerValue = bindingContext.HttpContext.Request.Headers.Where(h =>
        {
            string guid = Guid.NewGuid().ToString();
            return h.Key.Equals(bindingContext.ModelName ?? guid) | 
                   h.Key.Equals(bindingContext.ModelType.Name ?? guid) | 
                   h.Key.Equals(bindingContext.ModelMetadata.ParameterName); 
        }).Select(h => h.Value).FirstOrDefault();
        if (headerValue.Any())
        {
            try
            {
                //Convert started
                bindingContext.Model = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(Convert.FromBase64String(headerValue)), bindingContext.ModelType);
                bindingContext.Result = ModelBindingResult.Success(bindingContext.Model);
            }
            catch
            {
            }
        }
        return Task.CompletedTask;
    }
}

Model Binder提供商

我们可以使用任何BindingSource。

  • 身体
  • BindingSource自定义
  • BindingSource表单
  • BindingSource FormFile
  • BindingSource标头
  • BindingSource ModelBinding
  • BindingSource路径
  • BindingSource查询
  • BindingSource服务
  • BindingSource特殊


public class ParametersModelBinderProvider : IModelBinderProvider
{
    private readonly IConfiguration configuration;

    public ParametersModelBinderProvider(IConfiguration configuration)
    {
        this.configuration = configuration;
    }

    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context.Metadata.ModelType.GetInterfaces().Where(value => value.Name.Equals(nameof(ISecurityParameter))).Any() && BindingSource.Header.Equals(context.Metadata.BindingSource))
        {
            return new SecurityParameterModelBinder(configuration);
        }

        if (context.Metadata.ModelType.GetInterfaces().Where(value=>value.Name.Equals(nameof(IHeader))).Any() && BindingSource.Header.Equals(context.Metadata.BindingSource))
        {
            return new HeaderParameterModelBinder();
        }
        return null!;
    }
}

在Startup.cs中

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        options.ModelBinderProviders.Insert(0,new ParametersModelBinderProvider(configuration));
    });
}

控制器操作

ExchangeResult是我的结果类。

[HttpGet(nameof(Exchange))]
public ActionResult<ExchangeResult> Exchange([FromHeader(Name = nameof(RequestHeader))] RequestHeader header)
{
    //RequestHeader previously was processed in modelbinder.
    //RequestHeader is null or object instance.  
    //Some instructions
}