public TypedObjectAccessor(Type targetType, MemberRenamerDelegate renamer) { _type = targetType ?? throw new ArgumentNullException(nameof(targetType)); _renamer = renamer ?? StandardMemberRenamer.Default; _members = new Dictionary <string, MemberInfo>(); PrepareMembers(); }
public async Task OrderStatusNotify(string email, Order orderId, OrderStatus newOrderStatus) { var statusIdle = false; if (newOrderStatus != orderId.Status) { statusIdle = true; } if (statusIdle) { MemberRenamerDelegate memberRenamer = member => member.Name; var templateContentSubject = await File.ReadAllTextAsync(templateSubjectFrom); var templateSubject = Template.Parse(templateContentSubject); var subject = templateSubject.Render(new { OrderId = orderId }, memberRenamer); string from = "Rui Dias"; var templateContentBody = await File.ReadAllTextAsync(templateBodyFrom); var templateBody = Template.Parse(templateContentBody); var message = templateBody.Render( new { OrderId = orderId, From = from, NewOrderStatus = newOrderStatus != orderId.Status } ); await _emailSender.SendEmailAsync(email, subject, message); } }
public static object Evaluate(string expression, object model, MemberRenamerDelegate memberRenamer = null, MemberFilterDelegate memberFilter = null) { if (expression == null) { throw new ArgumentNullException(nameof(expression)); } var lexerOption = new LexerOptions() { Mode = ScriptMode.ScriptOnly }; var template = Parse(expression, lexerOptions: lexerOption); return(template.Evaluate(model, memberRenamer, memberFilter)); }
/// <summary> /// Renders this template using the specified object model. /// </summary> /// <param name="model">The object model.</param> /// <param name="memberRenamer">The member renamer used to import this .NET object and transitive objects. See member renamer documentation for more details.</param> /// <returns>A rendering result as a string </returns> public string Render(object model = null, MemberRenamerDelegate memberRenamer = null) { var scriptObject = new ScriptObject(); if (model != null) { scriptObject.Import(model, renamer: memberRenamer); } var context = _lexerOptions.Mode == ScriptMode.Liquid ? new LiquidTemplateContext() : new TemplateContext(); context.MemberRenamer = memberRenamer; context.PushGlobal(scriptObject); return(Render(context)); }
public void ReturnsPdfPageFromScriban() { var template = Template.Parse(TemplateContent()); var catalogModel = new CatalogIndexViewModel(); var items = new List <CatalogItemViewModel>(); items.Add(new CatalogItemViewModel() { Name = "Name_1", Price = 1.2m, PriceSymbol = "€" }); items.Add(new CatalogItemViewModel() { Name = "Name_2", Price = 2.2m, PriceSymbol = "€" }); catalogModel.CatalogItems = items; var listCatalogItems = new List <CatalogItemViewModel>(); foreach (var item in catalogModel.CatalogItems) { listCatalogItems.Add( new CatalogItemViewModel() { Name = item.Name, Price = item.Price, ShowPrice = item.ShowPrice, PriceSymbol = item.PriceSymbol, PictureUri = System.IO.Path.GetFullPath($"~{item.PictureUri}").Replace("~", "wwwroot") //PictureUri = "C:\\Formacao\\ASP.Net\\desenvolvimento\\eShopOnWeb\\src\\Web\\wwwroot\\images\\products\\1.png" } ); } MemberRenamerDelegate memberRenamer = member => member.Name; var pp = new { Data = listCatalogItems, Date = DateTime.Now.ToString(), Year = DateTime.Now.Year }; var html = template.Render(pp, memberRenamer); // Assert Assert.Contains("Name_1", html); }
public static string ScribanParse(string template, dynamic model, MemberRenamerDelegate f = null) { try { return(ScribanRawParse(template, model, f)); } catch (Exception e) { var errors = ScribanErrors(template, model, f); var msg = $"{e.Message} {template} parse error with model\n"; Console.Error.WriteLine(msg); if (e.InnerException != null) { Console.Error.WriteLine($"\n{e.InnerException.Message}\n"); } //ExceptionHandler.GenericExceptionHandler(Program.Exceptions, e, msg); throw; }; }
public object Evaluate(object model = null, MemberRenamerDelegate memberRenamer = null, MemberFilterDelegate memberFilter = null) { var scriptObject = new ScriptObject(); if (model != null) { scriptObject.Import(model, renamer: memberRenamer, filter: memberFilter); } var context = LexerOptions.Lang == ScriptLang.Liquid ? new LiquidTemplateContext() : new TemplateContext(); context.EnableOutput = false; context.MemberRenamer = memberRenamer; context.MemberFilter = memberFilter; context.UseScientific = LexerOptions.Lang == ScriptLang.Scientific; context.PushGlobal(scriptObject); var result = Evaluate(context); context.PopGlobal(); return(result); }
public async Task <FileResult> ScribanAsync() { var pathTemplate = _configuration.GetValue <string>("Template:CatalogPdf"); var templateContent = await System.IO.File.ReadAllTextAsync(pathTemplate); var template = Template.Parse(templateContent); var catalogPageModel = new CatalogPageFiltersViewModel() { Culture = CultureInfo.CurrentCulture.Name, ItemsPerPage = 0 }; var catalogModel = await _catalogViewModelService.GetCatalogItems(catalogPageModel, false, true); var listCatalogItems = new List <CatalogItemViewModel>(); foreach (var item in catalogModel.CatalogItems) { listCatalogItems.Add( new CatalogItemViewModel() { Name = item.Name, Price = item.Price, ShowPrice = item.ShowPrice, PriceSymbol = item.PriceSymbol, PictureUri = System.IO.Path.GetFullPath($"~{item.PictureUri}").Replace("~", "wwwroot") //PictureUri = "C:\\Formacao\\ASP.Net\\desenvolvimento\\eShopOnWeb\\src\\Web\\wwwroot\\images\\products\\1.png" } ); } MemberRenamerDelegate memberRenamer = member => member.Name; var pp = new { Data = listCatalogItems, Date = DateTime.Now.ToString(), Year = DateTime.Now.Year }; var html = template.Render(pp, memberRenamer); var htmlToPdf = new HtmlToPdf(); var pdf = await htmlToPdf.RenderHtmlAsPdfAsync(html); return(File(pdf.BinaryData, "application/pdf;", "Catalog.pdf")); }
/// <summary> /// Evaluates the template using the specified context /// </summary> /// <param name="model">An object model to use with the evaluation.</param> /// <param name="memberRenamer">The member renamer used to import this .NET object and transitive objects. See member renamer documentation for more details.</param> /// <param name="memberFilter">The member filter used to filter members for .NET objects being accessed through the template, including the model being passed to this method.</param> /// <exception cref="System.InvalidOperationException">If the template <see cref="HasErrors"/>. Check the <see cref="Messages"/> property for more details</exception> /// <returns>Returns the result of the last statement</returns> public object Evaluate(object model = null, MemberRenamerDelegate memberRenamer = null, MemberFilterDelegate memberFilter = null) { var scriptObject = new ScriptObject(); if (model != null) { scriptObject.Import(model, renamer: memberRenamer, filter: memberFilter); } var context = new TemplateContext { EnableOutput = false, MemberRenamer = memberRenamer, MemberFilter = memberFilter }; context.PushGlobal(scriptObject); var result = Evaluate(context); context.PopGlobal(); return(result); }
/// <summary> /// Catalog Item notify client /// </summary> /// <param name="email"></param> /// <param name="catalogItem"></param> /// <param name="priceNew"></param> /// <returns></returns> public async Task CatalogItemNotifyClient(string email, CatalogItem catalogItem, decimal priceNew) { var anyChanges = false; if (priceNew != catalogItem.Price) { anyChanges = true; } if (anyChanges) { MemberRenamerDelegate memberRenamer = member => member.Name; //email subject var subject = templateSubject.Render(new { CatalogItem = catalogItem }, memberRenamer); //email message var message = templateBody.Render( new { Greeting = greeting, PriceChanged = priceNew != catalogItem.Price } ); await _emailSender.SendEmailAsync(email, subject, message); } }
/// <summary> /// Imports the specified object intto this <see cref="ScriptObject"/> context. See remarks. /// </summary> /// <param name="obj">The object.</param> /// <param name="filter">Optional member filterer</param> /// <param name="renamer">Optional renamer</param> /// <remarks> /// <ul> /// <li>If <paramref name="obj"/> is a <see cref="System.Type"/>, this method will import only the static field/properties of the specified object.</li> /// <li>If <paramref name="obj"/> is a <see cref="ScriptObject"/>, this method will import the members of the specified object into the new object.</li> /// <li>If <paramref name="obj"/> is a plain object, this method will import the public fields/properties of the specified object into the <see cref="ScriptObject"/>.</li> /// </ul> /// </remarks> public static void Import(this IScriptObject script, object obj, FilterMemberDelegate filter = null, MemberRenamerDelegate renamer = null) { if (obj is IScriptObject) { script.Import((IScriptObject)obj); return; } script.Import(obj, ScriptMemberImportFlags.All, filter, renamer); }
private static string ScribanRawParse(string template, dynamic model, MemberRenamerDelegate f = null) => Template.Parse(template).Render(model, f ?? ScribanCleanName);
public static void Import(this IScriptObject script, object obj, MemberFilterDelegate filter = null, MemberRenamerDelegate renamer = null) { if (obj is IScriptObject) { // TODO: Add support for filter, member renamer script.Import((IScriptObject)obj); return; } if (obj is IDictionary) { // TODO: Add support for filter, member renamer script.ImportDictionary((IDictionary)obj); return; } script.Import(obj, ScriptMemberImportFlags.All, filter, renamer); }
public static void Import(this IScriptObject script, object obj, ScriptMemberImportFlags flags, MemberFilterDelegate filter = null, MemberRenamerDelegate renamer = null) { if (obj == null) { return; } if (!ScriptObject.IsImportable(obj)) { throw new ArgumentOutOfRangeException(nameof(obj), $"Unsupported object type `{obj.GetType()}`. Expecting plain class or struct"); } var typeInfo = (obj as Type ?? obj.GetType()); bool useStatic = false; bool useInstance = false; if (obj is Type) { useStatic = true; obj = null; } else { useInstance = true; } renamer = renamer ?? StandardMemberRenamer.Default; var typeToImports = new Stack <Type>(); while (typeInfo != null) { typeToImports.Push(typeInfo); if (typeInfo.BaseType == typeof(object)) { break; } typeInfo = typeInfo.BaseType; } var scriptObj = script as ScriptObject; while (typeToImports.Count > 0) { typeInfo = typeToImports.Pop(); if ((flags & ScriptMemberImportFlags.Field) != 0) { foreach (var field in typeInfo.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly)) { if (!field.IsPublic || field.IsLiteral) { continue; } if (filter != null && !filter(field)) { continue; } var keep = field.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null; if (keep && ((field.IsStatic && useStatic) || useInstance)) { var newFieldName = renamer(field); if (String.IsNullOrEmpty(newFieldName)) { newFieldName = field.Name; } // If field is init only or literal, it cannot be set back so we mark it as read-only if (scriptObj == null) { script.TrySetValue(null, new SourceSpan(), newFieldName, field.GetValue(obj), field.IsInitOnly || field.IsLiteral); } else { scriptObj.SetValue(newFieldName, field.GetValue(obj), field.IsInitOnly || field.IsLiteral); } } } } if ((flags & ScriptMemberImportFlags.Property) != 0) { foreach (var property in typeInfo.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly)) { // Workaround with .NET Core, extension method is not working (retuning null despite doing property.GetMethod), so we need to inline it here var getMethod = property.GetMethod; if (!property.CanRead || !getMethod.IsPublic) { continue; } if (filter != null && !filter(property)) { continue; } var keep = property.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null; if (keep && (((getMethod.IsStatic && useStatic) || useInstance))) { var newPropertyName = renamer(property); if (String.IsNullOrEmpty(newPropertyName)) { newPropertyName = property.Name; } // Initially, we were setting readonly depending on the precense of a set method, but this is not compatible with liquid implems, so we remove readonly restriction //script.SetValue(null, new SourceSpan(), newPropertyName, property.GetValue(obj), property.GetSetMethod() == null || !property.GetSetMethod().IsPublic); if (scriptObj == null) { script.TrySetValue(null, new SourceSpan(), newPropertyName, property.GetValue(obj), false); } else { if (property.GetIndexParameters().Length == 0) { scriptObj.SetValue(newPropertyName, property.GetValue(obj), false); } } } } } if ((flags & ScriptMemberImportFlags.Method) != 0 && useStatic) { foreach (var method in typeInfo.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly)) { if (filter != null && !filter(method)) { continue; } var keep = method.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null; if (keep && method.IsPublic && method.IsStatic && !method.IsSpecialName) { var newMethodName = renamer(method); if (String.IsNullOrEmpty(newMethodName)) { newMethodName = method.Name; } if (scriptObj == null) { script.TrySetValue(null, new SourceSpan(), newMethodName, DynamicCustomFunction.Create(obj, method), true); } else { scriptObj.SetValue(newMethodName, DynamicCustomFunction.Create(obj, method), true); } } } } } }
/// <summary> /// Imports the specified object. /// </summary> /// <param name="obj">The object.</param> /// <param name="flags">The import flags.</param> /// <param name="filter">A filter applied on each member</param> /// <param name="renamer">The member renamer.</param> /// <exception cref="System.ArgumentOutOfRangeException"></exception> public static void Import(this IScriptObject script, object obj, ScriptMemberImportFlags flags, FilterMemberDelegate filter = null, MemberRenamerDelegate renamer = null) { if (obj == null) { return; } if (!ScriptObject.IsImportable(obj)) { throw new ArgumentOutOfRangeException(nameof(obj), $"Unsupported object type [{obj.GetType()}]. Expecting plain class or struct"); } var typeInfo = (obj as Type ?? obj.GetType()).GetTypeInfo(); bool useStatic = false; bool useInstance = false; bool useMethodInstance = false; if (obj is Type) { useStatic = true; obj = null; } else { useInstance = true; useMethodInstance = (flags & ScriptMemberImportFlags.MethodInstance) != 0; } renamer = renamer ?? StandardMemberRenamer.Default; if ((flags & ScriptMemberImportFlags.Field) != 0) { foreach (var field in typeInfo.GetDeclaredFields()) { if (!field.IsPublic) { continue; } if (filter != null && !filter(field.Name)) { continue; } var keep = field.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null; if (keep && ((field.IsStatic && useStatic) || useInstance)) { var newFieldName = renamer(field.Name); if (String.IsNullOrEmpty(newFieldName)) { newFieldName = field.Name; } // If field is init only or literal, it cannot be set back so we mark it as read-only script.SetValue(null, new SourceSpan(), newFieldName, field.GetValue(obj), field.IsInitOnly || field.IsLiteral); } } } if ((flags & ScriptMemberImportFlags.Property) != 0) { foreach (var property in typeInfo.GetDeclaredProperties()) { if (!property.CanRead || !property.GetGetMethod().IsPublic) { continue; } if (filter != null && !filter(property.Name)) { continue; } var keep = property.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null; if (keep && (((property.GetGetMethod().IsStatic&& useStatic) || useInstance))) { var newPropertyName = renamer(property.Name); if (String.IsNullOrEmpty(newPropertyName)) { newPropertyName = property.Name; } script.SetValue(null, new SourceSpan(), newPropertyName, property.GetValue(obj), property.GetSetMethod() == null || !property.GetSetMethod().IsPublic); } } } if ((flags & ScriptMemberImportFlags.Method) != 0 && (useStatic || useMethodInstance)) { foreach (var method in typeInfo.GetDeclaredMethods()) { if (filter != null && !filter(method.Name)) { continue; } var keep = method.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null; if (keep && method.IsPublic && ((useMethodInstance && !method.IsStatic) || (useStatic && method.IsStatic)) && !method.IsSpecialName) { var newMethodName = renamer(method.Name); if (String.IsNullOrEmpty(newMethodName)) { newMethodName = method.Name; } script.SetValue(null, new SourceSpan(), newMethodName, new ObjectFunctionWrapper(obj, method), true); } } } }
private static List <Scriban.Parsing.LogMessage> ScribanErrors(string template, dynamic model, MemberRenamerDelegate f = null) => Template.Parse(template).Messages;
/// <summary> /// Imports the specified object. /// </summary> /// <param name="scriptObject">The script object to import into</param> /// <param name="obj">The object.</param> /// <param name="flags">The import flags.</param> /// <param name="filter">A filter applied on each member</param> /// <param name="renamer">The member renamer.</param> /// <exception cref="ArgumentOutOfRangeException">The object is not importable.</exception> public static void Import(this IScriptObject scriptObject, object obj, ScriptMemberImportFlags flags, MemberFilterDelegate filter = null, MemberRenamerDelegate renamer = null) { if (obj == null) { return; } if (!ScriptObject.IsImportable(obj)) { throw new ArgumentOutOfRangeException(nameof(obj), string.Format(RS.InvalidObjectType, obj.GetType())); } #if NETSTANDARD TypeInfo typeInfo = (obj as Type ?? obj.GetType()).GetTypeInfo(); #else Type typeInfo = (obj as Type ?? obj.GetType()).GetTypeInfo(); #endif bool useStatic = false; bool useInstance = false; if (obj is Type) { useStatic = true; obj = null; } else { useInstance = true; } renamer = renamer ?? StandardMemberRenamer.Default; while (typeInfo != null) { if ((flags & ScriptMemberImportFlags.Field) != 0) { foreach (FieldInfo field in typeInfo.GetDeclaredFields()) { if (!field.IsPublic) { continue; } if (filter != null && !filter(field)) { continue; } bool keep = field.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null; if (keep && ((field.IsStatic && useStatic) || useInstance)) { string newFieldName = renamer(field); if (string.IsNullOrEmpty(newFieldName)) { newFieldName = field.Name; } // If field is init only or literal, it cannot be set back so we mark it as read-only scriptObject.SetValue(null, new SourceSpan(), newFieldName, field.GetValue(obj), field.IsInitOnly || field.IsLiteral); } } } if ((flags & ScriptMemberImportFlags.Property) != 0) { foreach (PropertyInfo property in typeInfo.GetDeclaredProperties()) { // Workaround with .NET Core, extension method is not working (retuning null) #if NETFX MethodInfo getMethod = property.GetGetMethod(); #else MethodInfo getMethod = property.GetMethod; #endif if (!property.CanRead || !getMethod.IsPublic) { continue; } if (filter != null && !filter(property)) { continue; } bool keep = property.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null; if (keep && ((getMethod.IsStatic && useStatic) || useInstance)) { string newPropertyName = renamer(property); if (string.IsNullOrEmpty(newPropertyName)) { newPropertyName = property.Name; } // Initially, we were setting readonly depending on the precense of a set method, but this is not compatible with liquid implems, so we remove readonly restriction //script.SetValue(null, new SourceSpan(), newPropertyName, property.GetValue(obj), property.GetSetMethod() == null || !property.GetSetMethod().IsPublic); scriptObject.SetValue(null, new SourceSpan(), newPropertyName, property.GetValue(obj), false); } } } if ((flags & ScriptMemberImportFlags.Method) != 0 && useStatic) { foreach (MethodInfo method in typeInfo.GetDeclaredMethods()) { if (filter != null && !filter(method)) { continue; } bool keep = method.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null; if (keep && method.IsPublic && method.IsStatic && !method.IsSpecialName) { string newMethodName = renamer(method); if (string.IsNullOrEmpty(newMethodName)) { newMethodName = method.Name; } scriptObject.SetValue(null, new SourceSpan(), newMethodName, DynamicCustomFunction.Create(obj, method), true); } } } if (typeInfo.BaseType == typeof(object)) { break; } typeInfo = typeInfo.BaseType.GetTypeInfo(); } }
/// <summary> /// Imports the specified object. /// </summary> /// <param name="script">The script object to import into</param> /// <param name="obj">The object.</param> /// <param name="flags">The import flags.</param> /// <param name="filter">A filter applied on each member</param> /// <param name="renamer">The member renamer.</param> /// <exception cref="System.ArgumentOutOfRangeException"></exception> public static void Import(this IScriptObject script, object obj, ScriptMemberImportFlags flags, MemberFilterDelegate filter = null, MemberRenamerDelegate renamer = null) { if (obj == null) { return; } if (!ScriptObject.IsImportable(obj)) { throw new ArgumentOutOfRangeException(nameof(obj), $"Unsupported object type `{obj.GetType()}`. Expecting plain class or struct"); } var typeInfo = (obj as Type ?? obj.GetType()).GetTypeInfo(); bool useStatic = false; bool useInstance = false; if (obj is Type) { useStatic = true; obj = null; } else { useInstance = true; } renamer = renamer ?? StandardMemberRenamer.Default; while (typeInfo != null) { if ((flags & ScriptMemberImportFlags.Field) != 0) { foreach (var field in typeInfo.GetDeclaredFields()) { if (!field.IsPublic) { continue; } if (filter != null && !filter(field)) { continue; } var keep = field.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null; if (keep && ((field.IsStatic && useStatic) || useInstance)) { var newFieldName = renamer(field); if (String.IsNullOrEmpty(newFieldName)) { newFieldName = field.Name; } // If field is init only or literal, it cannot be set back so we mark it as read-only script.SetValue(null, new SourceSpan(), newFieldName, field.GetValue(obj), field.IsInitOnly || field.IsLiteral); } } } if ((flags & ScriptMemberImportFlags.Property) != 0) { foreach (var property in typeInfo.GetDeclaredProperties()) { var methodInfoReadProperty = property.GetGetMethod(); if (methodInfoReadProperty is null) { continue; } if (!property.CanRead || !methodInfoReadProperty.IsPublic) { continue; } if (filter != null && !filter(property)) { continue; } var keep = property.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null; if (keep && (((methodInfoReadProperty.IsStatic && useStatic) || useInstance))) { var newPropertyName = renamer(property); if (String.IsNullOrEmpty(newPropertyName)) { newPropertyName = property.Name; } // Initially, we were setting readonly depending on the precense of a set method, but this is not compatible with liquid implems, so we remove readonly restriction //script.SetValue(null, new SourceSpan(), newPropertyName, property.GetValue(obj), property.GetSetMethod() == null || !property.GetSetMethod().IsPublic); script.SetValue(null, new SourceSpan(), newPropertyName, property.GetValue(obj), false); } } } if ((flags & ScriptMemberImportFlags.Method) != 0 && useStatic) { foreach (var method in typeInfo.GetDeclaredMethods()) { if (filter != null && !filter(method)) { continue; } var keep = method.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null; if (keep && method.IsPublic && method.IsStatic && !method.IsSpecialName) { var newMethodName = renamer(method); if (String.IsNullOrEmpty(newMethodName)) { newMethodName = method.Name; } script.SetValue(null, new SourceSpan(), newMethodName, DynamicCustomFunction.Create(obj, method), true); } } } if (typeInfo.BaseType == typeof(object)) { break; } typeInfo = typeInfo.BaseType.GetTypeInfo(); } }
public TypedObjectAccessor(Type targetType, MemberFilterDelegate filter, MemberRenamerDelegate renamer) : this(targetType, null, filter, renamer) { }