How to access Asp.net Core DI Container from Class

michael

I am learning IoC & DI with Asp.net core. I have setup my dbcontext and other classes to be injected into my controllers. Currently my startup.cs looks like this:

        // 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"));

As you can see amongst other things I am injecting AppSettings class. I have no problem accessing this class like this:

    private readonly AppSettings _appSettings;


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

Passing it into the constructor of a controller works fine.

But I need to access the AppSettings in a class, and was hoping there was a static method I could use to inject the class into any random class. Is this possible? Or do I need to inject it into the controller and pass it to each other class?

Steven

Prevent injecting IOptions<T> dependencies into application classes. Doing so is riddled with problems as described here.

Likewise is the injection of a AppSettings into classes a problem, because this means that all classes get all configuration values injected, while they only use one or two of those values. This makes those classes harder to test, and it becomes much harder to figure out which configuration value such class actually requires. It also pushes the verification of the configuration to inside your application, which makes your application much more fragile; you'll find out much later when a configuration value is missing, instead of finding out when the application is started.

A class should specify the things it requires in its constructor, and should not pass those dependencies around through other classes. This holds for both injected components and configuration values. This means that in case a class requires a specific configuration value, it should specify that -and only that- value in its constructor.

Update

The "email class" that contains this SendVerification() method that you mention, seems like an application component to me. Since that class sends the actual mail, it is the one that requires all those mail configuration settings; not the controller! So those settings should be injected directly into that component. But again, refrain from injecting anything general (such as IOptions<T>, AppSettings or IConfiguration) into that class. 1 Be as specific as possible as what that class needs and 2. make sure configuration values are read at application startup where you can let the application fail fast when the application starts up.

So I imagine your "mail class" to be defined by an abstraction as follows:

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

This allows your controller to take a dependency on this abstraction. Note that no component should create dependencies of application components itself. This is an anti-pattern known as Control Freak (see this book).

// 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);  
    }
}

Now we have a IVerificationSender implementation that uses mail to send messages (that's your "mail class" thingy). That class is companioned by a Parameter Object that holds all the configuration values that this class requires (but absolutely nothing more than that).

// 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);
            }
        }
    }
}

Using this approach, registration of both the controller and the EmailVerificationSender should be trivial. You can even use this SmtpVerificationSenderSettings as serializable object that is loaded from the configuration file:

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));

Where the settings.json might look as follows:

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

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

How DI container knows what Constructors need (ASP.NET Core)?

From Dev

How do I access DataContext from another class in ASP.NET Core?

From Dev

ASP.Net Core docker access serviceA container from serviceB container throws ssl certificate error

From Dev

How to add IHttpContextAccessor in the Startup class in the DI in ASP.NET Core 1.0?

From Dev

Access App key data from class libraries in .NET Core / ASP.NET Core

From Dev

How to access session from a view in ASP .NET Core MVC 1.0

From Java

Resolving instances with ASP.NET Core DI from within ConfigureServices

From Java

How to do DI in asp.net core middleware?

From Dev

Access from class library to appsetting.json in Asp.net-core

From Dev

How to access cookie asp.net core

From Java

How do I access Configuration in any class in ASP.NET Core?

From Dev

MediatR with ASP.NET Core DI

From Dev

ASP.NET Core reflection di

From Dev

ASP.NET Core reflection di

From Dev

How can i access my DI Container configuration file from somewhere?

From Dev

How to use DI inside a static Method in Asp.net Core rc1

From Dev

Why ASP.NET Core DI knows how to resolve ILogger<T>, but not ILogger?

From Dev

ASP.NET MVC - access route parameters from class

From Dev

How to access a method a Spring Bean from a class not in the Spring Container

From Dev

How to access "container" methods from "has-a" (contained) class

From Dev

How to implement Permission Based Access Control with Asp.Net Core

From Dev

How to access the Session in ASP.NET Core via static variable?

From Dev

How to access session in class library .Net Core 5

From Dev

Asp.net core with linux docker container

From Dev

How to add reference of class library project in asp net core project

From Dev

How to create a class extension in asp.net core?

From Dev

How fill custom class in View in asp.net core 2.1

From Dev

Dependency Injection (DI) in ASP.NET Core/MVC 6 ViewModel

From Dev

ASP.NET Core initialize singleton after configuring DI

Related Related

  1. 1

    How DI container knows what Constructors need (ASP.NET Core)?

  2. 2

    How do I access DataContext from another class in ASP.NET Core?

  3. 3

    ASP.Net Core docker access serviceA container from serviceB container throws ssl certificate error

  4. 4

    How to add IHttpContextAccessor in the Startup class in the DI in ASP.NET Core 1.0?

  5. 5

    Access App key data from class libraries in .NET Core / ASP.NET Core

  6. 6

    How to access session from a view in ASP .NET Core MVC 1.0

  7. 7

    Resolving instances with ASP.NET Core DI from within ConfigureServices

  8. 8

    How to do DI in asp.net core middleware?

  9. 9

    Access from class library to appsetting.json in Asp.net-core

  10. 10

    How to access cookie asp.net core

  11. 11

    How do I access Configuration in any class in ASP.NET Core?

  12. 12

    MediatR with ASP.NET Core DI

  13. 13

    ASP.NET Core reflection di

  14. 14

    ASP.NET Core reflection di

  15. 15

    How can i access my DI Container configuration file from somewhere?

  16. 16

    How to use DI inside a static Method in Asp.net Core rc1

  17. 17

    Why ASP.NET Core DI knows how to resolve ILogger<T>, but not ILogger?

  18. 18

    ASP.NET MVC - access route parameters from class

  19. 19

    How to access a method a Spring Bean from a class not in the Spring Container

  20. 20

    How to access "container" methods from "has-a" (contained) class

  21. 21

    How to implement Permission Based Access Control with Asp.Net Core

  22. 22

    How to access the Session in ASP.NET Core via static variable?

  23. 23

    How to access session in class library .Net Core 5

  24. 24

    Asp.net core with linux docker container

  25. 25

    How to add reference of class library project in asp net core project

  26. 26

    How to create a class extension in asp.net core?

  27. 27

    How fill custom class in View in asp.net core 2.1

  28. 28

    Dependency Injection (DI) in ASP.NET Core/MVC 6 ViewModel

  29. 29

    ASP.NET Core initialize singleton after configuring DI

HotTag

Archive