C# 在运行时列出、加载和实例化App_代码中的未知类
我想在运行时加载并实例化位于我的App_代码文件夹中的类 这些类实现了IModule:C# 在运行时列出、加载和实例化App_代码中的未知类,c#,C#,我想在运行时加载并实例化位于我的App_代码文件夹中的类 这些类实现了IModule: public interface IModule { String Test(); } 测试类: // ~/App_Code/Test.cs namespace ModuleManagementSystem { class Test : IModule { public String Test() { return "Test
public interface IModule
{
String Test();
}
测试类:
// ~/App_Code/Test.cs
namespace ModuleManagementSystem
{
class Test : IModule
{
public String Test()
{
return "Testing! One, two, thee!";
}
}
}
类文件由系统用户上传并作为模块
模块的类名将始终与模块文件名相同。
我正在寻找功能示例代码 我会尽快悬赏。
更新:
namespace ModuleManagementSystem
{
public sealed class Compile
{
public void ToDLL(String sourcefile, String outputfile)
{
var compilerResults =
CodeDomProvider.CreateProvider("CSharp").CompileAssemblyFromFile(
new CompilerParameters {
OutputAssembly = outputfile,
GenerateInMemory = false,
TreatWarningsAsErrors = false,
GenerateExecutable = false,
},
sourcefile
);
}
}
}
上述工程适用于:
// ~/App_Code/Test.cs
public class Test
{
// ...
}
但是如果我实现我的IModule
接口:
namespace ModuleManagementSystem
{
public interface IModule
{
String HelloWorld();
}
}
我得到以下错误:
{c:\inetpub\wwwroot\ModuleManagementSystemWeb\App\u Code\Test.cs(4,21)
:错误CS0246:类型或命名空间
无法指定名称“ModuleManagementSystem”
找不到(您是否缺少一个用户
指令或程序集
参考?}System.CodeDom.Compiler.CompilerError
IModule
接口和Compile
类都位于同一类库中,该类库从web应用程序中引用:
我觉得实际上传到应用程序代码文件夹是个坏主意。我会使用一个单独的文件夹,ASP.NET对此一无所知。这样,您就不会让框架试图为您自动编译代码 您可以轻松地使用-查看示例来编译和运行代码 不过,我希望这只是供内部使用(并且经过验证)——我不建议让不受信任的用户在您的web服务器上执行他们的代码。您可以通过运行代码使其稍微安全一点,这大大减少了权限,但您仍然有代码紧循环等风险 编辑:为了回答更新后的问题,您只需要提供适当的程序集供参考,其中包含
IModule
。请参阅CompilerParameters.ReferencedAssembles
属性
Assembly assembly = Assembly.Load(assemblyName);
IModule instance = assembly.CreateInstance(typeName) as IModule;
您还可以使用该方法创建实例,而无需显式引用程序集。您可以使用反射进行创建,下面是一个非常简单的方法,它将返回传递给函数的模块名[类名]的实例
Public Shared Function GetDALInstance(ByVal moduleClassName As String) As IModule
Dim className As String
dim path as string = <<NamespacePath>>
className = Path + moduleClassName
Return Assembly.Load(Path).CreateInstance(className)
End Function
公共共享函数GetDaInstance(ByVal moduleClassName作为字符串)作为IModule
将类名设置为字符串
作为字符串的dim路径=
className=路径+模块className
返回Assembly.Load(Path).CreateInstance(className)
端函数
上面的方法在vb.net中,您可以简单地将其转换为c#我决定在运行时加载的类必须实现给定的接口,并且类的名称必须与文件名相同 类上载和编译到的文件夹是不相关的。
加载已编译类(.dll)并实例化它:
return (IInterfaceClassesMustImplement)Assembly
/* continued --> */ .LoadFile("c:\...\SomeClass.dll")
/* continued --> */ .CreateInstance("SomeClass");
internal static class Compiler
{
internal static void AssemblyFromFile(
String classFilePath,
String assemblyFilePath,
String[] referencedAssemblies
)
{
var cp = new CompilerParameters { OutputAssembly = assemblyFilePath };
foreach (String ra in referencedAssemblies)
{
cp.ReferencedAssemblies.Add(ra);
}
CompilerResults cr = CodeDomProvider.CreateProvider("CSharp")
/* continued --> */ .CompileAssemblyFromFile(cp, classFilePath);
if (cr.Errors.Count > 0) // throw new Exception();
}
}
编译一个类:
return (IInterfaceClassesMustImplement)Assembly
/* continued --> */ .LoadFile("c:\...\SomeClass.dll")
/* continued --> */ .CreateInstance("SomeClass");
internal static class Compiler
{
internal static void AssemblyFromFile(
String classFilePath,
String assemblyFilePath,
String[] referencedAssemblies
)
{
var cp = new CompilerParameters { OutputAssembly = assemblyFilePath };
foreach (String ra in referencedAssemblies)
{
cp.ReferencedAssemblies.Add(ra);
}
CompilerResults cr = CodeDomProvider.CreateProvider("CSharp")
/* continued --> */ .CompileAssemblyFromFile(cp, classFilePath);
if (cr.Errors.Count > 0) // throw new Exception();
}
}
Jon,ASP.NET提供了声明您自己的生成文件夹的功能。:)不需要手动编译,但我想拥有更多的控制权。特别是,我不希望每次上传新文件时都重新启动应用程序。我还想确保新代码只能访问我想让它知道的应用程序部分。如果是这样的话,是的。这样会更好。我还建议添加一些CAS属性,这些属性明确拒绝访问除真正需要的权限之外的所有权限。@Jon Skeet。更新了我的问题。介意再看一眼吗?:)嗨,丹尼尔。谢谢你的回答。不过,我在名为“Mediator.CreateInstance()”的C#框架中找不到任何内容。你能详细解释一下吗?我写的是Mediator.CreateInstance(),但意思是Activator.CreateInstance()。参考MSDN。组装。负载(“测试”);导致了我这方面的错误。什么例外?安全例外?找不到程序集?“Test”真的是程序集的名称还是仅仅是文件名?我尝试了以下方法:assembly.Load(“Test.cs”)、assembly.Load(MapPath(“~/App\u Code/”)+“Test.cs”),这两种方法都导致找不到程序集