. net - services.配置绑定到已经实例化的实体



我创建了以下扩展来简化我们许多项目中的应用程序配置

public static TAppSettings AddAppSettings<TAppSettings>(this IServiceCollection services,
IConfiguration configuration, string sectionName = BaseAppSettings.DefaultSectionName,
ServiceLifetime lifetime = ServiceLifetime.Scoped)
where TAppSettings : BaseAppSettings
{
var appSettingsSection = configuration.GetSection(sectionName);
var appSettings = appSettingsSection.Get<TAppSettings>();
if (appSettings == null) throw new NullReferenceException(nameof(appSettings));
services.Configure<TAppSettings>(appSettingsSection);
services.Add(new ServiceDescriptor(typeof(TAppSettings),serviceProvider =>appSettings , lifetime));
return appSettings;
}

这样我就可以把它叫做

services.AddAppSettings<AppSettings>(context.Configuration);

是否有绑定一个已经定义的对象实例,像一个与一些默认值?

我试过下面的代码,但是IOptions中的任何值是空的

public static TAppSettings AddAppSettings<TAppSettings>(this IServiceCollection services, IConfiguration configuration,
TAppSettings appSettings,
ServiceLifetime lifetime = ServiceLifetime.Scoped)
where TAppSettings : BaseAppSettings
{
if (appSettings == null) throw new NullReferenceException(nameof(appSettings));
services.Configure<TAppSettings>(options=>options=appSettings);
return appSettings;
}
<标题>

更新我知道这是不寻常的,但想象一下,我有一个应用程序,不使用appsettings.json。我想为我的配置设置一些值(我知道可以在类中设置默认值),但想象一下,我不想在那里设置一些默认值,因为它们可以从应用程序更改到不使用appsettings的应用程序。但是我仍然想注入IOptions;

任何想法?

如果你想注册一个对象(代表一些设置)为IOptions<T>,你只需要用IOptions<T>包装该实例。

Options.Create<T>做这个

创建TOptions实例的包装器,以返回自身为IOptions<TOptions>

public static class Extenions
{
public static TAppSettings AddAppSettings<TAppSettings>(
this IServiceCollection services, TAppSettings appSettings,
) where TAppSettings : class
{
services.AddSingleton(typeof(IOptions<TAppSettings>), Options.Create(appSettings));
return appSettings;
}
}

创建AppSettings实例的注册存在,设置一些属性并调用该扩展方法。

这样一个已经存在的实例的生命周期总是需要是单例的,因为你只需要创建这个实例一次。

var appSettings = new AppSettings();
// Set some properties on appSettings.
services.AddAppSettings(appSettings);

现在你的其他类可以有一个IOptions<AppSettings>实例注入。

这一行

services.Configure<TAppSettings>(options=>options=appSettings);

行不通

你需要构造一个像

这样的Action
public static void AddAppSettings<TAppSettings>(this IServiceCollection services,TAppSettings appSettings)
where TAppSettings : class
{
if (appSettings == null) throw new NullReferenceException(nameof(appSettings));


ParameterExpression paraexpression = Expression.Parameter(appSettings.GetType(), "x");

foreach (var prop in appSettings.GetType().GetProperties())
{
if (prop.PropertyType.Name=="String")
{
ConstantExpression val = Expression.Constant(prop.GetValue(appSettings));
MemberExpression memberexpression = Expression.PropertyOrField(paraexpression, prop.Name);
BinaryExpression assign = Expression.Assign(memberexpression, val);
Expression<Action<TAppSettings>> exp = Expression.Lambda<Action<TAppSettings>>(assign, new ParameterExpression[] { paraexpression });
services.Configure<TAppSettings>(exp.Compile());
}
}
}

基于@pfx答案

我改进了一点,添加了IOptionsMonitor

创建AppSettingsExtensions.cs类:

