Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/flash/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# asp.net核心web api 2中的抽象类模型绑定_C#_Asp.net Core 2.0_Model Binding - Fatal编程技术网

C# asp.net核心web api 2中的抽象类模型绑定

C# asp.net核心web api 2中的抽象类模型绑定,c#,asp.net-core-2.0,model-binding,C#,Asp.net Core 2.0,Model Binding,我一直在试图找出如何使用.NETCore2WebAPI的自定义模型绑定,但一直未能使其正常工作 我已经阅读了以下几篇文章 在我的例子中,bindingContext.ModelName始终为空。有人能解释为什么会这样吗 下面是示例实现 控制器 public IActionResult SomeAction([ModelBinder(BinderType = typeof(BlahTypeModelBinder))][FromBody]TheBaseClass theBase)

我一直在试图找出如何使用.NETCore2WebAPI的自定义模型绑定,但一直未能使其正常工作

我已经阅读了以下几篇文章

在我的例子中,bindingContext.ModelName始终为空。有人能解释为什么会这样吗

下面是示例实现

控制器

        public IActionResult SomeAction([ModelBinder(BinderType = typeof(BlahTypeModelBinder))][FromBody]TheBaseClass theBase)
    {
        return Ok();
    }
模型

public abstract class TheBaseClass
{
    public abstract int WhatType { get; }
}

public class A : TheBaseClass
{
    public override int WhatType { get { return 1; }  }
}

public class B : TheBaseClass
{
    public override int WhatType { get { return 2; } }
}
提供者

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

        if (context.Metadata.ModelType == typeof(TheBaseClass))
        {
            var assembly = typeof(TheBaseClass).Assembly;
            var abstractSearchClasses = assembly.GetExportedTypes()
                .Where(t => t.BaseType.Equals(typeof(TheBaseClass)))
                .Where(t => !t.IsAbstract)
                .ToList();

            var modelBuilderByType = new Dictionary<Type, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder>();

            foreach (var type in abstractSearchClasses)
            {
                var propertyBinders = new Dictionary<ModelMetadata, IModelBinder>();
                var metadata = context.MetadataProvider.GetMetadataForType(type);

                foreach (var property in metadata.Properties)
                {
                    propertyBinders.Add(property, context.CreateBinder(property));
                }

                modelBuilderByType.Add(type, new Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder(propertyBinders));
            }

            return new BlahTypeModelBinder(modelBuilderByType, context.MetadataProvider);
        }

        return null;
    }
}
公共类BhalTypeBinderProvider:IModelBinderProvider
{
公共IModelBinder GetBinder(ModelBinderProviderContext)
{
if(上下文==null)
抛出新ArgumentNullException(nameof(context));
if(context.Metadata.ModelType==typeof(TheBaseClass))
{
var assembly=typeof(TheBaseClass).assembly;
var abstractSearchClasses=assembly.GetExportedTypes()
其中(t=>t.BaseType.Equals(typeof(TheBaseClass)))
.Where(t=>!t.IsAbstract)
.ToList();
var modelBuilderByType=new Dictionary();
foreach(AbstractSearchClass中的变量类型)
{
var propertyBinders=new Dictionary();
var metadata=context.MetadataProvider.GetMetadataForType(类型);
foreach(metadata.Properties中的var属性)
{
Add(property,context.CreateBinder(property));
}
添加(类型,新的Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder(propertyBinders));
}
返回新的BlahTypeModelBinder(modelBuilderByType,context.MetadataProvider);
}
返回null;
}
}
活页夹

public class BlahTypeModelBinder : IModelBinder
{
    private readonly IModelMetadataProvider _metadataProvider;
    private readonly IDictionary<Type, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder> _binders;

    public BlahTypeModelBinder(IDictionary<Type, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder> binders, IModelMetadataProvider metadataProvider)
    {
        _metadataProvider = metadataProvider;
        _binders = binders;
    }

    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
            throw new ArgumentNullException(nameof(bindingContext));

        var modelTypeValue = bindingContext.ValueProvider.GetValue(ModelNames.CreatePropertyModelName(bindingContext.ModelName, "WhatType"));
        if (modelTypeValue != null && modelTypeValue.FirstValue != null)
        {
            Type modelType = Type.GetType(modelTypeValue.FirstValue);
            if (this._binders.TryGetValue(modelType, out var modelBinder))
            {
                ModelBindingContext innerModelBindingContext = DefaultModelBindingContext.CreateBindingContext(
                    bindingContext.ActionContext,
                    bindingContext.ValueProvider,
                    this._metadataProvider.GetMetadataForType(modelType),
                    null,
                    bindingContext.ModelName);

                /*modelBinder*/
                this._binders.First().Value.BindModelAsync(innerModelBindingContext);

                bindingContext.Result = innerModelBindingContext.Result;
                return Task.CompletedTask;
            }
        }

