从动态加载的控制器中无法访问静态

Posted

技术标签:

【中文标题】从动态加载的控制器中无法访问静态【英文标题】:Statics are inaccessible from within dynamically loaded Controller 【发布时间】:2019-12-04 20:42:00 【问题描述】:

我这里有一个插件系统,用于检查程序集以查找基类的实现。一个基类应该提供一个 API,但是当我点击控制器时,静态变量会忘记它们的值并总是返回它们的默认值。

插件系统像这样创建模块实例:

var assembly = Assembly.LoadFile(@"absolute\path\to\TestModule.dll");
var types = assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(ModuleBase)));

ModuleBase instance = (ModuleBase)Activator.CreateInstance(types.FirstOrDefault());
instance.Execute();

到目前为止效果很好。插件基本类型尽可能小:

    public abstract class ModuleBase
    
        public abstract void Execute();
    

现在我在另一个项目中实现了一个插件:

public class TestModule : ModuleBase

    public static int StaticTest;

    public override void Execute()
    
        StaticTest = 3; // variable is initialized with some non-default value

        WebHost.CreateDefaultBuilder()
               .UseStartup<Startup>()
               .Build()
               .RunAsync(cancellationTokenSource.Token);
     
 

Startup.cs 类如下所示:

public class Startup

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    
        app.UseMvc();
    

    public void ConfigureServices(IServiceCollection services)
    
        services.AddMvc();
    

没什么特别的,真的。但是,当我现在实现一个正在访问我的 StaticTest 变量的控制器时,它的值为 0:

public class TestController : ControllerBase

    [Route("Test")]
    [HttpGet]
    public ActionResult<int> GetStatics()
    
        return TestModule.StaticTest;
    

如果我放弃插件方法,而是直接从控制台应用程序创建WebHost,一切都会按预期工作,并且控制器返回 3。

我怀疑 MVC 会在不同的 AppDomain 中启动控制器,但情况似乎并非如此,因为 AppDomain.CurrentDomain.FriendlyNameAppDomain.CurrentDomain.Id 不会改变,AppDomain.CurrentDomain.DomainUnload 也不会被调用。

欢迎任何想法,我现在完全一无所知,我觉得我错过了整个事情的一些基本概念。

【问题讨论】:

That's working nice so far. Now I implement a plugin for that in a different project: 这个。你的意思是?你怎么知道执行被调用?你有日志吗?您确定(非常非常确定)您引用的 StaticTest 属性是正确的类型,并且不是基类型上类似命名的属性吗?你所描述的似乎是不可能的,所以我会假设发生了什么事。 @A. Chiesa:我确定我引用了来自TestModule 的静态变量,因为该变量未在基本类型中定义。为清楚起见,我已相应地更新了问题。如果我将TestModule 包装到控制台应用程序中并使用new TestModule().Execute() 运行它,一切都会按预期工作。 那么现在的问题是:你怎么知道在MVC中调用了TestModule.Execute方法?您是否在方法内记录(到控制台或您使用的任何记录工具)?你确定找到的类型是TestModule 好吧,既然项目是从Visual Studio启动的,我就简单的在TestModule.Execute设置一个断点。我还调查了加载器中的types(第一个代码sn-p),它确实是一个包含单个TestModule 类型的列表。 真的很尴尬,我用C#已经10多年了,但我完全不知道这里发生了什么。 【参考方案1】:

您有一个名为 Test 的 ivar,并且您正在访问一个名为 StaticTest 的成员,该成员似乎没有被定义。我的假设是您在这个问题中错误命名了 ivar,它应该是 StaticTest,而不是 Test

基于该假设,问题在于您已将动态创建的对象转换为ModuleBase,但StaticTest 存在于TestModule。因此,除非您转换为 TestModule,否则您无法访问 StaticTest,因为这是定义它的位置。

编辑

抱歉,我没有对控制器代码给予足够的关注。真正的问题与上述类似,但与Execute 有关。您还没有显示它的名称,但我假设您将其称为 somewhere 或者为什么静态没有价值的答案将非常明显。但是,如果您的实例键入为ModuleBase,它将调用ModuleBase.Execute(),而不是TestModule.Execute(),即使它实际上是TestModule 实例。只有当您使用实际键入为TestModule 的内容时,才会调用正确的Execute 覆盖。

【讨论】:

感谢@Chris Pratt 指出这一点,我已经相应地编辑了我的问题。写下来的时候就漏掉了。我有一些最小的代码可以隔离问题,并且我错过了一致地重命名变量。缺少的Execute 只是在代码块下方的格式错误。变量已初始化,不会在两者之间被覆盖。

以上是关于从动态加载的控制器中无法访问静态的主要内容,如果未能解决你的问题,请参考以下文章

Safari:重新加载后“由于访问控制检查而无法加载 Fetch API”

spring boot 部署war 到tomcat上面静态资源无法访问

将数据传递给静态表 - 无法访问 TableViewCell 单元格值

无法从 Cordova 中的手机存储访问 CSS

SpringBoot加载静态资源 无法加载js问题

访问 UIScrollView 中动态加载的标签