• ABP框架使用(版本3.3.1) Feature module


    {{baseUrl}}/api/feature-management/features?providerName=D&providerKey=

    1. 必须给对应的Provider给予Policy,不然会报错

        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            Configure<FeatureManagementOptions>(options =>
            {
                options.ProviderPolicies[DefaultValueFeatureValueProvider.ProviderName] = AppNet6Permissions.Products.Default;
            });
        }

    2. 新加个FeatureDefinitionProvider,添加Feature值

        public class MyFeatureDefinitionProvider : FeatureDefinitionProvider
        {
            public override void Define(IFeatureDefinitionContext context)
            {
                var myGroup = context.AddGroup("MyApp");
    
                var reportingFeature = myGroup.AddFeature(
                    "MyApp.Reporting",
                    defaultValue: "false",
                    displayName: LocalizableString
                                     .Create<AppNet6Resource>("Reporting"),
                    valueType: new ToggleStringValueType()
                );
    
                reportingFeature.CreateChild(
                    "MyApp.PdfReporting",
                    defaultValue: "false",
                    displayName: LocalizableString
                                     .Create<AppNet6Resource>("PdfReporting"),
                    valueType: new ToggleStringValueType()
                );
    
                reportingFeature.CreateChild(
                    "MyApp.ExcelReporting",
                    defaultValue: "false",
                    displayName: LocalizableString
                                     .Create<AppNet6Resource>("ExcelReporting"),
                    valueType: new ToggleStringValueType()
                );
            }
        }

    3. 所用的ProviderName跟最后出来的value有关,DefaultValueFeatureValueProvider.ProviderName 的值是“D"

    如果Provider是用别的值,那么API返回的value会是空.

    Default的不会查询表AbpFeatureValues,也可以新起个provider从数据库取值

    可以查看FeatureManager的代码如下

     4.这里的IValueType是dynamic的,现成的有ToggleStringValueType,SelectionStringValueType,FreeTextStringValueType,对于于UI上的CheckBox,DropdownList和InputBox 。如果我想定义多一些属性给SelectionStringValueType,可以继承ISelectionStringValueItem。

        public interface IMySelectionStringValueItemSource
        {
            ICollection<MySelectionStringValueItem> Items { get; }
        }
        public class MySelectionStringValueItemSource : IMySelectionStringValueItemSource
        {
    
            public ICollection<MySelectionStringValueItem> Items { get; }
    
      
            public MySelectionStringValueItemSource(params MySelectionStringValueItem[] items)
            {
                Items = Check.NotNullOrEmpty(items, nameof(items));
            }
        }
        [Serializable]
        [StringValueType("MYSELECTION")]
        public class MySelectionStringValueType : StringValueTypeBase
        {
            public MySelectionStringValueItemSource ItemSource { get; set; }
    
            public MySelectionStringValueType()
            {
    
            }
    
            public MySelectionStringValueType(IValueValidator validator)
                : base(validator)
            {
    
            }
        }
        public class MySelectionStringValueItem : ISelectionStringValueItem
        {
            public string Value { get; set; }
    
            public string Label { get; set; }
    
            public string Source { get; set; }
            public LocalizableStringInfo DisplayText { get; set; }
    
            public MySelectionStringValueItem(string value, string label, string source)
            {
                Value = value;
                Label = label;
                Source = source;
                DisplayText = null; 
            }
        }

    MyFeatureDefinitionProvider

               myGroup.AddFeature(
                    "MyApp.Product",
                    defaultValue: "name2",
                    displayName: LocalizableString
                                     .Create<AppNet6Resource>("MaxProductCount"),
                    // valueType: new FreeTextStringValueType(
                    //               new NumericValueValidator(0, 1000000)),
                    valueType : new MySelectionStringValueType()
                    {
                        ItemSource = new MySelectionStringValueItemSource(
                             new MySelectionStringValueItem("name", "label","source")
                            , new MySelectionStringValueItem("name2", "label", "source")
                            , new MySelectionStringValueItem("name3", "label", "source"))
                    }
    
                );

    还不清楚  properties 怎么用

     5.UI Selection 用Enum类型会更适合,利用 DisplayAttribute,可以定义Name,Description,GroupName,ShortName给前端使用

    MySelectionStringValueItem

        public class MySelectionStringValueItem : ISelectionStringValueItem
        {
    
            public int? Order { get; set; }
            public string Name { get; set; }
            public string Description { get; set; }
            public string GroupName { get; set; }
            public string ShortName { get; set; }
            public string Value { get; set; }
    
            public LocalizableStringInfo DisplayText { get; set; }
    
            public MySelectionStringValueItem()
            {
    
            }
    
    
            public MySelectionStringValueItem(int? order, string name, string value = null, string description = null, string groupName = null, string shortName = null, LocalizableStringInfo displayText = null)
            {
                Order = order;
                Name = name;
                Value = value ?? Name;
                //Description = description ?? Name;
                //GroupName = groupName ?? Name;
                //ShortName = shortName ?? Name;
                //DisplayText = displayText ?? new LocalizableStringInfo(null, Name);
                Description = description;
                GroupName = groupName ;
                ShortName = shortName ;
                DisplayText = displayText;
            }
        }

    接着将Enum Type转换成 MySelectionStringValueItem

    EnumHelper

        public static class EnumHelper
        {
            public static MySelectionStringValueItem[] ConvertEnumToArray(Type enumType)
            {
                MySelectionStringValueItem[] items = new MySelectionStringValueItem[Enum.GetNames(enumType).Length];
                FieldInfo[] fieldInfos = enumType.GetFields();
                int i = 0;
                foreach (FieldInfo fieldInfo in fieldInfos)
                {
                    if (fieldInfo.FieldType != enumType) continue;
                    DisplayAttribute[] attributes = (DisplayAttribute[])fieldInfo.GetCustomAttributes(typeof(DisplayAttribute), false);
    
                    if (attributes.Length > 0)
                    {
                        var attribute = attributes[0];
                        int order = attribute.GetOrder() == null ? 0 : attribute.GetOrder().Value;
                        items[i] = new MySelectionStringValueItem(order: attribute.GetOrder()
                                                                    , name: attribute.Name ?? fieldInfo.Name
                                                                    , value: fieldInfo.GetValue(null).GetHashCode().ToString()
                                                                    , description: attribute.Description
                                                                    , groupName: attribute.GroupName
                                                                    , shortName: attribute.ShortName
                                                                    , displayText: null);
                    }
                    else
                    {
                        items[i] = new MySelectionStringValueItem(order: null
                                                                    , name: fieldInfo.Name
                                                                    , value: fieldInfo.GetValue(null).GetHashCode().ToString()
                                                                    , description: null
                                                                    , groupName: null
                                                                    , shortName: null
                                                                    , displayText: null);
                    }
                    i++;
                }
                return items;
            }
        }

    MyFeatureDefinitionProvider

    public class MyFeatureDefinitionProvider : FeatureDefinitionProvider
        {
            public override void Define(IFeatureDefinitionContext context)
            {
                var myGroup = context.AddGroup("MyApp");
    
                myGroup.AddFeature(
                    "MyApp.Product",
                    defaultValue: "name2",
                    displayName: LocalizableString
                                     .Create<AppNet6Resource>("MaxProductCount"),
                    // valueType: new FreeTextStringValueType(
                    //               new NumericValueValidator(0, 1000000)),
                    valueType: new MySelectionStringValueType()
                    {
                        ItemSource = new MySelectionStringValueItemSource(
                        //     new MySelectionStringValueItem("name", "label", "source")
                        //    , new MySelectionStringValueItem("name2", "label", "source")
                        //    , new MySelectionStringValueItem("name3", "label", "source")
                         EnumHelper.ConvertEnumToArray(typeof(TestEnum))
                        )
                    }
    
                );
            }
    
    
    
            public enum TestEnum
            {
                [Display(Name = "TestEnum1", Order = 1, Description = "TestEnum1 Description")]
                TestEnumOne = -1,
                [Display(Order = 2, Description = "TestEnum2 Description")]
                TestEnumFour = 4,
                [Display(Name = "TestEnum15", Order = 3, Description = "TestEnum3 Description")]
                TestEnumFive = 5
            }
        }

     6.既然 Feature里的data可以利用Attribute转换成 UI 上的组件,那Service上的也可以做到这一点。
    从 api/abp/api-definition 可以得到各个api parameter的meta data,不过默认返回 PropertyApiDescriptionModel 的内容没有包含长度之类。
    需要进一步改造,由于 PropertyApiDescriptionModel 和 TypeApiDescriptionModel 都不是接口类,想另外加field就要起多个新的Api
    MyAbpApiDefinitionController

    下面代码用的是abp5的版本

    [Area("abp")]
    [RemoteService(Name = "abp")]
    [Route("api/abp/abp-api-definition")]
    public class MyAbpApiDefinitionController : AbpController, IRemoteService
    {
        private readonly IMyApiDescriptionModelProvider _modelProvider;
        private readonly IDistributedCache<MyApplicationApiDescriptionModel> _cache;
    
        public MyAbpApiDefinitionController(IMyApiDescriptionModelProvider modelProvider
            , IDistributedCache<MyApplicationApiDescriptionModel> cache)
        {
            _modelProvider = modelProvider;
            _cache = cache;
        }
    
        //[HttpGet]
        //public ApplicationApiDescriptionModel Get(ApplicationApiDescriptionModelRequestDto model)
        //{
        //    return _modelProvider.CreateApiModel(model);
        //}
    
        [HttpGet]
        public MyApplicationApiDescriptionModel GetMyApplicationApiDescriptionModel(ApplicationApiDescriptionModelRequestDto model)
        {
            return  _cache.GetOrAdd(
                "CacheApplicationApiDescriptionModel", //Cache key
                () => GetCacheApplicationApiDescriptionModel(model),
                () => new DistributedCacheEntryOptions
                {
                    AbsoluteExpiration = DateTimeOffset.Now.AddHours(24)
                }
            );
            
        }
    
        protected MyApplicationApiDescriptionModel GetCacheApplicationApiDescriptionModel(ApplicationApiDescriptionModelRequestDto model)
        {
            return _modelProvider.CreateMyApiModel(model);
        }
    }

    IMyApiDescriptionModelProvider

    public interface IMyApiDescriptionModelProvider
    {
        ApplicationApiDescriptionModel CreateApiModel(ApplicationApiDescriptionModelRequestDto input);
    
        MyApplicationApiDescriptionModel CreateMyApiModel(ApplicationApiDescriptionModelRequestDto input);
    }

    MyApplicationApiDescriptionModel

    可以只返回customer的service

    MyAspNetCoreApiDescriptionModelProvider

    public class MyAspNetCoreApiDescriptionModelProvider : IApiDescriptionModelProvider, ITransientDependency
    {
        public ILogger<AspNetCoreApiDescriptionModelProvider> Logger { get; set; }
    
        private readonly AspNetCoreApiDescriptionModelProviderOptions _options;
        private readonly IApiDescriptionGroupCollectionProvider _descriptionProvider;
        private readonly AbpAspNetCoreMvcOptions _abpAspNetCoreMvcOptions;
        private readonly AbpApiDescriptionModelOptions _modelOptions;
    
        public MyAspNetCoreApiDescriptionModelProvider(
            IOptions<AspNetCoreApiDescriptionModelProviderOptions> options,
            IApiDescriptionGroupCollectionProvider descriptionProvider,
            IOptions<AbpAspNetCoreMvcOptions> abpAspNetCoreMvcOptions,
            IOptions<AbpApiDescriptionModelOptions> modelOptions)
        {
            _options = options.Value;
            _descriptionProvider = descriptionProvider;
            _abpAspNetCoreMvcOptions = abpAspNetCoreMvcOptions.Value;
            _modelOptions = modelOptions.Value;
    
            Logger = NullLogger<AspNetCoreApiDescriptionModelProvider>.Instance;
        }
    
        public MyApplicationApiDescriptionModel CreateMyApiModel(ApplicationApiDescriptionModelRequestDto input)
        {
            //TODO: Can cache the model?
    
            var model = MyApplicationApiDescriptionModel.Create();
            var apiItems = _descriptionProvider.ApiDescriptionGroups.Items.Where(o => o.Items.Any(p => p.RelativePath.StartsWith("api/app"))).ToList();
            foreach (var descriptionGroupItem in apiItems)
            {
                foreach (var apiDescription in descriptionGroupItem.Items)
                {
                    if (!apiDescription.ActionDescriptor.IsControllerAction())
                    {
                        continue;
                    }
    
                    AddApiDescriptionToModel(apiDescription, model, input);
                }
            }
    
            return model;
        }

    MyPropertyApiDescriptionModel

    [Serializable]
    public class MyPropertyApiDescriptionModel 
    {
    
        public string Name { get; set; }
    
        public string JsonName { get; set; }
    
        public string Type { get; set; }
    
        public string TypeSimple { get; set; }
    
        public bool IsRequired { get; set; }
    
        public string DisplayName { get; set; }
    
        public int Min { get; set; }
    
        public int Max { get; set; }
    
    
        //TODO: Validation rules for this property
        public static MyPropertyApiDescriptionModel Create(PropertyInfo propertyInfo)
        {
            MyPropertyApiDescriptionModel propertyModel =  new MyPropertyApiDescriptionModel
            {
                Name = propertyInfo.Name,
                JsonName = AbpApiProxyScriptingConfiguration.PropertyNameGenerator.Invoke(propertyInfo),
                Type = ApiTypeNameHelper.GetTypeName(propertyInfo.PropertyType),
                TypeSimple = ApiTypeNameHelper.GetSimpleTypeName(propertyInfo.PropertyType),
                IsRequired = propertyInfo.IsDefined(typeof(RequiredAttribute), true)
            };
            var attributes = propertyInfo.GetCustomAttributes(true);
            if (propertyInfo.IsDefined(typeof(StringLengthAttribute), true))
            {
                var attr = attributes.OfType<StringLengthAttribute>().FirstOrDefault();
                propertyModel.Min = attr.MinimumLength;
                propertyModel.Max = attr.MaximumLength;
            }
            if (propertyInfo.IsDefined(typeof(RangeAttribute), true))
            {
                var attr = attributes.OfType<RangeAttribute>().FirstOrDefault();
                propertyModel.Min = Convert.ToInt32(attr.Minimum);
                propertyModel.Max = Convert.ToInt32(attr.Maximum);
            }
            if (!propertyInfo.PropertyType.IsEnum && propertyInfo.IsDefined(typeof(DisplayAttribute), true))
            {
                var attr = attributes.OfType<DisplayAttribute>().FirstOrDefault();
                propertyModel.DisplayName = attr.GetName();
            }
            else
                propertyModel.DisplayName = propertyModel.Name;
    
    
            return propertyModel;
        }
    }
    

    MyTypeApiDescriptionModel

    [Serializable]
    public class MyTypeApiDescriptionModel
    {
        public string BaseType { get; set; }
    
        public bool IsEnum { get; set; }
    
        //public string[] EnumNames { get; set; }
    
        //public object[] EnumValues { get; set; }
    
        public string[] GenericArguments { get; set; }
    
        public MyPropertyApiDescriptionModel[] Properties { get; set; }
    
        public MySelectionStringValueItem[] EnumProperties { get; set; }
    
        public MyTypeApiDescriptionModel()
        {
    
        }
    
        public static MyTypeApiDescriptionModel Create(Type type)
        {
            var baseType = type.BaseType;
            if (baseType == typeof(object))
            {
                baseType = null;
            }
    
            var typeModel = new MyTypeApiDescriptionModel
            {
                IsEnum = type.IsEnum,
                BaseType = baseType != null ? TypeHelper.GetFullNameHandlingNullableAndGenerics(baseType) : null
            };
    
    
    
            if (typeModel.IsEnum)
            {
                //typeModel.EnumNames = type.GetEnumNames();
                //typeModel.EnumValues = type.GetEnumValues().Cast<object>().ToArray();
                typeModel.EnumProperties = EnumHelper.ConvertEnumToArray(type);
            }
            else
            {
                typeModel.Properties = type
                    .GetProperties()
                    .Where(p => p.DeclaringType == type)
                    .Select(MyPropertyApiDescriptionModel.Create)
                    .ToArray();
    
                if (type.IsGenericTypeDefinition)
                {
                    typeModel.GenericArguments = type.GetGenericArguments().Select(a => a.Name).ToArray();
                }
            }
    
    
            return typeModel;
        }
    }

    ProductDto

        public class ProductDto : FullAuditedEntityDto<Guid>
        {
            [Required]
            [Display(Name = "Product Name")]
            [StringLength(50, MinimumLength = 5,ErrorMessage = "Invalid Product Name.")]
            public string Name { get; set; }
            
            [JsonProperty("testvalue")]
            public Guid StoreId { get; set; }
    
            [Range(0, 15, ErrorMessage = "Can only be between 0 .. 15")]
            public int Quantity { get; set; }
    
            public ProductType ProductType { get; set; }
        }
        
        
        public enum ProductType
        {
            [Display(Name = "Product Type 1")]
            ProductType1 = 0,
            ProductType2 = 1,
            ProductType3 = 2,
        }

    调用 api/abp/abp-api-definition 结果如下,这样返回的内容就可以给UI进行validation了

  • 相关阅读:
    C++内存泄漏检测拾遗
    利用ACE_Get_Opt解析命令
    ACE Reactor模型学习
    Acceptor模型和Connector模型学习
    IOCP模型示例
    ACE Proactor模型示例
    如何:为 ASP.NET 网页全球化设置区域性和 UI 区域性
    Update Calendar Item In excaheng server by exchange web services
    ASP.NET Security Architecture
    Error message when you visit a Web site that is hosted on IIS 7.0: "HTTP Error 500.19 – Internal Server Error"
  • 原文地址:https://www.cnblogs.com/sui84/p/16052499.html
Copyright © 2020-2023  润新知