从动态加载的控制器中无法访问静态
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.FriendlyName
和 AppDomain.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上面静态资源无法访问