逃げるNet MVCフレームワークの枷、Razorビューエンジンを使用


その他の背景は前伝を参照:Razorビューエンジンの浅い分析の後続:eLiteWebフレームワークMVC(Model-View-Command)メカニズムの解析


 

どうしてそうするの?


1.  Asp.Net MVCも実はあまりよくありません.私は自分の敏捷なWebフレームワークを持っていて、依然としてRazorエンジンを使いたいです.ダイナミックコンパイルはとても面白くて、これも将来の1つのトレンドで、もし誰かが興味があれば、私はこの方面の内容を書きたいです.しかし、このような考えを持っている人は多くなく、探しに来て、この方面の資料と論述は極めて少ない.淵に臨んで魚をうらやましがるより,引き下がって網を結んだほうがましだ.自分で手を出して,衣食を豊かにする.
Razorエンジンの概要に記載されているように、Razorの2つの主要な機能、テンプレートファイル、動的コンパイラ.私たちは単純にこの2つの主要な特性だけを必要とすることができますか?他のスマートビューファイルなどは、ゴミとは言えないが、手足を縛る枠でもあり、私は完全に自分で作ることができ、失ったのはロープで、手に入れるのは世界全体だ.テンプレート機能を維持し、特に設計時のインテリジェント文法サポートは簡単で、プロジェクト作成時にMVCプロジェクトを選択し、他のMVC関連の引用を削除するのはRazorだけでよい.コンパイル?このコードが見つからず、大量の補助コードに埋もれています.幸いなことに、私はここで見つけました.修正を簡略化した後、いくつかの行が残っています.Webプロジェクトでなくても、直接使用することができます.
(本明細書の著作権は© 2012-2013予沁安|転載作者と出典WangHaoBlogを明記してください.com)
まず、Razorドメイン名空間を使います.
using System.Web.Razor;
using System.Web.Razor.Generator;
using System.Web.Razor.Parser;

最初のステップ、動的コンパイル:ビューファイルを解析し、コードを生成します.はい、コードを生成します.Razorの構文はプライベート構文と言えますが、標準コードを生成してからコンパイルし、よく知っているC#クラスTypeを生成する必要があります.注意しなければならないのは、私の下のコード用のテンプレートベースクラスは私自身のTeamplateBaseで、後で簡単な実現を与えて、もちろん、メリットは柔軟性です.あなたも直接Aspを使うことができます.Net MVCのSystem.Web.Mvc.WebViewPageですが、試したことがありません.他に問題があるかもしれません.保証できません.
public static Type Compile<T>(string template_path)
        {
            //      ,       Razor     
            var class_name = "c" + Guid.NewGuid().ToString("N");
            var base_type = typeof(TemplateBase<>).MakeGenericType(typeof(T));
            var template = File.ReadAllText(template_path);

            var host = new RazorEngineHost(new CSharpRazorCodeLanguage(), () => new HtmlMarkupParser())
                           {

                               DefaultBaseClass = base_type.FullName,
                               DefaultClassName = class_name,
                               DefaultNamespace = "YourNameSpace.dynamic",
                               GeneratedClassContext =
                                   new GeneratedClassContext("Execute", "Write", "WriteLiteral", "WriteTo",
                                                             "WriteLiteralTo",
                                                             "YourNameSpace.TemplateBase")

                           };
            host.NamespaceImports.Add("System");
            host.NamespaceImports.Add("YourNameSpaces");
            
            //    
            CodeCompileUnit code;
            using (var reader = new StringReader(template)) {
                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
", compiled.Errors.Cast<object>().Select(o => o.ToString())); throw new ApplicationException("Failed to compile Razor:" + compileErrors); } // , Type return compiled.CompiledAssembly.GetType("Skight.Arch.Presentation.Web.Core.ViewEngins.Razor.dynamic." + class_name); }

第2のステップは簡単で、任意の静的クラスと同様に、反射でインスタンスを作成し、Modelオブジェクトをコピーしてテンプレートを実行し、最終的に出力した結果、自動的にModelクラスのデータが埋め込まれます.
 
public static string Render<T>(T model,string template_path)
        {
            var type = Compile<T>(template_path);
            //      
            var instance = (TemplateBase<T>)Activator.CreateInstance(type);

            //    (       )
            instance.Model = model;
            instance.Execute();
            //      
            var result = instance.Result;

            return result;
        }

最後に、ビューテンプレートクラス、ベースクラス、および汎用ベースクラスを見てみましょう.後者は、前のタイプModelで使用されます.
public abstract class TemplateBase
    {
        public string Layout { get; set; }
        public UrlHelper Url { get; set; }
        public Func<string> RenderBody { get; set; }
        public string Path { get; internal set; }
        public string Result { get { return Writer.ToString(); } }

        protected TemplateBase()
        {
        }

        public TextWriter Writer
        {
            get
            {
                if(writer==null)
                {writer = new StringWriter();
                }
                return writer;
            }
            set { 
                writer = value;
            }
        }

        private TextWriter writer;

        public void Clear() {
           Writer.Flush();
        }

        public virtual void Execute() { }

        public void Write(object @object) {
            if (@object == null) {
                return;
            }
            Writer.Write(@object);
        }

        public void WriteLiteral(string @string) {
            if (@string == null) {
                return;
            }
            Writer.Write(@string);
        }

        public static void WriteLiteralTo(TextWriter writer, string literal) {
            if (literal == null) {
                return;
            }
            writer.Write(literal);
        }

        public static void WriteTo(TextWriter writer, object obj) {
            if (obj == null) {
                return;
            }
            writer.Write(obj);
        }
    }
    public abstract class TemplateBase<T> :TemplateBase
    {
        public T Model { get; set; }             
    }