C#自主脚本实现

目的:模板文件中支持程序语言,以便于输出一些数据,而非一般的模板文件替换方案,借此开发自主的MVC模板支持
思路:读取模板文件中的语句块,然后生成真实的C#代码,调用编译器编译并保存,下次直接装载该编译过的类库,支持运行

 

一:模板
确定模板文件中的语句块,采用正则表达式读取
参见如下模板:

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <NXDO.WebUI.Faces>
  3.   <html index="0" des="">
  4.     <![CDATA[
  5.   <table width="100%" border="1">
  6.     
  7.     <@imp="DemoMvcLib.Controllers"/>
  8.     <@server>
  9.         
  10.       List<Class1> lst = (List<Class1>)(${lst});
  11.       int i = 0;
  12.       foreach(Class1 cls in lst)
  13.       {
  14.         ${cls} = cls;
  15.         ${ii} = ++i;
  16.         
  17.     </@server>
  18.         
  19.       <tr>
  20.         <td><@out=${ii}/></td>
  21.         <td><@out=${cls.Name}/></td>
  22.         <td><@out=${cls.Sex}/></td>
  23.       </tr>
  24.       
  25.     <@server>
  26.       }
  27.     </@server>
  28.       
  29.       
  30.   </table>
  31.   ]]>
  32.   </html>
  33.   </NXDO.WebUI.Faces>

得到<@server>与</@server>之间的代码,将 ${cls},类似与这样的变量全部替换成 env["cls"].
env是一个脚本与host之间交换数据的媒介对象,它实现了IDictionary<string, object>接口.

这一段有输出,则直接解释成 String,生成代码时,将<@out=${ii}/>替换成 env.Out("ii");

  1.       <tr>
  2.         <td><@out=${ii}/></td>
  3.         <td><@out=${cls.Name}/></td>
  4.         <td><@out=${cls.Sex}/></td>
  5.       </tr>

Out是env对象的输出方法,env.Out("ii")返回 ii 的值.
Out主要通过传入的字符判断,得到集合中的值并采用反射完成,不带.直接调用集合中的值ToString().
带有.的,则通过反射得到成员的值,记住采用递归调用,可能开发人员输入多个.

 

 

二:生成的代码

  1. [Serializable]
  2. public class default2_FaceHtml1_0 : MarshalByRefObject, IScript
  3. {
  4.     public default2_FaceHtml1_0(ScriptContext env){
  5.         this._env = env;
  6.     }
  7.     public string GetHtml(){
  8.         StringBuilder builder = new StringBuilder();
  9.         List<Class1> list = (List<Class1>) env["lst"];
  10.         int ii = 0;
  11.         foreach (Class1 cls in list)
  12.         {
  13.             env["cls"] = cls;
  14.             env["ii"] = ++ii;
  15.             string str = "<tr>" + 
  16.         "<td>" + env.Out("ii") + "</td>" +
  17.         "<td>" + env.Out("cls.Name") + "</td>" +
  18.         "<td>" + env.Out("cls.Sex") + "</td>" +
  19.         "</tr>";
  20.             builder.AppendLine(str);
  21.         }
  22.         return builder.ToString();
  23.     }
  24.     public override object InitializeLifetimeService(){return null;}
  25.     public ScriptContext env{
  26.         get{
  27.             return this._env;
  28.         }
  29.     }[NonSerialized]ScriptContext _env;
  30. }

说明:继承自MarshalByRefObject,便于在第二次调用时,新建一个AppDomain调用,实现IScript,便于反射得到实例后调用 GetHtml方法
新建一个AppDomain的原因,主要考虑如果模板发生更改,则不装载而是重新编译,替换上一次编译的结果.在新的AppDomain中运行.可以不锁定该DLL加载default2_FaceHtml1_0类,编译以后就可以覆盖.
判断是否需要重新编译脚本的条件为:比较生成的DLL与模板文件的最后一次更新时间


三:编译以上生成的原代码
贴出代码段:

  1. string DyOutName = "Script." + this.className + ".dll";
  2. string DyDllName = Path.Combine(outDllsDir, DyOutName);//outDllsDir编译后保存DLL的路径
  3. CodeDomProvider prov = new CSharpCodeProvider();
  4. CompilerParameters parms = new CompilerParameters();
  5. parms.ReferencedAssemblies.Add("System.dll");
  6. //...其它需要的引用
  7. parms.GenerateInMemory = true;
  8. parms.OutputAssembly = DyDllName;
  9. CompilerResults cr = prov.CompileAssemblyFromSource(parms, sCode);  //sCode为上面产生的代码
  10. Assembly asm = cr.CompiledAssembly;
  11. Type type = asm.GetType("NXDO.WebUI.Script." + this.className); 
  12. IScript iscript = type.GetConstructor(new Type[] { scriptCnxt.GetType() }).Invoke(new object[] { scriptCnxt }) as IScript;  //scriptCnxt就是代码段中的 env 
  13. string sReturnHtml = iscript.GetHtml(); //执行

 

 

四:如果DLL文件存在,则建立新的AppDomain运行
贴出代码段:

  1. if (needCompiler())//比较生成的DLL与模板文件的最后一次更新时间
  2. {
  3.     //调用第三部 {编译以上生成的原代码}
  4.     ...
  5.     return;
  6. }
  7. //直接装载并运行
  8. AppDomainSetup setup = new AppDomainSetup();
  9. setup.ApplicationBase = binPath;
  10. setup...其它属性设置
  11. AppDomain appDomain = AppDomain.CreateDomain("Script Domain"null, setup);
  12. string webuiDll = Path.Combine(binPath, "NXDO.WebUI.dll");  //ScriptAppDomain此类,存在NXDO.WebUI.dll中
  13. ScriptAppDomain scriptDomain = appDomain.CreateInstanceFromAndUnwrap(webuiDll, "NXDO.WebUI.CScriptEngine.ScriptAppDomain"as ScriptAppDomain;
  14. string sReturnHtml = scriptDomain.IScriptExecute(this.scriptDllName, this.className, ctxt)  //ctxt为ScriptContext实例
  15. AppDomain.Unload(appDomain);    //卸载appDomain ,主要为实现HotSwap
  16. IScriptExecute这个方法体的主要代码
  17. class ScriptAppDomain : MarshalByRefObject
  18. {
  19.     public string IScriptExecute(string asmFile, string className, MarshalByRefObject scriptCnxtRefObj)
  20.     {           
  21.         AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);          
  22.         Assembly asm= AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(asmFile));
  23.         ScriptContext scriptCnxt = (ScriptContext)scriptCnxtRefObj;
  24.         Type type = asm.GetType("NXDO.WebUI.Script." + className);
  25.         IScript iscript = type.GetConstructor(new Type[] { scriptCnxt.GetType() }).Invoke(new object[] { scriptCnxt }) as IScript;
  26.         return iscript.GetHtml();
  27.     }
  28. }


五:运行结果示图

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值