【问题标题】:ASP.Net Core API bind model int Ids to custom Id objectsASP.Net Core API 将模型 int Id 绑定到自定义 Id 对象
【发布时间】:2019-10-30 11:54:26
【问题描述】:

我有代表不同类型 ID 的结构。该结构具有 int 属性“Id”、带有 (int id) 参数的公共构造函数并实现 IEquatable 接口。我希望我的 ASP.Net Core WebAPI 应用程序以某种方式将这些结构绑定到查询中的传入整数 Id。我知道有自定义模型绑定器,但是要使用它,我需要为所有查询模型实现自定义模型绑定器,因为用自定义模型绑定器标记每个键结构属性还不够 - 我需要注册自定义模型绑定器提供程序,我切换 ModelType 并返回单个模型绑定器,如下所示:

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

            if (context.Metadata.ModelType == typeof(DogQueryModel))
            {
                return new BinderTypeModelBinder(typeof(DogQueryModelBinder));
            }

所以我不能只为每个 Id 结构创建一个模型绑定器 - 需要为每个查询模型创建它。

为了清楚起见,我将提供该结构、查询模型和操作的一些示例代码:

    public struct DogKey : IEquatable<DogKey>
    {
        public DogKey(int id)
        {
            Id = id;
        }

        public int Id { get; }

        #region IEquatable implementation
        #endregion IEquatable implementation
    }

    public class DogQueryModel
    {
        public DogKey Id { get; set; }
        public SomeOtherKey OtherId { get; set; }
        public string Name { get; set; }
    }

    [HttpGet("dog")]
    public async Task<ActionResult<IList<DogResultModel>>> GetDogs([FromQuery]DogQueryModel dogQueryModel)
    {
        //use dogQueryModel.Id as DogKey struct
    }

我想这样查询:https://localhost/api/v1/dogs/dog?id=1&amp;otherId=2&amp;Name=dogname

【问题讨论】:

    标签: c# asp.net-core design-patterns


    【解决方案1】:

    您可以通过实现type converter 来做到这一点,documentation 中提到了它,但遗憾的是没有示例。我已经实现了使您的示例正常工作的必要位。

    我在 KeyConverter 类中添加了一些似乎符合您需要的通用约束,但它们不是必需的。

    public class KeyConverter<T> : TypeConverter
        where T : struct, IEquatable<T>
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(string))
            {
                return true;
            }
    
            return base.CanConvertFrom(context, sourceType);
        }
    
        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            var stringValue = value as string;
            if (!string.IsNullOrWhiteSpace(stringValue))
            {
                if(int.TryParse(stringValue, out int parsed))
                {
                    return Activator.CreateInstance(typeof(T), new object[] { parsed });
                }
            }
            return base.ConvertFrom(context, culture, value);
        }
    }
    

    然后用TypeConverter 属性装饰你的关键类。

    [TypeConverter(typeof(KeyConverter<DogKey>))]
    public struct DogKey : IEquatable<DogKey>
    {
        public DogKey(int id)
        {
            Id = id;
        }
    
        public int Id { get; }
    
        #region IEquatable implementation
        #endregion IEquatable implementation
    
    }
    
    [TypeConverter(typeof(KeyConverter<CatKey>))]
    public struct CatKey : IEquatable<CatKey>
    {
        public CatKey(int id)
        {
            Id = id;
        }
    
        public int Id { get; }
    
        #region IEquatable implementation
        #endregion IEquatable implementation
    
    }
    

    【讨论】:

    • 谢谢你,就像一个魅力!唯一的缺点是 swagger 将参数键显示为字符串,我没有找到任何解决方案如何标记该键以便 swagger 将其显示为整数。
    • 根据您使用的内容,您可以自定义招摇信息:github.com/domaindrivendev/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-07
    • 1970-01-01
    • 2018-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多