0

I'm now trying DI in ASP.NET Core.
I created a singleton object, and saved some application information to it.
I could inject Dependency into constructors, razor pages and repositories but don't know how to inject into entity.

MyConfig.cs:

  public interface IMyConfig
  { ... }
  
  public class MyConfig:IMyConfig
  {
    public MyConfig() {}

    public string CompanyName { get { return _companyName; } }
    public string ContactEMail { get { return _contactEmail; } }
  }

program.cs:

builder.Services.AddSingleton<IMyConfig, MyConfig>();  // application information
builder.Services.AddSingleton<IMyRep, MyRep>();        // my repository

Repositories.cs:

  public interface IMyRep
  {
    public string GetCompanyName();
    public IEnumerable<IUser> GetUsers();
  }

  public class MyRep : IMyRep
  {
    private readonly DbContext _context;
    private readonly MyConfig _config;

    public MyRep(DbContext context, MyConfig config)
    {
      _context = context;
      _config = config;
    }

    public string GetCompanyName() { return _config.CompanyName; }
    public string GetContactEmail() { reutnr _config.ContactEmail; }

    public GetUsers()
    {
      _context.Users.Select(m => m);
    }
  }

All above codes worked.

In addtion to above, I want to inject MyConfig to User entity.
It contains specific MyConfig information in User, like following.

user.cs:

public interface IUser
{
  public int Id { get;set; }
  public string Name { get;set; }
  public string Company { get; }
}
public class User: IUser
{
  private readonly IMyConfig _config;
  public User(IMyConfig config)
  {
    _config = config;
  }
  public int Id { get;set; }
  public string Name { get;set; }
  public string Company { get { return _config.CompanyName; } }
}
 

Although I was tried to implement following code in program.cs, didn't work.

builder.Services.AddSingleton<IUser, User>();

Can I inject the object into the entity?

hiks
  • 59
  • 1
  • 8
  • 1. when doing DI, you need to use the interface. In first "working" example however, you are using the `MyConfig` instead of `IMyConfig`. 2. in your second exaple Interface has the same name as the class. Do I understand it correctly that it is upposed to be `IUser` and `User` should implement `IUser` ? – StyleZ Oct 17 '22 at 08:55
  • if that is the case, I think that registering only user will not be enough, since it needs to get the `IMyConfig` from somewhere. However, I recommend to read the following -> https://stackoverflow.com/a/38139500/9559884 to see, whether AddSingleton is really something that you want (based the properties inside, it is not) – StyleZ Oct 17 '22 at 09:01
  • I think the `Company` property should be removed from the `User` entity and `config` should not be passed to it. You should make another class, something like `UserModel` or `UserDTO`. And inject `config` into it and map `User` to this additional class. – Alexander Petrov Oct 17 '22 at 11:31
  • Thank you both. Sorry, I had written some mistakes in the code here. Of course I know that DI needs a class and a interface and both have to have different name. In any way, I understood it's hard to make up this solution. I'll try Alexander's suggestion. – hiks Oct 18 '22 at 02:07
  • I have a problem with the code you say works. Dependency injection should use interface but you are using implementation method in `Repositories` which is wrong. Also, the registration service is determined by the lifecycle, I think `AddScoped` should be used, not `AddSingleton`. – Chen Oct 18 '22 at 09:31
  • The way you are injecting `MyConfig` into the `User` entity is correct. Please take a look at the problem pointed out by my last comment, in my code I can pass `MyConfig.CompanyName` to `User.Company`. – Chen Oct 18 '22 at 09:35
  • Thanks Chen. Where is your code you pointed out? – hiks Oct 19 '22 at 00:20
  • I pointed it out in my first comment, I just added the corresponding code below as well. You can see if this is the result you want. @hiks – Chen Oct 19 '22 at 01:20

1 Answers1

0

I will provide a simple example based on your code and point out the problem in your code:

MyConfig.cs:

public interface IMyConfig
    { 
        string CompanyName { get; }
        string ContactEMail { get; }
    }

    public class MyConfig : IMyConfig
    {
        public MyConfig() { }

        public string CompanyName { get { return "Company"; } }
        public string ContactEMail { get { return "Email"; } }
    }

Repositories.cs:

When injecting MyConfig, the interface IMyConfig should be injected, not the implementation method.

public interface IMyRep
    {
        public string GetCompanyName();
        public string GetContactEmail();
        public IEnumerable<IUser> GetUsers();
    }

    public class MyRep : IMyRep
    {
        private readonly MyDbContext _context;
        private readonly IMyConfig _config;

        public MyRep(MyDbContext context, IMyConfig config)
        {
            _context = context;
            _config = config;
        }

        public string GetCompanyName() { return _config.CompanyName; }
        public string GetContactEmail() { return _config.ContactEMail; }

        public IEnumerable<IUser> GetUsers()
        {
            return _context.Users.Select(m => m);
        }
    }

user.cs:

public interface IUser
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Company { get; }
    }
    public class User : IUser
    {
        private readonly IMyConfig _config;
        public User(IMyConfig config)
        {
            _config = config;
        }
        public int Id { get; set; }
        public string Name { get; set; }
        public string Company { get { return _config.CompanyName; } }
    }

program.cs:

IMyConfig,IMyRep, IUser should be registered as Scoped.

builder.Services.AddScoped<IMyConfig, MyConfig>(); 
builder.Services.AddScoped<IMyRep, MyRep>();
builder.Services.AddScoped<IUser, User>();

Then I can successfully pass MyConfig.CompanyName to User.Company:

public class HomeController : Controller
{
    private readonly IUser _user;
    public HomeController(IUser user)
    {
        _user = user;
    }
    public IActionResult Index()
    {
        var Company = _user.Company;
        return View();
    }
}

enter image description here

Is this what you expected?

Chen
  • 4,499
  • 1
  • 2
  • 9
  • Thanks. Good solution. It seems my problem has soluted. I'm grateful to you. – hiks Oct 19 '22 at 06:46
  • It won't work anyway. A DI container cannot inject dependencies into objects that it does not create itself. In the `GetUsers()` method objects returned from this expression: `_context.Users.Select(m => m);` will not have the set value `IMyConfig`. @hiks – Alexander Petrov Oct 20 '22 at 13:40
  • [Injecting services](https://learn.microsoft.com/en-us/ef/core/modeling/constructors#injecting-services). @hiks – Alexander Petrov Oct 20 '22 at 18:38