“自定义环境”中的Razor不接受@model指令

时间:2011-04-27 15:13:17

标签: .net razor

我正在尝试在沙盒环境中解析和编译Razor模板a.k.a。基于this信息的自定义主机(架构见下文)。

我在使智力感知工作时遇到了麻烦,所以我按照here指定BuildProvider并按照该问题答案中提供的“workaround”进行操作。

On @model MyAssembly.MyModel intellisense出现以下错误:

  

无法加载文件或程序集“System.Web.WebPages.Razor”或其中一个依赖项。

(程序集 引用并复制到本地,以及所有其他相关的Razor程序集)

在解析和编译模板时,会引发以下错误:

  

行:33列:7错误:当前上下文中不存在名称“模型”

任何线索/建议?

P.S。如果我删除@model指令,模板解析并编译好

架构:

  • Web应用程序:引用类库,并使用3d方类库中的模型提供.cshtml模板文件。
  • 类库:包含RazorHost和BaseTemplate,并引用3d方库将模型添加到webapplication提供的.cshtml文件中。
  • 3d Party Class:为webapplication提供模型

4 个答案:

答案 0 :(得分:6)

@model是MVC实现Razor的非常具体的东西。因此,开箱即用,它不起作用。我已经在codeplex上向RazorEngine上传了一个补丁,它为它的引擎添加了@model支持,并且在特定版本之外实现它非常容易。 http://razorengine.codeplex.com/SourceControl/list/patches

它基本上涉及覆盖razor用来生成它的类文件并覆盖TryVisitSpecialSpan

的CodeGenerator
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);
相关问题