[英]Applying Dependency Injection when base-class constructor contains arguments
我有一個基本 API 控制器,我希望所有控制器都應請求執行,以充當安全機制。 這是那個控制器
public abstract class SharepointAuthController : ApiController
{
private ClientContext clientContext;
public SharepointAuthController()
: base()
{
ValidateContext();
}
protected void ValidateContext()
{
if (ControllerContext.Request != null)
{
var spContext = SharePointApiControllerContextProvider.Current.GetSharePointContext(ControllerContext);
clientContext = spContext.CreateUserClientContextForSPHost();
if (clientContext == null)
{
throw new AuthenticationException();
}
}
}
protected string GetUserName()
{
User spUser = null;
var spContext = SharePointApiControllerContextProvider.Current.GetSharePointContext(ControllerContext);
using (clientContext = spContext.CreateUserClientContextForSPHost())
{
if (clientContext != null)
{
spUser = clientContext.Web.CurrentUser;
clientContext.Load(spUser, user => user);
clientContext.ExecuteQuery();
return spUser.Email;
}
}
throw new AuthenticationException();
}
}
和一個調用它的控制器
public class CallPointsController : SharepointAuthController
{
private readonly ICallPointRepository _callPointRepository;
public CallPointsController(ICallPointRepository callPointRepository)
{
_callPointRepository = callPointRepository;
}
[SharePointContextFilter]
[HttpGet]
[Route("api/callpoints")]
public List<CallPointDto> Get()
{
string user = base.GetUserName();
if (!string.IsNullOrEmpty(user))
{
return _callPointRepository.ListAll();
}
return null;
}
}
我現在想擴展 SharepointAuthController 以獲取有關用戶的其他信息(存在於 DB 中)。 我希望能夠將存儲庫傳遞給基類的構造函數以獲得正確的 DI,就像這樣
private ClientContext clientContext;
private _repo Repo;
public SharepointAuthController(Repo repo)
: base()
{
ValidateContext();
_repo = repo;
}
protected UserDto GetUserName()
{
User spUser = null;
var spContext = SharePointApiControllerContextProvider.Current.GetSharePointContext(ControllerContext);
using (clientContext = spContext.CreateUserClientContextForSPHost())
{
if (clientContext != null)
{
spUser = clientContext.Web.CurrentUser;
clientContext.Load(spUser, user => user);
clientContext.ExecuteQuery();
return _repo.GetAdditionalUserInfo(spUser.Email);
}
}
throw new AuthenticationException();
}
然而,僅僅這樣做是行不通的,因為調用這個基類的類沒有正確設置
沒有給出與 Repo 所需的形式參數“repo”相對應的參數
我會以正確的方式解決這個問題嗎? 我可以在沒有 DI 的情況下從 Auth 控制器調用 Repo 類
要回答您的問題:
您需要將參數注入繼承的類並將其傳遞給父類:
public class SharepointAuthController
{
public SharepointAuthController(Repo repo)
{
ValidateContext();
_repo = repo;
}
// rest of controller ...
}
public class CallPointsController : SharepointAuthController
{
private readonly ICallPointRepository _callPointRepository;
public CallPointsController(ICallPointRepository callPointRepository, Repo repo)
: base(repo)
{
_callPointRepository = callPointRepository;
}
}
另一方面:要進行身份驗證,最好不要使用基本控制器。 而是創建一個繼承自AuthorizeAttribute
的屬性(例如: SharepointAuthAttribute
)並在其中進行身份驗證。
然后,您可以將該屬性應用於需要它的控制器。
一般不鼓勵使用基類。 常見的說法是:
基類通常是個壞主意,因為:
因此,組合不是使用基類,而是設計系統的更好方法,尤其是應用橫切關注點(例如安全性)的更好方法。
應用橫切關注點的一種典型方式是使用裝飾器。 然而,Web API 使得無法用裝飾器包裝控制器類型。 對於 Web API, 在控制器級別應用橫切關注點的設計模式是使用DelegatingHandler
。
您已向基類的構造函數添加了一個參數:
public SharepointAuthController(Repo repo)
: base()
{
//...
}
但是您沒有在派生類的構造函數中提供該參數:
public CallPointsController(ICallPointRepository callPointRepository)
{
//...
}
需要提供:
public CallPointsController(ICallPointRepository callPointRepository, Repo repo)
: base(repo)
{
//...
}
否則派生類將無法構造基類,因此不能成為基類的實例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.