我正在尝试在沙盒环境中解析和编译Razor模板a.k.a。基于this信息的自定义主机(架构见下文)。
我在使智力感知工作时遇到了麻烦,所以我按照here指定BuildProvider
并按照该问题答案中提供的“workaround”进行操作。
On @model MyAssembly.MyModel
intellisense出现以下错误:
无法加载文件或程序集“System.Web.WebPages.Razor”或其中一个依赖项。
(程序集 引用并复制到本地,以及所有其他相关的Razor程序集)
在解析和编译模板时,会引发以下错误:
行:33列:7错误:当前上下文中不存在名称“模型”
任何线索/建议?
P.S。如果我删除@model指令,模板解析并编译好
架构:
答案 0 :(得分:6)
@model
是MVC实现Razor的非常具体的东西。因此,开箱即用,它不起作用。我已经在codeplex上向RazorEngine上传了一个补丁,它为它的引擎添加了@model
支持,并且在特定版本之外实现它非常容易。 http://razorengine.codeplex.com/SourceControl/list/patches
它基本上涉及覆盖razor用来生成它的类文件并覆盖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");
}
}
然后你还必须创建自己的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;
}
}
即使在那之后你必须覆盖主机以使用你的新类
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);
}
}
}
您还必须创建自己的自定义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);
}
}
除了告诉设计师使用什么型号之外,此实现不做任何其他事情。它根本不应影响编译,但允许编译器忽略此特定命令。
答案 1 :(得分:1)
There is a simple solution for IntelliSense to work使用&#39;自定义Razor环境&#39;和Resharper(例如使用RazorEngine进行报告)。要启用IntelliSense,请在项目中创建以下类:
public class EnableIntelliSenseFor<T>
{
public readonly T Model;
}
在.cshtml文件的顶部添加以下行:
@inherits EnableIntelliSenseFor<YourModelType>
然后在解析模板时,只需按照ThiagoPXP的建议删除顶行:
template = RemoveInheritsDirective(template);
var html = Razor.Parse(template, model);
private static string RemoveInheritsDirective(string template)
{
return template.StartsWith("@inherits")
? template.Substring(template.IndexOf('\n') + 1)
: template;
}
使用@Model访问您的模型,IntelliSense应该按预期工作。
答案 2 :(得分:0)
我有同样的问题,我的解决方案非常简单。
在文件开头有@model是很好的,因为它给了我们一些智能感知。但是,它打破了剃刀引擎,因此我的解决方案是在调用解析器之前删除运行时的模型声明。
string template = File.ReadAllText(@"C\myRazorView.cshtml");
var model = new MyViewModel { Name = "Foo", Surname = "Bar" };
//remove model declaration from the view file
template = template.Replace("@model MyViewModel", "");
string result = Razor.Parse(template, model);
在我的情况下,所有视图都使用相同的模型,因此在第一行使用String.Replace()为我做了诀窍。
您可以通过其他方式(例如正则表达式或其他方式)来删除第一行。
答案 3 :(得分:0)
对我来说这很有用(在NET4.0上使用RazorEngine 3.3):
1.这行到cshtml顶部
@inherits RazorEngine.Templating.TemplateBase<MyModel>
2.这是在Page_Load
中var templateName = System.IO.Path.ChangeExtension( Request.PhysicalPath, "cshtml");
var template = System.IO.File.ReadAllText(templateName);
var r = Razor.Parse<MyModel>(template, new MyModel {
FileName = "Example.pdf",
MessageId = Guid.NewGuid()
}, "MyPage");
Response.Write(r);