简体   繁体   English

依赖注入和配置 - .NET 核心

[英]Dependency Injection and Configurations - .NET Core

Creating a standalone project which read JSON and simply response back.创建一个读取 JSON 的独立项目并简单地回复。 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) .所以首先调用了依赖于ClassAHomeController ,因此在重构ClassA实现IClassA并更新Startup.cs之后, HomeController现在可以成功地使用 Startup.cs 创建的实例来调用方法_IClassA.GetOP(data)

Now I see similar behavior where ClassA has a dependency on ClassB , UtiClass & Document class.现在我看到ClassA依赖于ClassBUtiClassDocument class 的类似行为。 So do I need to create Interfaces for all to remove the new keyword used for creating instances.所以我需要为所有人创建接口以删除用于创建实例的new关键字。

Again, my primary focus is to retrieve the value of KeysAndValues -> path .同样,我的主要重点是检索KeysAndValues -> path的值。 So in ClassA constructor I instantiated ClassB and pass the IOptions<KeyAndValue> .因此,在ClassA构造函数中,我实例化了ClassB并传递了IOptions<KeyAndValue> Unfortunately, I am unable to get the value of options.path .不幸的是,我无法获得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启动.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 HomeController需要接口IClassA , class ClassA需要接口IClassB Class ClassB is the one that requires IOptions<KeysAndValues> , because it's ClassB that actually needs the path value. Class ClassB是需要IOptions<KeysAndValues>的,因为实际上需要path值的是ClassB

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如果您不想使用接口,只需删除所有接口并将所有构造函数参数替换为具体的 class,并将ConfigureServices修改为

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

I'd recommend AddTransient over AddScoped .我会推荐AddTransient而不是AddScoped Use Scoped only if you need information from the HTTP request/response explicitly in that service.仅当您需要来自该服务中明确的 HTTP 请求/响应的信息时,才使用 Scoped。 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).我还建议不要在服务( Document requestUtiClass objUtiClass )中包含任何不是readonly且由 DI 设置的属性,否则您将需要使用AddSingleton并确保您不会遇到竞争条件(您当前的代码看起来会的)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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