RazorEngine
RazorEngine copied to clipboard
Using @helper methods defined in external templates
When using Razor with MVC, you can add a template in the App_Code directory that contains @helper methods, and access these helper methods from other templates using TemplateName.HelperName() syntax.
Is something like this possible with RazorEngine? I investigated the generated classes, but they appear to be named randomly so the helpers aren't accessible as static methods on nicely-named classes. But perhaps I'm missing the correct approach for this.
If it's not currently possible, what do you think of naming the classes to match the template name to enable this?
Desired Usage Example
What I'm getting at would enable something like this.
string sharedHelperTemplate = "@helper MyMethod(string name) { Hello @name }";
string template1 = "@SharedHelpers.MyMethod(Model.Name). Welcome to Template1.";
string template2 = "@SharedHelpers.MyMethod(Model.Name). Welcome to Template2.";
service.Compile(sharedHelperTemplate, typeof(object), "SharedHelpers");
string result1 = service.Parse(template1, model);
string result2 = service.Parse(template2, model);
This could be possible, I will be looking at this, and the ability to persist the template assemblies to the file system. The only thing we need to handle is ensuring that templates that are cleared from the cache are also cleared from the the file system and don't cause naming conflicts. May have to do something special with namespaces.
hi - is this possible? thanks
To make helpers work across templates we need to reference dynamic assemblies. This would work in theory, but one would need to invest some thinking into it (naming of assemblies and classes)...
The main problems:
- How to ensure the helpers are compiled before the other templates
- What about multiple Helper templates (conflicting class names anyone?)
- How should we call the classes and make sure they are 'unique' (which is the current strategy with guids).
If anyone wants to do that just go ahead. I will mark this as up-for-grabs.
Edit: To clarify with "dynamic assemblies" I don't mean dynamic assemblies as generated by Reflection.Emit but REAL assemblies dynamically created and loaded.
In case this helps anyone else, I found a way to accomplish this using RazorGenerator in addition to RazorEngine in Visual Studio.
Steps to follow:
- Install RazorGenerator extension from the Visual Studio Marketplace.
- In your project that contains RazorEngine functionality (presumably in .cshtml files), create a .cshtml file to contain the @helper methods (e.g. Helpers.cshtml).
- Place some RazorGenerator directives at the beginning, and place a simple helper method in the template. Example:
@* Generator: MvcHelper GeneratePrettyNames : true *@
@helper Test(string message)
{
<span>This is a test: @message</span>
}
- On the properties for Helpers.cshtml, set Custom Tool to "RazorGenerator", and enter a Custom Tool Namespace (e.g. RazorHelpers).
- Build. You will see a new nested file under Helpers.cshtml called Helpers.generated.cs which contains the C# output from the compiled template.
- In one of your existing templates that is consumed by RazorEngine, add a @using directive at the top for the Custom Tool Namespace you chose (e.g. RazorHelpers).
- Invoke the helper method somewhere in your template. Example:
@Raw(RazorHelpers.Helpers.Test("test message").ToString());
It was necessary to make a call to Raw and ToString to prevent the rendering engine from html escaping the output from the helper method.
This works well for me, and everything is type checked / compile-safe.
Mathias