Asp网核rc2。 抽象类模型绑定

在RC1中,我使用以下代码进行抽象类或接口绑定:

public class MessageModelBinder : IModelBinder { public Task 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; } } 

此绑定程序仅从查询字符串中读取模型类型( messageType参数)并覆盖元数据类型。 其余的工作由标准粘合剂(如BodyModelBinder

在Startup.cs中我只添加第一个binder:

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

控制器:

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

我怎样才能在RC2中执行此操作?

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

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

ModelBinderProvider:

 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; } } 

ModelBinder的:

 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 ,我在控制器中得到null模型。 如果我指定bindingContext.Result ,我得到空模型而不设置模型字段。

我对自定义模型绑定和抽象类有类似的要求, dougbu在github上发布的建议AspNet / Mvc / issues / 4703对我有用 。 我从RC1升级到ASP.NET Core 1.0 ,需要根据他的建议修改我的自定义模型绑定器。 我已经复制并粘贴了他的代码,以防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(); 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); } } 

MessageModelBinder

 public class MessageModelBinder : IModelBinder { private readonly IModelMetadataProvider _metadataProvider; private readonly Dictionary _binders; public MessageModelBinder(IModelMetadataProvider metadataProvider, Dictionary 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; } }