【问题标题】:ASP.NET (Core)'s zombie virus of 'public': can controllers be internal? [closed]ASP.NET (Core) 的“公共”僵尸病毒:控制器可以是内部的吗? [关闭]
【发布时间】:2021-01-17 18:10:04
【问题描述】:

上下文是 ASP.NET Core。

请考虑以下最小设置。

public class ExampleController : ControllerBase
{
   public ExampleController(IExempleService exampleService)
   {

(...)

public interface IExampleService
{
   ExampleStruct Foo();
}

public readonly struct ExampleStruct (...)
public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IInverterService, InverterService>();

这里有一个宣传链。

  1. 控制器必须是公共的;可以被发现。 公平。
  2. 控制器的构造函数必须是公共的;让框架实例化它。 这就是生活。
  3. 服务接口必须是公共的,因为控制器的构造函数是公共的。 悲伤。
  4. 服务类型(例如 ExampleStruct)必须是 public,因为接口是公共的。 我觉得恶心。

这样做有实际的后果:

  • 文档,我正在记录实际上是内部但技术上公开的类,其中包含将变得过时的毫无意义的 cmets。
  • 公共类型有更多的责任。例如,内部结构不需要提供相等性,但当它是公共的时它应该提供。

我想这里有两个问题:

  • 最终会为这种公共访问的僵尸病毒找到结构性解决方案吗?
  • 是我做错了吗,现在有好的解决方案吗?

单元测试和internalInternalsVisibleToAttribute 一起使用。

【问题讨论】:

  • 可以使您的控制器内部化,您只需使用ControllerFeatureProvider 使其可被发现@看看这个stackoverflow.com/a/50906593/1612975
  • @MichaelRandall 这很有趣。我不是OP,但感谢您的链接! :)
  • @MichaelRandall 您能否将您的评论作为答案,我将添加我的设置MyControllerFeatureProvider。或者,如果您更喜欢只做一个简短的回答,我会将我的答案发布在旁边并接受您的回答。我希望将功劳归于您,而不是我发布答案并将其标记为已接受。

标签: c# .net asp.net-core dependency-injection scope


【解决方案1】:

所有功劳都应归功于@MichaelRandall:

可以将您的控制器设置为内部控制器,您只需使用 ControllerFeatureProvider 使它们可被发现,看看这个 stackoverflow.com/a/50906593/1612975 – Michael Randall


public void ConfigureServices(IServiceCollection services)
{
    (...)
    services
        .AddControllers(options => ...)
        .ConfigureApplicationPartManager(manager =>
        {
            manager.FeatureProviders.Add(new MyControllerFeatureProvider());
        })
     
(...)   

internal class MyControllerFeatureProvider : ControllerFeatureProvider
{
    protected override bool IsController(TypeInfo typeInfo)
    {
        // https://source.dot.net/#Microsoft.AspNetCore.Mvc.Core/Controllers/ControllerFeatureProvider.cs,41
        // contains
        // 
        // // We only consider public top-level classes as controllers. IsPublic returns false for nested
        // // classes, regardless of visibility modifiers
        // if (!typeInfo.IsPublic)
        // {
        //   return false;
        // }

        if (typeInfo.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) &&
            typeInfo.IsDefined(typeof(ApiControllerAttribute)))
        {
            System.Diagnostics.Debug.WriteLine($"Found controller '{typeInfo.Name}'");
            return true;
        }

        if (typeInfo.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase))
        {
            System.Diagnostics.Debug.Fail($"Found class that ends in 'Controller' but will not be registered as a controller: {typeInfo.Name}");
        }

        return false;
    }
}

【讨论】:

    【解决方案2】:

    可以让你的控制器internal,你只需要用@让他们可发现 987654321@

    ApplicationPart 实例列表中发现控制器。

    在 Asp.Net Core 中有 4 种方式定义控制器:

    1. 从 ControllerBase 类继承
    2. 定义一个名称包含“Controller”后缀的控制器。
    3. 使用控制器属性定义
    4. 定义自定义控制器类型类

    对于internal 控制器的情况最重要的是最后一点(定义自定义控制器类型)。

    要做到这一点,你需要

    • 实施ControllerFeatureProvider
    • 覆盖 IsController 并为您的类型的可发现性实现任何逻辑

    例如

    internal class MyControllerFeatureProvider : ControllerFeatureProvider
    {
        protected override bool IsController(TypeInfo typeInfo)
        {
            ...
    
    • 通过FeatureProviders 将其添加到ConfigureApplicationPartManager

    例如

    .ConfigureApplicationPartManager(manager =>
    {
        manager.FeatureProviders.Add(YourControllerFeatureProvider)
        ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-24
      • 1970-01-01
      • 2014-07-19
      • 1970-01-01
      • 1970-01-01
      • 2011-03-14
      相关资源
      最近更新 更多