RazorEngine extension methods in a template
I am using the Razor engine: https://github.com/Antaris/RazorEngine.
I am creating a model dynamically. I'm trying to include a extension method in a template but it inst recognising the extension class. I am receiving the following error message " 'string' does not contain a definition for 'ToUpperFirstLetter' "
Model Creation
dynamic model = new ExpandoObject();
((IDictionary<string, object>)model).Add("Forename", "john");
Template
@using Namespace.Extensions
@{
ViewBag.Title = "Title";
}
Hello @Model.Forename.ToUpperFirstLetter()
Extension Class
namespace Namespace.Extensions
{
public static class StringExtensions
{
public static string ToUpperFirstLetter(this string source)
{
return ....removed for abbreviation
}
}
}
Razor Parsing
ITemplate template = Razor.Resolve(template, model);
string result = template.Run(new ExecuteContext());
Edit
I also wanted to create an extension method on the Dynamic ExpandoObject. To see if a value inside the Model exists. I am receiving the following error message " System.Dynamic.ExpandoObject' does not contain a definition for 'HasValue' "
Extension Class
public static class ExpandoObjectExtensions
{
public static bool HasValue(this ExpandoObject source, string key)
{
return ((IDictionary<String, object>)source).ContainsKey(key);
}
}
Extension Use
@if(Model.HasValue("Hello"))
{
@Model.Hello
}
EDIT TWO
The below works and goes into the extension method
var o = new object();
var bool = o.HasValue("value");
The dynamic model still throws an exception - RuntimeBinderException: 'System.Dynamic.ExpandoObject' does not contain a definition for 'HasValue'
dynamic model = new ExpandoObject();
var bool = model.HasValue("value");
The problem you're seeing is that you're trying to execute a method ToUpperFirstLetter(this string source)
when in reality, the Forename
property is dynamic
. I would imagine if you did something like:
@(((string)Model.Forename).ToUpperFirstLetter())
... it would probably work. This is all down to the use of dynamic
. Dynamic is handled at runtime through late binding, but as RazorEngine is compiling your view, it's trying to statically link the method that expects a string where you're providing dynamic. The compiler doesn't know that Forename
is a string.
You also cannot have a dynamic
first argument to an extension method, eg:
public static string ToUpperFirsLetter(this dynamic source) { ... }
Because extension methods are resolved at compile time to explicit method calls, but the compiler doesn't know how to handle dynamic first arguments in extension methods.
EDIT Based on your response, if you want to achieve these sort of extension methods where dynamic might be the type, you'll be better of using object
and testing for types, eg:
public static class StringExtensions
{
public static string ToUpperFirstLetter(this object val)
{
string str = val as string;
if (string.IsNullOrWhitespace(str)) return str;
return str.Substring(0, 1).ToUpper() + str.Substring(1);
}
}
public static class ExpandoObjectExtensions
{
public static bool HasValue(this object val, string key)
{
var expando = val as ExpandoObject;
if (expando == null) return false;
return ((IDictionary<string, object>)expando).ContainsKey(key);
}
}
... Not ideal, but it is still a typesafe way of using extension methods on dynamic
.
上一篇: 使用RazorEngine IsolatedTemplateService和resolver?
下一篇: RazorEngine扩展方法在模板中