[英]C# ASP.NET Core alternative to an extension method to register services
我的 AspNet Core 應用程序有問題,我有一個擴展方法來在外部庫上注冊配置,如示例所示:
public static AuthenticationBuilder AddSaml2PIdP(this AuthenticationBuilder builder, SamlSettings settings)
{
foreach (var idP in settings.IdPs)
{
builder.AddSaml2p(idP.Scheme, options =>
{
options.ServiceProviderOptions = SpOptionsHelper.GetSpOptions(settings);
....
}
}
return builder;
}
在啟動 class 中,在 ConfigureServices 中我這樣調用此方法:
var samlSettings = _configuration.GetSection(SamlSettings.SamlSection).Get<SamlSettings>();
services.AddAuthentication()
.AddSaml2PIdP(samlSettings);
現在不幸的是我不得不進行一些更改,所以我需要注入依賴項才能在 class 中執行其他操作,所以我不能再使用 static class:也不能使用擴展方法
public class Saml2PExtension
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public Saml2PExtension(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = serviceScopeFactory;
}
public void AddSaml2PIdP()
{
using var scope = _serviceScopeFactory.CreateScope();
var settings = scope.ServiceProvider.GetRequiredService<SamlSettings>();
var metadataParser = scope.ServiceProvider.GetRequiredService<ISamlMetadataParser>();
var environment = scope.ServiceProvider.GetRequiredService<IWebHostEnvironment>();
var builder = scope.ServiceProvider.GetRequiredService<AuthenticationBuilder>();
foreach (var idP in settings.IdPs)
{
builder.AddSaml2p(idP.Scheme, options =>
{
options.ServiceProviderOptions = SpOptionsHelper.GetSpOptions(settings);
....
}
}
}
}
但是我應該如何在 ConfigureServices 方法中注冊這個 class 並調用 configure 方法?
使用新的實現,我不是將 ServiceProvider 用作 ServiceLocator 反模式嗎?
也歡迎可以以更優雅的方式解決問題的替代解決方案。
謝謝
** 編輯 **
最后,我選擇保留第一個核心代碼片段,在擴展方法中添加 IWebHostEnvironment 參數並手動實例化 SamlMetadataParser,如下所示:
public static AuthenticationBuilder AddSaml2PIdP(this AuthenticationBuilder builder, IWebHostEnvironment environment, SamlSettings settings)
{
var metadataParser = new SamlMetadataParser(new ...); // manually create object
foreach (var idP in settings.IdPs)
{
builder.AddSaml2p(idP.Scheme, options =>
{
options.ServiceProviderOptions = SpOptionsHelper.GetSpOptions(settings);
// Read metadata from file ...
var idPOptions = metadataParser.Pars(xml);
........
}
}
return builder;
}
由於我在作曲根,我認為這種方法是正確的。
無論如何感謝您的幫助
這可以通過構建您自己的(使用過的)容器來獲取您的注冊服務來實現。 您可以保留您的擴展方法,因為我們通過AuthenticationBuilder
公開了一個IServiceCollection
,這非常方便:
public static AuthenticationBuilder AddSaml2PIdP(this AuthenticationBuilder builder,
SamlSettings settings)
{
using var scope = builder.Services.BuildServiceProvider().CreateScope();
//get the services
var settings = scope.ServiceProvider.GetRequiredService<SamlSettings>();
var metadataParser = scope.ServiceProvider.GetRequiredService<ISamlMetadataParser>();
var environment = scope.ServiceProvider.GetRequiredService<IWebHostEnvironment>();
var builder = scope.ServiceProvider.GetRequiredService<AuthenticationBuilder>();
//start using the services
foreach (var idP in settings.IdPs)
{
builder.AddSaml2p(idP.Scheme, options =>
{
options.ServiceProviderOptions = SpOptionsHelper.GetSpOptions(settings);
....
}
}
return builder;
}
請注意,這是可能的,但您需要關心您使用的服務所需的所有依賴項的注冊順序。 實際上,您可以將AddAuthentication
放在ConfigureServices
的末尾以確保它始終成功。 但是如果有什么問題,就會拋出異常,我們可以相應地調整順序。
更新:
關於可能與 IdentityServer4 中的IdpOptions
一起使用的后配置(供 OP 試用):
services.AddOptions<IdpOptions>()
.Configure((IdpOptions o,
SamlSettings settings,
ISamlMetadataParser metadataParser,
IWebHostEnvironment environment,
AuthenticationBuilder builder) => {
//use your services here to configure next ...
});
實際上,上面使用OptionsBuilder
,它支持一種最多注入 5 個依賴項的方法。 您可以改用實現IConfigureOptions<IdpOptions>
或IPostConfigureOptions<IdpOptions>
的單獨 class 。 然后只需使用services.ConfigureOptions<TImplementation>()
對其進行配置。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.