目前為止設定 DI 都是按照官方的文件設定一下,就放著不理他了。 結果今天踩到一個超級大雷,所以我要鄭重地說:
前提概要
因為我最近都在整合 PayPal 的服務,所以很常要寫程式發 http request
,而我用的則是 RestSharp 這個套件,他是一個只要設定網址、header、body等等…就能夠很輕易地發送 http request
。
根據 PayPal API 的規範,在使用付款或者建立發票等等的 API ,要先去呼叫 OAuth API 取的 token。
所以我程式就這樣設計
- 使用 RestSharp 套件的 RestClient 發送
http request
- PayPalService 使用 RestClient
呼叫 OAuth API 取得 token。
- InvoiceService 使用 RestClient
呼叫發票相關 API 建立發票,而在呼叫建立發票 request 的時後,要傳入 token。
程式範例
為了讓程式能夠更容易了解,我有將原本的程式碼簡化,而這三個類別程式碼如下
PayPalService 與 InvoiceService 都是呼叫 restClient.Url 設定網址,接下來就是發送 request
code- RestClient
- PayPalService
- InvoiceService
1 2 3 4 5 6 7 8 9
| public class RestClient : IRestClient { public string Url { get; set; }
public string SendRequest(RestRequest request) { return $"I use this url:{Url} send request"; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class PayPalService : IPayPalService { private IRestClient _restClient;
public PayPalService(IRestClient restClient) { this._restClient = restClient; }
public string GetToken() { string url = @"https://api.PayPal/GetToken/xxx"; _restClient.Url = url;
var request = new RestRequest(Method.POST); string result = _restClient.SendRequest(request);
return result; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class InvoiceService : IInvoiceService { private IRestClient _restClient; private IPayPalService _payPalService; public InvoiceService( IRestClient restClient, IPayPalService payPalService) { this._restClient = restClient; this._payPalService = payPalService; }
public void CreateInvoice() { string url = @"https://api.PayPal/xxx/invoice"; _restClient.Url = url;
string token = this._payPalService.GetToken();
var request = new RestRequest(Method.POST); request.AddHeader("authorization", $"{token}"); string result = _restClient.SendRequest(request);
} }
|
接下來我有一個 ValuesController
建構式注入 IInvoiceService
, 並且有一個建立發票的API。
ValuesController1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class ValuesController : ApiController { private IInvoiceService _invoiceService; public ValuesController(IInvoiceService invoiceService) { this._invoiceService = invoiceService; } [HttpGet] public IHttpActionResult CreateInvoice() { this._invoiceService.CreateInvoice();
return Ok(); } }
|
程式碼跑執行之網址改變了
為什麼會這樣
因為我 DI 注入的時候使用 InstancePerLifetimeScope
的生命週期
意思是說,只要是同一個 request 就會使用同一個物件 !!!
PayPalService 與 InvoiceService 使用的是同一個 RestClient 物件
所以在取得 Token 的時候,把 InvoiceService 設定好的 Url 覆寫掉了
DI 三種生命週期
- SingleInstance : 整個應用程式都是使用同一個物件
- InstancePerLifetimeScope : 只要是同一個 request 則使用同一個物件
- InstancePerDependency : 只要有注入都是一個全新的物件
所以我只要將 RestClient 注入的生命週期改成 InstancePerDependency
,問題就會解決了。
執行結果
參考
docs.autofac.org