asp.net 核心依赖注入到 System.ComponentModel.TypeConverter

时间:2021-07-21 16:26:04

标签: c# asp.net-core asp.net-web-api dependency-injection type-conversion

我有一个服务和 ILogger 需要在我的 TypeConverter 中使用,但没有使用或触发带有参数的构造函数,并且我的记录器和服务在转换类型时保持为空。

public class ModelServiceVersionConverter : TypeConverter
    {
        private static readonly Type StringType = typeof(string);
        private static readonly Type VersionType = typeof(ModelServiceVersion);

        private readonly ModelServiceVersions modelServiceVersions;

        private readonly ILogger<ModelServiceVersionConverter> logger;

        public ModelServiceVersionConverter()
        {
        }

        public ModelServiceVersionConverter(ModelServiceVersions modelServiceVersions, ILogger<ModelServiceVersionConverter> logger)
        {
            this.modelServiceVersions = modelServiceVersions;
            this.logger = logger;
        }

        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) =>
            sourceType == StringType ||
            sourceType == VersionType ||
            base.CanConvertFrom(context, sourceType);

        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value is null)
            {
                return this.modelServiceVersions.ServiceVersions.Last();
            }

            var modelServiceVersion = this.modelServiceVersions.ServiceVersions.FirstOrDefault(x => x == value.ToString());

            if (modelServiceVersion is null)
            {
                var errorMessage = $"Version {value} unexpected. No implementation of {nameof(IModelService)} for this version.";
                this.logger.LogError(errorMessage);
                throw new ArgumentException(errorMessage);
            }

            return modelServiceVersion;
        }
    }


ModelServiceVersion 类非常简单,并且具有 TypeConverter 属性。

    [TypeConverter(typeof(ModelServiceVersionConverter))]
    public class ModelServiceVersion : ValueObject, IComparer<ModelServiceVersion>
    {
        private readonly string version;

        public static ModelServiceVersion New(string version)
        {
            return new ModelServiceVersion(version);
        }

        private ModelServiceVersion(string version) =>
            this.version = version;

        public static implicit operator string(ModelServiceVersion modelServiceVersion) => modelServiceVersion.version;

        public static implicit operator ModelServiceVersion(StringValues stringValues) => New(stringValues[0]);

        protected override IEnumerable<object> GetEqualityComponents()
        {
            yield return this.version;
        }

        public int Compare(ModelServiceVersion x, ModelServiceVersion y)
        {
            // TODO these rules can and will likely change
            var versionNumberX = FirstOrDefaultDigit(x?.version);
            var versionNumberY = FirstOrDefaultDigit(x?.version);

            if (y is null || versionNumberY is null)
            {
                return 1;
            }

            if (x is null || versionNumberX is null)
            {
                return -1;
            }

            if (versionNumberX == versionNumberY)
            {
                return 0;
            }

            return versionNumberX > versionNumberY ? 1 : -1;

            static int? FirstOrDefaultDigit(string versionString) =>
                versionString?.ToCharArray().FirstOrDefault(IsDigit);
        }
    }

所有服务都注册到 Microsoft.Extensions.DependencyInjection.IServiceCollection

我试过只注册为作用域,但它没有触发类型转换器构造函数来注入依赖项。

services.AddScoped<ModelServiceVersionConverter>();

用于控制器上的动作时

        public async Task<IActionResult> GetPrediction([FromRoute] int decisionModelId, [FromQuery] ModelServiceVersion version, [FromBody] GetPredictionModelRequest.Request request)
        {
            var result = await this.predictionModelQueries.GetPrediction(new GetPredictionModelRequest(decisionModelId, request));

            return this.Ok(result);
        }

有什么想法我哪里出错了吗?

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

假设您已经创建了一个自定义 Attribute 并将其应用于一个方法或一个类。在这种情况下,构造函数 DI 会起作用吗?

没有。除非您使用 specific asp.net-core attributes like ServiceFilterAttribute,否则不支持此功能。

因此您需要重新设计类或对 DI 容器 IServiceProvider 进行静态访问。