layout: docs-default
依賴注入
這一節(jié)的例子可以看 here
IdentityServer3 有很多擴展點支持不同的服務(wù)。默認的服務(wù)實現(xiàn)設(shè)計成相互解耦,可以獨立替換。為了實現(xiàn)這個目標,我們使用依賴注入來把所有的服務(wù)組裝起來。
注入 IdentityServer 服務(wù)
如果需要,IdentityServer托管程序可以替換默認服務(wù)。自定義的服務(wù)實現(xiàn)也可以使用依賴注入,IdentityServer的類型和用戶自定義的類型都可以注入。注意,注入只支持通過Registration注冊的服務(wù)和存儲。
對于使用IdentityServer類型的自定義服務(wù),可以在構(gòu)造函數(shù)里指定依賴關(guān)系。
當IdentityServer實例化注冊的類型時,構(gòu)造函數(shù)里的參數(shù)會被自動構(gòu)建。比如:
public class MyCustomTokenSigningService: ITokenSigningService
{
private readonly IdentityServerOptions _options;
public MyCustomTokenSigningService(IdentityServerOptions options)
{
_options = options;
}
public Task<string> SignTokenAsync(Token token)
{
// ...
}
}
用如下方法注冊:
var factory = new IdentityServerServiceFactory();
factory.TokenSigningService = new Registration<ITokenSigningService>(typeof(MyCustomTokenSigningService));
或者使用簡化語法:
var factory = new IdentityServerServiceFactory();
factory.TokenSigningService = new Registration<ITokenSigningService, MyCustomTokenSigningService>();
注入自定義服務(wù)
你的自定義服務(wù)可能依賴于你自己的類型。
通過在IdentityServer的依賴注入系統(tǒng)中配置,自定義的類型也可以注入。
通過使用IdentityServerServiceFactory的Register()方法來實現(xiàn),比如:如果需要把自定義的日志服務(wù)注入到自己的服務(wù)里面:
public interface ICustomLogger
{
void Log(string message);
}
public class DebugLogger : ICustomLogger
{
public void Log(string message)
{
Debug.WriteLine(message);
}
}
public class MyCustomTokenSigningService: ITokenSigningService
{
private readonly IdentityServerOptions _options;
private readonly ICustomLogger _logger;
public MyCustomTokenSigningService(IdentityServerOptions options, ICustomLogger logger)
{
_options = options;
_logger = logger;
}
public Task<string> SignTokenAsync(Token token)
{
// ...
}
}
為了注入ICustomLogger,我們需要等級ICustomLogger和MyCustomDebugLogger的關(guān)系:
var factory = new IdentityServerServiceFactory();
factory.TokenSigningService = new Registration<ITokenSigningService, MyCustomTokenSigningService>();
factory.Register(new Registration<ICustomLogger, MyCustomDebugLogger>());
沒有接口的服務(wù)
上面的例子我們注入了 ICustomLogger ,它的實現(xiàn)是 MyCustomDebugLogger.如果自定義服務(wù)沒有設(shè)計成接口實現(xiàn)分離的方式,我們可以直接注冊實體類型來注入。
例如: MyCustomTokenSigningService的構(gòu)造函數(shù)不接受日志接口類型,而是接受日志實體類型。
public class MyCustomTokenSigningService: ITokenSigningService
{
public MyCustomTokenSigningService(IdentityServerOptions options, MyCustomDebugLogger logger)
{
_options = options;
_logger = logger;
}
// ...
}
我們需要把實體類型注入配置成下面的樣子:
var factory = new IdentityServerServiceFactory();
factory.TokenSigningService = new Registration<ITokenSigningService, MyCustomTokenSigningService>();
factory.Register(new Registration<MyCustomDebugLogger>());
簡單說,上面的注冊方式意味著MyCustomDebugLogger實體類會被注入到依賴的服務(wù)中。
自定義類型創(chuàng)建
如果自定義服務(wù)需要手動構(gòu)建(比如有些特殊的參數(shù)必須自己配置,不能依賴于注入),這時候,我們可以用Registration類,傳入一個工廠回調(diào)函數(shù),這個Registration構(gòu)造方法前面如下:
new Registration<T>(Func<IDependencyResolver, T> factory)
這個回調(diào)函數(shù)必須返回一個實現(xiàn)T接口的對象,如下代碼:
var factory = new IdentityServerServiceFactory();
factory.TokenSigningService = new Registration<ITokenSigningService>(resolver =>
new MyCustomTokenSigningService("SomeSigningKeyValue")
);
獲取其它依賴
上面的方法已經(jīng)很靈活啦,但是你可能需要更精巧的依賴注入。比如你可能依賴于其它服務(wù)。這時候IDependencyResolver開始展現(xiàn)威力啦。它允許你從回調(diào)函數(shù)中取到服務(wù)。比如,你自定義的客戶端存儲依賴于來自IdentityServer的另一個服務(wù),他可以用下面的方式來得到:
var factory = new IdentityServerServiceFactory();
factory.TokenSigningService = new Registration<ITokenSigningService>(resolver =>
new MyCustomTokenSigningService("SomeSigningKeyValue", resolver.Resolve<ICustomLogger>())
);
命名依賴
最后,當我們通過IdentityServerServiceFatory的Register()方法注冊依賴時,我們可以給這個依賴名字。這個名字通過Registeration構(gòu)造函數(shù)的name參數(shù)來指定。這個只用于自定義注冊的以來,這個名字也只能在自定義服務(wù)里面,使用IDependencyResolver方法解決依賴時使用。
命名依賴在一個T接口有多個實現(xiàn)時特別有用,比如:
string mode = "debug"; // or "release", for example
var factory = new IdentityServerServiceFactory();
factory.Register(new Registration<ICustomLogger, MyFileSystemLogger>("debug"));
factory.Register(new Registration<ICustomLogger, MyDatabaseLogger>("release"));
factory.TokenSigningService = new Registration<ITokenSigningService>(resolver =>
new MyCustomTokenSigningService(resolver.Resolve<ICustomLogger>(mode))
);
這個例子中mode做為配置項,決定了運行的時候到底使用哪一個ICustomLogger具體實現(xiàn)。
注冊模式的實例化
Registration 類允許服務(wù)指定一個服務(wù)有多少個實例可以創(chuàng)建,Mode屬性是一個枚舉,可選值如下:
-
InstancePerHttpRequest
每次請求創(chuàng)建一個實例。這意味著如果服務(wù)在一次請求中,申請了兩次某個依賴,會得到同樣的實例。 -
InstancePerUse
為服務(wù)里每次獨立的請求創(chuàng)建一個實例。也就是說如果自定義服務(wù)在不同的代碼段請求了某個依賴,那么會得到不同的實例。 -
Singleton
只有一個實例會被創(chuàng)建。當傳給Registration構(gòu)造函數(shù)一個單例對象的時候,這個模式會自動啟用。