gpt4 book ai didi

c# - Asp 净核心 rc2.抽象类模型绑定(bind)

转载 作者:太空狗 更新时间:2023-10-29 21:53:15 25 4
gpt4 key购买 nike

在 RC1 中,我将以下代码用于抽象类或接口(interface)绑定(bind):

public class MessageModelBinder : IModelBinder {

public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext) {
if(bindingContext.ModelType == typeof(ICommand)) {
var msgTypeResult = bindingContext.ValueProvider.GetValue("messageType");
if(msgTypeResult == ValueProviderResult.None) {
return ModelBindingResult.FailedAsync(bindingContext.ModelName);
}
var type = Assembly.GetAssembly(typeof(MessageModelBinder )).GetTypes().SingleOrDefault(t => t.FullName == msgTypeResult.FirstValue);
if(type == null) {
return ModelBindingResult.FailedAsync(bindingContext.ModelName);
}
var metadataProvider = (IModelMetadataProvider)bindingContext.OperationBindingContext.HttpContext.RequestServices.GetService(typeof(IModelMetadataProvider));
bindingContext.ModelMetadata = metadataProvider.GetMetadataForType(type);
}
return ModelBindingResult.NoResultAsync;
}
}

此绑定(bind)器仅从查询字符串中读取模型类型(messageType 参数)并覆盖元数据类型。其余工作由标准绑定(bind)器执行,例如 BodyModelBinder

在 Startup.cs 中,我只添加了第一个 Binder :

services.AddMvc().Services.Configure<MvcOptions>(options => {
options.ModelBinders.Insert(0, new MessageModelBinder());
});

Controller :

[Route("api/[controller]")]
public class MessageController : Controller {
[HttpPost("{messageType}")]
public ActionResult Post(string messageType, [FromBody]ICommand message) {
}
}

我如何在 RC2 中执行此操作?

据我了解,现在我必须使用IModelBinderProvider。好的,我试过了。启动.cs:

services.AddMvc().Services.Configure<MvcOptions>(options => {
options.ModelBinderProviders.Insert(0, new MessageModelBinderProvider());
});

模型绑定(bind)器提供者:

public class MessageModelBinderProvider : IModelBinderProvider {
public IModelBinder GetBinder(ModelBinderProviderContext context) {
if(context == null) {
throw new ArgumentNullException(nameof(context));
}
return context.Metadata.ModelType == typeof(ICommand) ? new MessageModelBinder() : null;
}
}

模型绑定(bind)器:

public class MessageModelBinder : IModelBinder {
public Task BindModelAsync(ModelBindingContext bindingContext) {
if(bindingContext.ModelType == typeof(ICommand)) {
var msgTypeResult = bindingContext.ValueProvider.GetValue("messageType");
if(msgTypeResult == ValueProviderResult.None) {
bindingContext.Result = ModelBindingResult.Failed(bindingContext.ModelName);
return Task.FromResult(0);
}
var type = typeof(MessageModelBinder).GetTypeInfo().Assembly.GetTypes().SingleOrDefault(t => t.FullName == msgTypeResult.FirstValue);
if(type == null) {
bindingContext.Result = ModelBindingResult.Failed(bindingContext.ModelName);
return Task.FromResult(0);
}
var metadataProvider = (IModelMetadataProvider)bindingContext.OperationBindingContext.HttpContext.RequestServices.GetService(typeof(IModelMetadataProvider));
bindingContext.ModelMetadata = metadataProvider.GetMetadataForType(type);
bindingContext.Result = ModelBindingResult.Success(bindingContext.ModelName, Activator.CreateInstance(type));
}
return Task.FromResult(0);
}
}

但是我不能指定NoResult。如果我不指定 bindingContext.Result,我会在 Controller 中得到 null 模型。如果我指定 bindingContext.Result,我会得到没有设置模型字段的空模型。

最佳答案

我对自定义模型绑定(bind)和抽象类以及 dougbu 发布的建议有类似的要求在 github 上 AspNet/Mvc/issues/4703为我工作。我从 RC1 升级到 ASP.NET Core 1.0 并且需要根据他的建议修改我的自定义模型绑定(bind)器。我已经在下面复制并粘贴了他的代码,以防 github 问题的链接中断。阅读 github 问题中的评论,了解有关在服务器上创建请求类型的对象的代码的安全考虑。

MessageModelBinderProvider

public class MessageModelBinderProvider : IModelBinderProvider 
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}

if (context.Metadata.ModelType != typeof(ICommand))
{
return null;
}

var binders = new Dictionary<string, IModelBinder>();
foreach (var type in typeof(MessageModelBinderProvider).GetTypeInfo().Assembly.GetTypes())
{
var typeInfo = type.GetTypeInfo();
if (typeInfo.IsAbstract || typeInfo.IsNested)
{
continue;
}

if (!(typeInfo.IsClass && typeInfo.IsPublic))
{
continue;
}

if (!typeof(ICommand).IsAssignableFrom(type))
{
continue;
}

var metadata = context.MetadataProvider.GetMetadataForType(type);
var binder = context.CreateBinder(metadata);
binders.Add(type.FullName, binder);
}

return new MessageModelBinder(context.MetadataProvider, binders);
}
}

消息模型绑定(bind)器

public class MessageModelBinder : IModelBinder
{
private readonly IModelMetadataProvider _metadataProvider;
private readonly Dictionary<string, IModelBinder> _binders;

public MessageModelBinder(IModelMetadataProvider metadataProvider, Dictionary<string, IModelBinder> binders)
{
_metadataProvider = metadataProvider;
_binders = binders;
}

public async Task BindModelAsync(ModelBindingContext bindingContext)
{
var messageTypeModelName = ModelNames.CreatePropertyModelName(bindingContext.ModelName, "messageType");
var messageTypeResult = bindingContext.ValueProvider.GetValue(messageTypeModelName);
if (messageTypeResult == ValueProviderResult.None)
{
bindingContext.Result = ModelBindingResult.Failed();
return;
}

IModelBinder binder;
if (!_binders.TryGetValue(messageTypeResult.FirstValue, out binder))
{
bindingContext.Result = ModelBindingResult.Failed();
return;
}

// Now know the type exists in the assembly.
var type = Type.GetType(messageTypeResult.FirstValue);
var metadata = _metadataProvider.GetMetadataForType(type);

ModelBindingResult result;
using (bindingContext.EnterNestedScope(metadata, bindingContext.FieldName, bindingContext.ModelName, model: null))
{
await binder.BindModelAsync(bindingContext);
result = bindingContext.Result;
}

bindingContext.Result = result;
}
}

关于c# - Asp 净核心 rc2.抽象类模型绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37318029/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com