asp.net 如何避免与基类相同的重复派生类构造函数?

tpgth1q7  于 2022-11-19  发布在  .NET
关注(0)|答案(1)|浏览(130)

我正在使用.NET 7 Preview和ASP.NET来 Package 一组WCF服务,使它们成为REST。每个服务都有自己的控制器,我正在使用构造函数的依赖项注入。
每个WCF服务都是自动生成的,它有自己的客户端和几个方法,我在基类(MyBaseController)上使用委托来处理所有的逻辑和事情。
问题是我需要注入的依赖项,但是如果我改变了基构造函数,我必须修改40多个派生类。
下面是我使用的基本概念,但理想情况下,派生类 * 只 * 包含委托重写和提供泛型的类定义。
你可以看到对于派生类A/B,我必须有一个构造函数。

问题

1.有没有另一种不需要在构造函数中声明依赖注入的方法?这将允许我在基类中处理它,然后在派生类中保留一个简单的构造函数。
1.我可以以某种方式继承基构造函数吗?-我不认为旧版本的.NET有这样的功能,所以我希望.NET 7可能会有一些我不知道的新魔法。
1.我是否应该将所有的构造函数需求都转移到一个服务类中,然后将其传递到控制器的任何地方?
编码:

[ApiController]
[Route("[controller]")]
public abstract class MyBaseController<DerivedClient, MyRequest, MyResponse> : ControllerBase
    where DerivedClient : HttpClient, new()
{
    protected DerivedClient _derivedClient;
    protected readonly ILogger _logger;
    public IConfiguration _configuration;
    protected IOptions<MyOptions> _options;

    public abstract Func<MyRequest, Task<MyResponse>> MyClientDelegate { get; }

    protected MyBaseController(ILogger<DerivedClient> logger, IOptions<MyOptions> options, IConfiguration configuration)
    {
        // I need these dependencies though, and with a simple constructor (i.e. MyBaseController()),
        // I can't access them.
        _derivedClient = new();
        _logger = logger;
        _options = options;
        _configuration = configuration;
    }

    [HttpGet, Route("GetTheData")]
    public Task<MyResponse> GetTheData(MyRequest request)
    {
        return MyClientDelegate(request);
    }
}

public class A : MyBaseController<AClient, string, string>
{
    // How can I avoid having this in every derived class when they're all essentially identical?
    public A(ILogger<AClient> logger, IOptions<MyOptions> options, IConfiguration configuration) : base(logger, options, configuration) { }

    // I only want my derived classes to have the delegate
    public override Func<string, Task<string>> MyClientDelegate => _derivedClient.GetDataA;
}
public class B : MyBaseController<BClient, string, string>
{
    // How can I avoid having this in every derived class when they're all essentially identical?
    public B(ILogger<BClient> logger, IOptions<MyOptions> options, IConfiguration configuration) : base(logger, options, configuration){ }

    // I only want my derived classes to have the delegate
    public override Func<string, Task<string>> MyClientDelegate => _derivedClient.GetDataB;
}

public class AClient : HttpClient
{
    public AClient() { }

    public Task<string> GetDataA(string request)
    {
        return Task.FromResult($"A Request: {request}");
    }
}

public class BClient : HttpClient
{
    public BClient() { }

    public Task<string> GetDataB(string request)
    {
        return Task.FromResult($"B Request: {request}");
    }
}
r3i60tvu

r3i60tvu1#

我不认为有一种方法可以避免所有的构造函数都有相同的声明。
我相信这是一个语言设计的决定,因为取决于它是如何实现的,它可能会带来一些其他的问题 *,虽然我觉得有一些其他的方法来做它会很好。
一个可能的改进是将所有依赖项封装在一个新类中,这样就可以在任何地方注入该类。如果出现任何新的依赖项,只需更改该类。
大概是这样的:

public abstract class Base<DerivedClient> : where DerivedClient : HttpClient, new() 
{
    protected DependencyContainer _dependencyContainer;
    protected DerivedClient _derivedClient;

    protected MyBaseController(DependencyContainer<DerivedClient> dependencyContainer)
    {
        _dependencyContainer = dependencyContainer;
        _derivedClient = new();
    }
}

依赖关系容器为:

public class DependencyContainer<DerivedClient> : where DerivedClient : HttpClient
{
    public readonly ILogger<DerivedClient> logger;
    public IConfiguration configuration;
    public IOptions<MyOptions> options;
    
    public DependencyContainer(
        ILogger<DerivedClient> logger,
        IOptions<MyOptions> options,
        IConfiguration configuration,
        ... future new ones)
    {
        this.logger = logger;
        this.options = options;
        this.configuration = configuration;
        ... future new ones
    }
}

每个派生类都将保持如下形式:

public A : Base<AClient>
{
    public A(DependencyContainer<AClient> dependencyContainer) : base(dependencyContainer) { }

    public void Method()
    {
        _dependencyContainer.logger.log(":)");
        _dependencyContainer. ... all other dependencies ...
        _derivedClient.GetDataA("test"); // Method from AClient is accessible because we inherit from Base<AClient>
    }
}

然后,您应该记得将新的DependencyContainer添加到Program.cs中的服务集合:

builder.Services.AddScoped(typeof(DependencyContainer<>), typeof(DependencyContainer<>));

我不喜欢它,但当你想注入新的东西时,它只会让一个类发生变化。

  • 我一直在深入研究这个问题,并在另一个问题中找到了一条评论,该评论链接到一个MSDN帖子,可能会更好地解释这个问题

相关问题