@model
is something very specific to MVC's implementation of Razor. As such, out of the box, it doesn't work. I've uploaded a patch to the RazorEngine on codeplex that adds @model
support to it's engine and it would be pretty easy to implement it outside of that specific version. http://razorengine.codeplex.com/SourceControl/list/patches
It basically involves overriding the CodeGenerator that razor uses to generate it's class files and override TryVisitSpecialSpan
protected override bool TryVisitSpecialSpan(Span span) {
return TryVisit<ModelSpan>(span, VisitModelSpan);
//This is where you would add more special span tests
//|| TryVisit<SomeOtherSpan>(span, Method);
}
void VisitModelSpan(ModelSpan span) {
string modelName = span.ModelTypeName;
if (DesignTimeMode) {
WriteHelperVariable(span.Content, "__modelHelper");
}
}
Then you also have to create your own CSharpCodeParser
public class CSharpRazorCodeParser : CSharpCodeParser {
public string TypeName { get; set; }
public CSharpRazorCodeParser() {
RazorKeywords.Add("model", WrapSimpleBlockParser(System.Web.Razor.Parser.SyntaxTree.BlockType.Directive, ParseModelStatement));
}
bool ParseModelStatement(CodeBlockInfo block) {
End(MetaCodeSpan.Create);
SourceLocation endModelLocation = CurrentLocation;
Context.AcceptWhiteSpace(includeNewLines: false);
if (ParserHelpers.IsIdentifierStart(CurrentCharacter)) {
using (Context.StartTemporaryBuffer()) {
AcceptTypeName();
Context.AcceptTemporaryBuffer();
}
} else {
OnError(endModelLocation, "Model Keyword Must Be Followed By Type Name");
}
End(ModelSpan.Create(Context, TypeName));
return false;
}
}
And even after that you have to override the Host to use your new classes
public class RazorEngineHost : System.Web.Razor.RazorEngineHost {
public RazorEngineHost(RazorCodeLanguage codeLanguage, Func<MarkupParser> markupParserFactory)
: base(codeLanguage, markupParserFactory) { }
public override System.Web.Razor.Generator.RazorCodeGenerator DecorateCodeGenerator(System.Web.Razor.Generator.RazorCodeGenerator generator) {
if (generator is CSharpRazorCodeGenerator) {
return new CSharpRazorCodeGenerator(generator.ClassName,
generator.RootNamespaceName,
generator.SourceFileName,
generator.Host, false);
}
return base.DecorateCodeGenerator(generator);
}
public override ParserBase DecorateCodeParser(ParserBase incomingCodeParser) {
if (incomingCodeParser is CSharpCodeParser) {
return new CSharpRazorCodeParser();
} else {
return base.DecorateCodeParser(incomingCodeParser);
}
}
}
You also have to create your own custom CodeSpan
public class ModelSpan : CodeSpan {
public ModelSpan(SourceLocation start, string content, string modelTypeName) : base(start, content) {
this.ModelTypeName = modelTypeName;
}
public string ModelTypeName { get; private set; }
public override int GetHashCode() {
return base.GetHashCode() ^ (ModelTypeName ?? String.Empty).GetHashCode();
}
public override bool Equals(object obj) {
ModelSpan span = obj as ModelSpan;
return span != null && Equals(span);
}
private bool Equals(ModelSpan span) {
return base.Equals(span) && string.Equals(ModelTypeName, span.ModelTypeName, StringComparison.Ordinal);
}
public new static ModelSpan Create(ParserContext context, string modelTypeName) {
return new ModelSpan(context.CurrentSpanStart, context.ContentBuffer.ToString(), modelTypeName);
}
}
This implementation doesn't do anything other than tell the designer what model to use. It shouldn't affect compilation at all but allow the compiler to ignore this particular command.