C# 自定义模型绑定器未从值提供程序检索值
我有一个自定义模型绑定器,可以将发布的值转换为另一个模型。 问题是C# 自定义模型绑定器未从值提供程序检索值,c#,asp.net-core,asp.net-core-mvc,asp.net-core-1.1,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")] Anothe
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 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);
}
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.ModelBinderProviders.Insert(0,new ParametersModelBinderProvider(configuration));
});
}
快速观察显示ValueProvider确实有值
更新1
在updateaction方法中,当我可以遍历IFormCollection时,Request.Form拥有所有的键和值对。不确定为什么模型绑定器无法检索它
foreach (var f in HttpContext.Request.Form)
{
var key = f.Key;
var v = f.Value;
}
如果检查MVC的源代码,您会注意到“name[index]”形式的值将返回ValueProviderResult.None,需要单独处理 看起来你在试图解决错误的问题。我建议绑定到标准的集合类,如
Dictionary
要么
公共操作结果更新([DataSourceRequest]DataSourceRequest请求,
[Bind(Prefix=“models”)]字典项
或
public类AnotherModel:Dictionary{}
如果您不知道每个字典值在编译时的类型,那么定制活页夹就可以派上用场了
我的例子
在我的客户机中,我在请求中发送了一个头,这个头是Base64String(Json序列化对象)
对象->Json->Base64
标题不能是多行的。使用base64,我们得到一行
所有这些都适用于Body和其他来源
标题类
[ModelBinder(BinderType = typeof(MyModelBinder))]
public class AnotherModel
{
IEnumerable<Dictionary<string, object>> Items { get; set; }
}
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);
}
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.ModelBinderProviders.Insert(0,new ParametersModelBinderProvider(configuration));
});
}
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;
}
}
型号活页夹供应商
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;
}
}
我们可以使用任何BindingSource
- 身体
- BindingSource自定义
- BindingSource表单
- BindingSourceFormFile
- BindingSource标头
- BindingSourceModelBinding
- 绑定源路径
- 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中
[ModelBinder(BinderType = typeof(MyModelBinder))]
public class AnotherModel
{
IEnumerable<Dictionary<string, object>> Items { get; set; }
}
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);
}
}
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
}
[HttpGet(nameof(Exchange))]
公共操作结果交换([FromHeader(Name=nameof(RequestHeader))]RequestHeader头)
{
//RequestHeader以前是在modelbinder中处理的。
//RequestHeader为null或对象实例。
//一些说明
}
来自mvc集合活页夹的提示;您可以共享您的post数据吗?另外,您会收到AnotherModel
而不是List
,但是您会像models[0]那样传递数据。属性
。您需要传递models.property1
,models.property2
…你的数据源任务是什么
?如果你删除它会影响你的结果吗?@Rena这是剑道网格的帖子。这是从fiddlersort=&group=&filter=&models%5B0%5D.Id=2&models%5B0%5D.FirstName=foo&models%5B0%5D.LastName=bar中捕获的帖子。我试过字典,但没用。请注意,items
参数是网格行的集合。因此,它必须是IEnumerable
,其中每个字典
代表一行,所以您想绑定列表
?您正在发布模型[0]。Id=
,因此带有T.Id
字段的列表也可以工作。网格的列是动态的。我在设计时不知道“T”