public static class AppSettingsExtensions
{
public static TAppSettings AddAppSettings<TAppSettings>(this IServiceCollection services,
IConfiguration configuration, string sectionName = "AppSettings",
ServiceLifetime lifetime = ServiceLifetime.Singleton)
where TAppSettings : class
{
var appSettingsSection = configuration.GetSection(sectionName);
var appSettings = appSettingsSection.Get<TAppSettings>();
if (appSettings == null) throw new NullReferenceException(nameof(appSettings));
services.Configure<TAppSettings>(appSettingsSection);
services.Add(new ServiceDescriptor(typeof(TAppSettings), serviceProvider => appSettings, lifetime));
return appSettings;
}
public static TAppSettings AddAppSettings<TAppSettings>(this IServiceCollection services, IConfiguration configuration,
TAppSettings appSettings,
Func<IEnumerable<IOptionsChangeTokenSource<TAppSettings>>> optionsChangeTokenSourceBuilder = null,
ServiceLifetime lifetime = ServiceLifetime.Singleton)
where TAppSettings : class
{
if (appSettings == null) throw new NullReferenceException(nameof(appSettings));
var appSettingsConfigureOptions = configuration.CreateAppSettingsConfigureOptions<TAppSettings>();
appSettingsConfigureOptions.Configure(appSettings);
var appSettingsOptions = Options.Create(appSettings);
var appSettingsMonitor = AddAppSettingsMonitor(services, configuration, appSettingsConfigureOptions);
services.Add(appSettingsOptions,lifetime);
services.Add(appSettingsMonitor, lifetime);
return appSettings;
}
private static IOptionsMonitor<TAppSettings> AddAppSettingsMonitor<TAppSettings>(IServiceCollection services,
IConfiguration configuration, ConfigureFromConfigurationOptions<TAppSettings> appSettingsConfigureOptions)
where TAppSettings : class
{
var appSettingsOptionsFactory = services.CreateAppSettingsOptionsFactory(appSettingsConfigureOptions);
var appSettingsMonitor = new OptionsMonitor<TAppSettings>(appSettingsOptionsFactory,
configuration.CreateAppSettingsOptionsChangeTokenSources<TAppSettings>(), new OptionsCache<TAppSettings>());
return appSettingsMonitor;
}
private static IEnumerable<IOptionsChangeTokenSource<TAppSettings>> CreateAppSettingsOptionsChangeTokenSources<TAppSettings>(this IConfiguration configuration,
Func<IEnumerable<IOptionsChangeTokenSource<TAppSettings>>> builder=null) where TAppSettings : class
{
return builder?.Invoke()??Enumerable.Empty<IOptionsChangeTokenSource<TAppSettings>>();
}
public static ConfigureFromConfigurationOptions<TAppSettings> CreateAppSettingsConfigureOptions<TAppSettings>(this IConfiguration configuration) where TAppSettings : class
{
return new ConfigureFromConfigurationOptions<TAppSettings>(configuration);
}
public static OptionsFactory<TAppSettings> CreateAppSettingsOptionsFactory<TAppSettings>(this IServiceCollection services,ConfigureFromConfigurationOptions<TAppSettings> appSettingsConfigureOptions) where TAppSettings : class
{
return new OptionsFactory<TAppSettings>(new[] {appSettingsConfigureOptions},
Enumerable.Empty<IPostConfigureOptions<TAppSettings>>());
}
}

创建一个DependencyInjectionExtensions.cs类:

public static class DependencyInjectionExtensions
{
public static void Add<TService>(
this IServiceCollection services,
ServiceLifetime serviceLifetime = ServiceLifetime.Scoped)
where TService : class
{
switch (serviceLifetime)
{
case ServiceLifetime.Singleton:
services.AddSingleton<TService>();
break;
case ServiceLifetime.Scoped:
services.AddScoped<TService>();
break;
case ServiceLifetime.Transient:
services.AddTransient<TService>();
break;
default:
throw new ArgumentOutOfRangeException(nameof(serviceLifetime), (object) serviceLifetime, null);
}
}

public static void Add<TService, TImplementation>(
this IServiceCollection services,
ServiceLifetime serviceLifetime = ServiceLifetime.Scoped)
where TService : class
where TImplementation : class, TService
{
switch (serviceLifetime)
{
case ServiceLifetime.Singleton:
services.AddSingleton<TService, TImplementation>();
break;
case ServiceLifetime.Scoped:
services.AddScoped<TService, TImplementation>();
break;
case ServiceLifetime.Transient:
services.AddTransient<TService, TImplementation>();
break;
default:
throw new ArgumentOutOfRangeException(nameof(serviceLifetime), (object) serviceLifetime, null);
}
}
public static void Add<TService>(
this IServiceCollection services,
TService service,
ServiceLifetime serviceLifetime = ServiceLifetime.Singleton)
where TService : class
{
switch (serviceLifetime)
{
case ServiceLifetime.Singleton:
services.AddSingleton<TService>(service);
break;
case ServiceLifetime.Scoped:
services.AddScoped<TService>((Func<IServiceProvider, TService>) (_ => service));
break;
case ServiceLifetime.Transient:
services.AddTransient<TService>((Func<IServiceProvider, TService>) (_ => service));
break;
default:
throw new ArgumentOutOfRangeException(nameof(serviceLifetime), (object) serviceLifetime, null);
}
}
}

我知道这里有很多事情要做,但我的目标是提供一个库来帮助解决项目之间的公共代码,这样我就可以简化一些依赖注入代码。

希望它有帮助,请随时对这段代码提出建议,我将非常感激使这些扩展更好

最新更新