ASP.NET的核心RC2。抽象类模型绑定 [英] Asp net core rc2. Abstract class model binding

查看:184
本文介绍了ASP.NET的核心RC2。抽象类模型绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我使用抽象类或接口结合下面的代码RC1:

In the RC1 I use the following code for abstract classes or interfaces binding:

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

这粘结剂只读取机型(为messageType 参数)的查询字符串和覆盖元数据类型。其余的通过标准粘合剂,如 BodyModelBinder 执行的工作。

This binder only reads model type (messageType parameter) from query string and overrides metadata type. And the rest of the work performed by standard binders such as BodyModelBinder.

在Startup.cs我只是第一次加粘结剂:

In Startup.cs I just add first 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执行此?

How can I perform this in RC2?

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

As far as I understand, now I have to use IModelBinderProvider. OK, I tried. Startup.cs:

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



ModelBinderProvider:

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的:

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

But I cannot specify NoResult. If I do not specify bindingContext.Result, I get null model in controller. If I specify bindingContext.Result, I get empty model without setting model fields.

推荐答案

我有自定义的模型绑定和抽象类类似的要求,并张贴 dougbu 在github ASPNET / MVC /问题/ 4703 为我工作。我从 RC1 升级到 ASP.NET 1.0的核心并修改我的自定义模型粘结剂与他的建议所需。我有复制和放大器;粘贴下面一行代码的情况下,链接到GitHub的问题休息。阅读GitHub的问题为围绕在服务器上创建一个请求类型的对象的代码安全性的考虑意见。

I had a similar requirement with custom model binding and abstract classes and the suggestions posted by dougbu on github AspNet/Mvc/issues/4703 worked for me. I upgraded from RC1 to ASP.NET Core 1.0 and needed to modify my custom model binder with his recommendations. I've copy & pasted his code below in case the link to the github issue breaks. Read the comments in the github issue for security considerations around code that creates objects of a requested type on the server.

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



MessageModelBinder



MessageModelBinder

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

这篇关于ASP.NET的核心RC2。抽象类模型绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