RazorEngine icon indicating copy to clipboard operation
RazorEngine copied to clipboard

Using @helper methods defined in external templates

Open jeremyiverson opened this issue 12 years ago • 4 comments

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);

jeremyiverson avatar May 24 '12 18:05 jeremyiverson

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.

Antaris avatar May 26 '12 09:05 Antaris

hi - is this possible? thanks

shearer3000 avatar Feb 01 '13 03:02 shearer3000

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.

matthid avatar Jan 03 '15 12:01 matthid

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:

  1. Install RazorGenerator extension from the Visual Studio Marketplace.
  2. In your project that contains RazorEngine functionality (presumably in .cshtml files), create a .cshtml file to contain the @helper methods (e.g. Helpers.cshtml).
  3. 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>
}
  1. On the properties for Helpers.cshtml, set Custom Tool to "RazorGenerator", and enter a Custom Tool Namespace (e.g. RazorHelpers).
  2. Build. You will see a new nested file under Helpers.cshtml called Helpers.generated.cs which contains the C# output from the compiled template.
  3. 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).
  4. 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

mathias999us avatar Jul 17 '23 16:07 mathias999us