1

我有一个包含多个托管服务的网络服务。

我希望能够通过“appSettings.json”打开和关闭它们。

在“StartUp.cs”中,我填充了一个实例

    public class HostedServiceSettings
    {
        public StateOfUse BuildMontageTasks { get; init; }
        public StateOfUse BuildTasksFromFileCreations { get; init; }
        public StateOfUse BusinessEventPuller { get; init; }
        public StateOfUse FieldServiceAppointmentChanges { get; init; }
        public StateOfUse MvtBriefingCleanupLoop { get; init; }
        public StateOfUse SfCacheFileListener { get; init; }
        public StateOfUse TaskWorker { get; init; }
    }

StateOfUse这个枚举是:

    public enum StateOfUse
    {
        Inactive,
        Active
    }

每个属性对应一个托管服务。

回到StartUp课堂上,我添加了以下方法:

        private void AddHostedServices(IServiceCollection services)
        {
            HostedServiceSettings settings = Configure<HostedServiceSettings>(services, "HostedServices");
            foreach (PropertyInfo property in typeof(HostedServiceSettings).GetProperties())
            {
                StateOfUse stateOfUse = (StateOfUse)property.GetValue(settings);
                if (stateOfUse.IsActive())
                {
                    string hostedServiceName = $"PraxedoIntegration.{property.Name}HostedService";
                    Type hostedServiceType = Type.GetType(hostedServiceName);

                    Type type = typeof(IServiceCollection);
                    MethodInfo methodInfo = type.GetMethod("IServiceCollection.AddHostedService");
                    MethodInfo genericMethod = methodInfo.MakeGenericMethod(hostedServiceType);
                    genericMethod.Invoke(services, null);
                }
            }
        }

这会失败,因为MethodInfo methodInfo解析为 null,因此将在下一行引发异常。该方法IServiceCollection.AddHostedService<THostedService>()是一个静态方法,包含Microsoft.Extensions.DependencyInjectionpublic static class ServiceCollectionHostedServiceExtensions. (我不在nameof代码中使用,因为扩展方法不支持。:-()

是否可以通过泛型访问此方法?如果是这样,怎么做?

4

2 回答 2

0

一种选择是使用需要注册每个服务的重载AddHostedServiceimplementationFactory,但如果不活动返回 null 实现

services.AddHostedService<ServiceA>( (services => {
     HostedServiceSettings settings = Configure<HostedServiceSettings>(services, "HostedServices");
     if(settings.IsServiceAActive())
         return new ServiceA();
     return NullService();      
})
于 2021-09-09T14:36:59.900 回答
0

发现我可以通过将扩展方法包装在本地方法中来最简单地解决问题,例如:

        private void AddHostedServices(IServiceCollection services)
        {
            HostedServiceSettings settings = Configure<HostedServiceSettings>(services, "HostedServices");
            foreach (PropertyInfo property in typeof(HostedServiceSettings).GetProperties())
            {
                StateOfUse stateOfUse = (StateOfUse)property.GetValue(settings);
                if (stateOfUse.IsActive())
                {
                    string hostedServiceName = $"PraxedoIntegration.{property.Name}HostedService";
                    Type hostedServiceType = Type.GetType(hostedServiceName);

                    Type type = typeof(Startup);
                    MethodInfo methodInfo = type.GetMethod("AddHostedService");
                    MethodInfo genericMethod = methodInfo.MakeGenericMethod(hostedServiceType);
                    genericMethod.Invoke(this, new object[] { services });
                }
            }
        }

        // Needed as a work-arround because we can't call the extension method with reflection.
        public IServiceCollection AddHostedService<THostedService>(IServiceCollection services)
            where THostedService : class, IHostedService =>
                services.AddHostedService<THostedService>();

或者,它引起了我的注意,在这种情况下,实现细节AddHostedService()是已知的,它只是一个包装器(可以说是“语法糖”)AddTransient(),所以我可以通过这样做来避免反射:

        private void AddHostedServices(IServiceCollection services)
        {
            HostedServiceSettings settings = Configure<HostedServiceSettings>(services, "HostedServices");
            foreach (PropertyInfo property in typeof(HostedServiceSettings).GetProperties())
            {
                StateOfUse stateOfUse = (StateOfUse)property.GetValue(settings);
                if (stateOfUse.IsActive())
                {
                    string hostedServiceName = $"PraxedoIntegration.{property.Name}HostedService";
                    Type hostedServiceType = Type.GetType(hostedServiceName);

                    services.AddTransient(typeof(IHostedService), hostedServiceType);
                }
            }
        }
于 2021-09-09T15:35:16.373 回答