逃げる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; }
}