简体   繁体   中英

Dependency Injection and Configurations - .NET Core

Creating a standalone project which read JSON and simply response back. Trying to make the best use of dependency injection. However, I've few questions to clarify.

So firstly HomeController is called which has a dependendency on ClassA , so after refactoring ClassA implements IClassA and Updating Startup.cs , HomeController can now successfully use the instance created by the Startup.cs to invoke the method _IClassA.GetOP(data) .

Now I see similar behavior where ClassA has a dependency on ClassB , UtiClass & Document class. So do I need to create Interfaces for all to remove the new keyword used for creating instances.

Again, my primary focus is to retrieve the value of KeysAndValues -> path . So in ClassA constructor I instantiated ClassB and pass the IOptions<KeyAndValue> . Unfortunately, I am unable to get the value of options.path . Please help to clarify my doubts and kindly solve this puzzle. Thank you.

//HomeController
public class HomeController : ControllerBase
    {
        private readonly IClassA _IClassA;
        public HomeController(IClassA iClassA)
            _IClassA = iClassA;

        public string Get(DTO_A data)
            var result = _IClassA.GetOP(data);
}

//INTERFACE
public interface IClassA
        public string GetOP(DTO_A data);

//Class
 public sealed class ClassA : IClassA

        //private readonly IClassB _IClassB; //Cannot Instantiated
        private readonly ClassB _ClassB;
        public ClassA(IOptions<KeysAndValues> options) 
            _ClassB = new ClassB(options);

        Document request = new Document();
        UtiClass objUtiClass = new UtiClass();

        public string GetOP(DTO_A data)
        {
            request.Name = data.Name;
            objUtiClass .Document = request;
           _ClassB.UpdateMethod(objUtiClass );
        }

public class Document : IDocument
    {}

public class ClassC
    {}

Startup.cs

public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<IClassA, ClassA>();
            services.AddControllers();
            services.AddScoped<IClassB, ClassB>();
            services.Configure<KeysAndValues>(Configuration.GetSection("KeysAndValues"));
        }
public class ClassB : IClassB
        private IOptions<KeysAndValues> options;

        public ClassB(IOptions<KeysAndValues> options)
            this.options = options;

        public void UpdateMethod(UtiClass req)
           string fille = Path.Combine(options.path);
        }
public class KeysAndValues
        public string path { get; set; }

Just like how class HomeController requires interface IClassA , class ClassA needs to require interface IClassB . Class ClassB is the one that requires IOptions<KeysAndValues> , because it's ClassB that actually needs the path value.

Now, you don't need to use interfaces at all here. However, I'd recommend using interfaces because it makes your life much easier should you add unit testing.

Here's what it would look like with interfaces.

public class HomeController : ControllerBase
{
    private readonly IClassA _IClassA;
    public HomeController(IClassA iClassA)
    {
        _IClassA = iClassA;
    }
}

public interface IClassA { }
public interface IClassB { }

public class ClassA : IClassA
{
    private readonly IClassB _IClassB;
    public ClassA(IClassB iClassB)
    {
        _IClassB = iClassB;
    }
}

public class ClassB : IClassB
{
    private readonly KeysAndValues options;
    public ClassB(IOptions<KeysAndValues> options)
    {
        this.options = options.Value;
    }
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    
    services.AddTransient<IClassA, ClassA>();
    services.AddTransient<IClassB, ClassB>();
    services.Configure<KeysAndValues>(Configuration.GetSection("KeysAndValues"));
}

If you don't want to use interface, just remove all the interfaces and replace all constructor parameters with the concrete class, and modify ConfigureServices with

services.AddTransient<ClassA>();
services.AddTransient<ClassB>();

I'd recommend AddTransient over AddScoped . Use Scoped only if you need information from the HTTP request/response explicitly in that service. I'd also recommend not having any properties in a service ( Document request and UtiClass objUtiClass ) that are not readonly and set by DI, or you'll need to use AddSingleton and ensure you don't get race conditions (which your current code looks like it will).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM