当前访客身份:游客 [ 登录 | 加入开源中国 ]

代码分享

当前位置:
代码分享 » C#  » 常用工具方法
分享到: 
收藏 +0
2
重构就是设计。

逃脱Asp.Net MVC框架的枷锁,使用Razor视图引擎》其实写的很早,把它用到项目中之后,已经有很多的改变了。只到最近的一次重构,才敢说基本是洁净的代码。

标签: eLiteWeb

代码片段(6) [全屏查看所有代码]

1. [代码]对Stream进行编译的 Compiler接口定义     跳至 [1] [2] [3] [4] [5] [6] [全屏预览]

using System;
using System.IO;

namespace Skight.Arch.Presentation.Web.Core.ViewEngins.TemplateProvider
{
    public interface Compiler
    {
        Type compile_template(Stream stream);
        Type compile_template<T>(Stream stream);
    }
}

2. [代码]对磁盘文件编译的 FileCompiler接口定义     跳至 [1] [2] [3] [4] [5] [6] [全屏预览]

using System;

namespace Skight.Arch.Presentation.Web.Core.ViewEngins.TemplateProvider
{
    public interface FileCompiler
    {
        Type compile_template<T>(string path);
        Type compile_template(string path);
    }
}

3. [代码]文件编译器的实现,内部使用Stream的Compiler.(组合模式)     跳至 [1] [2] [3] [4] [5] [6] [全屏预览]

using System;
using System.IO;
using Skight.Arch.Domain.Containers;

namespace Skight.Arch.Presentation.Web.Core.ViewEngins.TemplateProvider
{
    [RegisterInContainer(LifeCycle.singleton)]
    public class FileCompilerImpl :FileCompiler
    {
        private Compiler internal_compiler;

        public  FileCompilerImpl(Compiler internalCompiler)
        {
            internal_compiler = internalCompiler;
        }

        protected FileCompilerImpl()
        {
        }

        public virtual  Type compile_template<T>(string path)
        {
            return internal_compiler.compile_template<T>(new FileStream(path, FileMode.Open, FileAccess.Read));
        }

        public virtual Type compile_template(string path) 
        {
           return internal_compiler.compile_template(new FileStream(path, FileMode.Open, FileAccess.Read));
        } 
    }
}

4. [代码]缓冲文件编译器,同样是对文件编译器的实现。可以通过Decorator模式,联合上面文件编译器使用     跳至 [1] [2] [3] [4] [5] [6] [全屏预览]

using System;
using System.Collections.Concurrent;
using Skight.Arch.Domain.Containers;

namespace Skight.Arch.Presentation.Web.Core.ViewEngins.TemplateProvider
{
    [RegisterInContainer(LifeCycle.singleton)]
    public class CachedFileCompiler:FileCompiler
    {
        //cache of already compiled types
        ConcurrentDictionary<Tuple<string, Type>, Type> cache = new ConcurrentDictionary<Tuple<string, Type>, Type>();
        ConcurrentDictionary<string, Type> cache_for_no_model = new ConcurrentDictionary<string, Type>();

        private FileCompilerImpl internal_compiler;

        public CachedFileCompiler(FileCompilerImpl internalCompiler)
        {
            internal_compiler = internalCompiler;
        }

        public Type compile_template<T>(string path)
        {
            var key = Tuple.Create(path, typeof(T));
            Type type;

            if (!cache.TryGetValue(key, out type)) 
            {
                type =internal_compiler.compile_template<T>(path);
                cache[key] = type;
            }
            return type;
        }

        public Type compile_template(string path) 
        {
            Type type;
            if (!cache_for_no_model.TryGetValue(path, out type)) {
                type =internal_compiler.compile_template(path);
                cache_for_no_model[path] = type;
            }
           return type;
        }  
    }
}

5. [代码]模板生成器,依赖上面的文件编译器。也是,整个Razor编译器的入口。     跳至 [1] [2] [3] [4] [5] [6] [全屏预览]

using System;
using System.Collections;
using Skight.Arch.Domain.Containers;

namespace Skight.Arch.Presentation.Web.Core.ViewEngins.TemplateProvider
{
    [RegisterInContainer(LifeCycle.singleton)]
    public class TemplateGenerator
    {
        private CachedFileCompiler internal_compiler;

        public TemplateGenerator(CachedFileCompiler internalCompiler)
        {
            internal_compiler = internalCompiler;
        }

        public TemplateBase<T> generate<T>(T model, IDictionary context, string path)
        {
            var type= internal_compiler.compile_template<T>(path);
            var instance = (TemplateBase<T>)Activator.CreateInstance(type);
            instance.Path = path;
            instance.Model = model;
            instance.Context = context;
            instance.Url = new UrlHelper(context);
            instance.Decoder = new DecodingHelper(context);
            return instance;
        }

        public TemplateBase generate(IDictionary context, string path) {
            var type = internal_compiler.compile_template(path);
            var instance = (TemplateBase)Activator.CreateInstance(type);
            instance.Path = path;
            instance.Context = context;
            instance.Url = new UrlHelper(context);
            instance.Decoder = new DecodingHelper(context);
            return instance;
        }
    }
}

6. [代码]最后一个, 真正的Razor Compiler。因为,大部分代码和原来的博客内容差不多,所以放在最后。     跳至 [1] [2] [3] [4] [5] [6] [全屏预览]

using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Linq;
using System.Web.Configuration;
using System.Web.Razor;
using System.Web.Razor.Generator;
using System.Web.Razor.Parser;
using Microsoft.CSharp;
using Skight.Arch.Domain.Containers;

namespace Skight.Arch.Presentation.Web.Core.ViewEngins.TemplateProvider.Razor
{
    [RegisterInContainer(LifeCycle.singleton)]
    public class RazorCompiler : Compiler
    {

        public Type compile_template(Stream stream)
        {
           return compile(stream, typeof (TemplateBase));
        }
        public Type compile_template<T>(Stream stream)
        {
            return compile(stream, typeof (TemplateBase<T>));
        }

        private Type compile(Stream stream,Type base_type)
        {
            var key = "c" + Guid.NewGuid().ToString("N");

            var parser = new HtmlMarkupParser();

            var host = new RazorEngineHost(new CSharpRazorCodeLanguage(), () => parser)
            {
                DefaultBaseClass = base_type.FullName,
                DefaultClassName = key,
                DefaultNamespace = "Skight.Arch.Presentation.Web.Core.ViewEngins.Razor.dynamic",
                GeneratedClassContext = new GeneratedClassContext("Execute", "Write", "WriteLiteral", "WriteTo", "WriteLiteralTo", "tinyweb.viewengine.razor.RazorCompiler.TemplateBase")
            };

            //always include this one

            host.NamespaceImports.Add("Skight.Arch.Presentation.Web.Core.ViewEngins");
            host.NamespaceImports.Add("System");

            //read web.config pages/namespaces
            if (File.Exists("\\web.config")) {
                var config = WebConfigurationManager.OpenWebConfiguration("\\web.config");
                var pages = config.GetSection("system.web/pages");
                if (pages != null) {
                    PagesSection pageSection = (PagesSection)pages;
                    for (int i = 0; i < pageSection.Namespaces.Count; i++) {
                        //this automatically ignores namespaces already added
                        host.NamespaceImports.Add(pageSection.Namespaces[i].Namespace);
                    }
                }
            }

            CodeCompileUnit code;
            using (var reader = new StreamReader(stream)) {
                var generatedCode = new RazorTemplateEngine(host).GenerateCode(reader);
                code = generatedCode.GeneratedCode;
            }

            var @params = new CompilerParameters
            {
                IncludeDebugInformation = false,
                TempFiles = new TempFileCollection(AppDomain.CurrentDomain.DynamicDirectory),
                CompilerOptions = "/target:library /optimize",
                GenerateInMemory = false
            };

            var assemblies = AppDomain.CurrentDomain
               .GetAssemblies()
               .Where(a => !a.IsDynamic)
               .Select(a => a.Location)
               .ToArray();

            @params.ReferencedAssemblies.AddRange(assemblies);

            var provider = new CSharpCodeProvider();
            var compiled = provider.CompileAssemblyFromDom(@params, code);

            if (compiled.Errors.Count > 0) {
                var compileErrors = string.Join("\r\n", compiled.Errors.Cast<object>().Select(o => o.ToString()));
                throw new ApplicationException("Failed to compile Razor:" + compileErrors);
            }

            return compiled.CompiledAssembly.GetType("Skight.Arch.Presentation.Web.Core.ViewEngins.Razor.dynamic." + key);
        }
    }
}


开源中国-程序员在线工具:Git代码托管 API文档大全(120+) JS在线编辑演示 二维码 更多»

发表评论 回到顶部 网友评论(5)

  • 1楼:优雅先生 发表于 2012-12-06 18:40 回复此评论
    楼主,分享不错,收藏了。顺便问下你的图是用啥工具画的呢?挺不错的。
  • 2楼:予沁安 发表于 2012-12-06 18:42 回复此评论

    引用来自“jxqlovejava”的评论

    楼主,分享不错,收藏了。顺便问下你的图是用啥工具画的呢?挺不错的。
    Yuml.me
  • 3楼:kiyeer 发表于 2012-12-07 20:17 回复此评论
    楼主能弄一个具体完整的实现就好了。看过你上篇关于MVC的博文。你让我看eliteWeb项目,我下载来看了,没有具体关于Razor脱离MVC方面的内容。
  • 4楼:予沁安 发表于 2012-12-07 23:43 回复此评论

    引用来自“kiyeer”的评论

    楼主能弄一个具体完整的实现就好了。看过你上篇关于MVC的博文。你让我看eliteWeb项目,我下载来看了,没有具体关于Razor脱离MVC方面的内容。
    哦,你是说,MVC的实现部分,有一些,不过还没有完全串起来。完成之后,第一时间通知你?
  • 5楼:kiyeer 发表于 2012-12-08 09:33 回复此评论

    引用来自“予沁安”的评论

    引用来自“kiyeer”的评论

    楼主能弄一个具体完整的实现就好了。看过你上篇关于MVC的博文。你让我看eliteWeb项目,我下载来看了,没有具体关于Razor脱离MVC方面的内容。
    哦,你是说,MVC的实现部分,有一些,不过还没有完全串起来。完成之后,第一时间通知你?
    是的,就是MVC的实现部分!感谢!