       //More code
    }
}
公共类BlahTypeModelBinder:IModelBinder
{
私有只读IModelMetadataProvider\u metadataProvider;
专用只读IDictionary活页夹;
公共BlahTypeModelBinder(IDictionary Binder、IModelMetadataProvider metadataProvider)
{
_metadataProvider=metadataProvider;
_粘合剂=粘合剂;
}
公共任务BindModelAsync(ModelBindingContext bindingContext)
{
if(bindingContext==null)
抛出新ArgumentNullException(nameof(bindingContext));
var modelTypeValue=bindingContext.ValueProvider.GetValue(ModelNames.CreatePropertyModelName(bindingContext.ModelName,“WhatType”);
if(modelTypeValue!=null&&modelTypeValue.FirstValue!=null)
{
类型modelType=Type.GetType(modelTypeValue.FirstValue);
if(this._binders.TryGetValue(modelType,out var modelBinder))
{
ModelBindingContext innerModelBindingContext=DefaultModelBindingContext.CreateBindingContext(
bindingContext.ActionContext,
bindingContext.ValueProvider,
此._metadataProvider.GetMetadataForType(modelType),
无效的
bindingContext.ModelName);
/*模型装订机*/
这是.u binders.First().Value.bindmodelsync(innerModelBindingContext);
bindingContext.Result=innerModelBindingContext.Result;
返回Task.CompletedTask;
}
}
//更多代码
}
}
链接到的示例使用外部查询字符串参数确定类型。 如果您像这样调用您的操作
SomeAction?WhatType=YourNamespaceName.A
绑定按预期工作

bindingContext.ModelName
为空很好,它将在模型绑定后设置。如果需要,可以在设置bindingContext.Result后进行设置。参数
WhatType
来自
QueryStringValueProvider
,因此没有前缀是可以的

如何单独基于JSON实现抽象模型绑定 为此,我们需要:

  • 一个值提供程序,用于读取JSON并为我们提供一些“WhatType”值,以代替QueryStringValueProvider
  • 将提取的数字映射到
    类型
    -s的一些反射
  • 1.价值提供者 这里有一篇关于创建ValueProviders的详细文章:

    作为起点,这里有一些代码成功地从主体json中提取WhatType整数:

        public class BlahValueProvider : IValueProvider
    {
        private readonly string _requestBody;
    
        public BlahValueProvider(string requestBody)
        {
            _requestBody = requestBody;
        }
    
        private const string PROPERTY_NAME = "WhatType";
    
        public bool ContainsPrefix(string prefix)
        {
            return prefix == PROPERTY_NAME;
        }
    
        public ValueProviderResult GetValue(string key)
        {
            if (key != PROPERTY_NAME)
                return ValueProviderResult.None;
    
            // parse json
    
            try
            {
                var json = JObject.Parse(_requestBody);
                return new ValueProviderResult(json.Value<int>("WhatType").ToString());
            }
            catch (Exception e)
            {
                // TODO: error handling
                throw;
            }
        }
    }
    
    public class BlahValueProviderFactory : IValueProviderFactory
    {
        public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
    
            var request = context.ActionContext.HttpContext.Request;
            if (request.ContentType == "application/json")
            {
                return AddValueProviderAsync(context);
            }
    
            return Task.CompletedTask;
        }
    
        private Task AddValueProviderAsync(ValueProviderFactoryContext context)
        {
            using (StreamReader sr = new StreamReader(context.ActionContext.HttpContext.Request.Body))
            {
                string bodyString = sr.ReadToEnd();
                context.ValueProviders.Add(new BlahValueProvider(bodyString));
            }
    
            return Task.CompletedTask;
        }
    }
    
    公共类BlahValueProvider:IValueProvider
    {
    私有只读字符串_requestBody;
    公共BlahValueProvider(字符串请求体)
    {
    _requestBody=requestBody;
    }
    私有常量字符串属性\u NAME=“WhatType”;
    公共bool ContainsPrefix(字符串前缀)
    {
    返回前缀==属性名称;
    }
    public ValueProviderResult GetValue(字符串键)
    {
    如果(键!=属性名称)
    返回值ProviderResult.None;
    //解析json
    尝试
    {
    var json=JObject.Parse(_requestBody);
    返回新的ValueProviderResult(json.Value(“WhatType”).ToString();
    }
    捕获(例外e)
    {
    //TODO:错误处理
    投掷;
    }
    }
    }
    公共类BlahValueProviderFactory:IValueProviderFactory
    {
    公共任务CreateValueProviderAsync(ValueProviderFactoryContext上下文)
    {
    if(上下文==null)
    {
    抛出新ArgumentNullException(nameof(context));
    }
    var request=context.ActionContext.HttpContext.request;
    if(request.ContentType==“应用程序/json”)
    {
    返回AddValueProviderAsync(上下文);
    }
    返回Task.CompletedTask;
    }
    专用任务AddValueProviderAsync(ValueProviderFactoryContext上下文)
    {
    使用(StreamReader sr=newstreamreader(context.ActionContext.HttpContext.Request.Body))
    {
    字符串bodyString=sr.ReadToEnd();
    Add(新BlahValueProvider(bodyString));
    }
    返回Task.CompletedTask;
    }
    }
    
    当然<
    public class BlahTypeModelBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
                throw new ArgumentNullException(nameof(bindingContext));
    
            var json = ExtractRequestJson(bindingContext.ActionContext);
            var jObject = Newtonsoft.Json.Linq.JObject.Parse(json);
            var whatTypeInt = (int)jObject.SelectToken("WhatType");
    
            if (whatTypeInt == 1)
            {
                var obj = DeserializeObject<A>(json);
                bindingContext.Result = ModelBindingResult.Success(obj);
            }
            else if (whatTypeInt == 2)
            {
                var obj = DeserializeObject<B>(json);
                bindingContext.Result = ModelBindingResult.Success(obj);
            }
            else
            {
                bindingContext.Result = ModelBindingResult.Failed();
                return Task.CompletedTask;
            }
    
            return Task.CompletedTask;
        }
    
        private static string ExtractRequestJson(ActionContext actionContext)
        {
            var content = actionContext.HttpContext.Request.Body;
            return new StreamReader(content).ReadToEnd();
        }
    
        private static T DeserializeObject<T>(string json)
        {
            return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(json, new Newtonsoft.Json.JsonSerializerSettings
            {
                TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto
            });
        }
    }