簡體   English   中英

如何從類中訪問 ASP.NET Core DI 容器

[英]How to access the ASP.NET Core DI Container from within a class

我正在使用 Asp.net 核心學習 IoC 和 DI。 我已經設置了要注入到控制器中的DbContext和其他類。

目前我的 startup.cs 看起來像這樣:

// Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));


services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
    options.Password.RequireDigit = false;
    options.Password.RequiredLength = 5;
    options.Password.RequireNonAlphanumeric = false;
    options.Password.RequireLowercase = false;
    options.Password.RequireUppercase = false;
}).AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

services.AddMvc();

services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));

正如您所看到的,我正在注入 AppSettings 類。 我像這樣訪問這個類沒有問題:

private readonly AppSettings _appSettings;

public HomeController(UserManager<ApplicationUser> userManager, 
    ApplicationDbContext dbContext,
    ViewRender view,
    IHostingEnvironment env,
    IOptions<AppSettings> appSettings
    )
{
}

將它傳遞給控制器​​的構造函數可以正常工作。

但是我需要在一個類中訪問 AppSettings,並且希望有一個靜態方法可以用來將該類注入到任何隨機類中。 這可能嗎? 還是我需要將其注入控制器並將其傳遞給其他類?

防止將IOptions<T>依賴項注入應用程序類。 如此處所描述的那樣,這樣做充滿了問題

同樣,將AppSettings注入類也是一個問題,因為這意味着所有類都獲得了注入的所有配置值,而它們只使用其中的一個或兩個值。 這使得這些類更難測試,並且更難弄清楚這些類實際需要哪個配置值。 它還將配置的驗證推送到您的應用程序內部,這使您的應用程序更加脆弱; 當缺少配置值時,您會在很久以后才發現,而不是找出應用程序何時啟動。

一個類應該在其構造函數中指定它需要的東西,並且不應該通過其他類傳遞這些依賴關系。 這適用於注入的組件和配置值。 這意味着如果一個類需要特定的配置值,它應該在其構造函數中指定該值,並且僅指定該值。

更新

包含您提到的此SendVerification()方法的“電子郵件類”對我來說似乎是一個應用程序組件。 由於該類發送實際郵件,因此需要所有這些郵件配置設置; 不是控制器! 所以這些設置應該直接注入到那個組件中。 但同樣,不要向該類注入任何通用內容(例如IOptions<T>AppSettingsIConfiguration )。 1 盡可能具體地滿足該類的需求; 2. 確保在應用程序啟動時讀取配置值,以便在應用程序啟動時讓應用程序快速失敗。

所以我想你的“郵件類”由一個抽象定義如下:

public interface IVerificationSender
{
    void SendVerification(User user);
}

這允許您的控制器依賴此抽象。 請注意,任何組件都不應創建應用程序組件本身的依賴關系。 這是一種被稱為Control Freak的反模式(參見本書)。

// Controller that depends on the IVerificationSender abstraction
public class HomeController : Controller
{
    private readonly IVerificationSender verificationSender;
    public HomeController(IVerificationSender verificationSender, ...) {
        this.verificationSender = verificationSender;
    }

    public void SomeAction() {
        this.verificationSender.SendVerification(user);  
    }
}

現在我們有一個使用郵件發送消息的IVerificationSender實現(這是你的“郵件類”東西)。 該類伴隨着一個 參數對象,該對象包含該類所需的所有配置值(但絕對僅此而已)。

// Settings class for the IVerificationSender implementation
public class SmtpVerificationSenderSettings
{
    public string MailHost { get; set; }
    public string UserName { get; set; }
    public string Password { get; set; }
    public bool EnableSsl { get; set; }
    // etc
}

public class EmailVerificationSender : IVerificationSender
{
    private readonly SmtpVerificationSenderSettings settings;
    public EmailVerificationSender(SmtpVerificationSenderSettings settings) {
        if (settings == null) throw new ArgumentNullException("settings");
        this.settings = settings;
    }

    public void SendVerification(User user) {
        using (var client = new SmtpClient(this.settings.MailHost, 25)) {
            smtpClient.EnableSsl = this.settings.EnableSsl;
            using (MailMessage mail = new MailMessage()) {
                mail.From = new MailAddress("info@foo", "MyWeb Site");
                mail.To.Add(new MailAddress(user.Email));
                mail.Body = $"Hi {user.Name}, Welcome to our site.";
                client.Send(mail);
            }
        }
    }
}

使用這種方法,控制器和EmailVerificationSender的注冊應該很簡單。 您甚至可以將此SmtpVerificationSenderSettings用作從配置文件加載的可序列化對象:

IConfiguration config = new ConfigurationBuilder()
    .SetBasePath(appEnv.ApplicationBasePath)
    .AddJsonFile("settubgs.json");
    .Build();

var settings = config.GetSection("SmtpVerificationSenderSettings")
    .Get<SmtpVerificationSenderSettings>();

// Verify the settings object
if (string.IsNullOrWhiteSpace(settings.MailHost)
    throw new ConfigurationErrorsException("MailSettings MailHost missing.");
if (string.IsNullOrWhiteSpace(settings.MailHost)
    throw new ConfigurationErrorsException("MailSettings UserName missing.");
// etc

// Register the EmailVerificationSender class
services.AddSingleton<IVerificationSender>(new EmailVerificationSender(settings));

settings.json可能如下所示:

{
    "SmtpVerificationSenderSettings": {
        "MailHost" : "localhost",
        "UserName" : "foobar",
        // etc
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM