我们正在构建一个内部应用程序,需要生成HTML文件以上传到eBay列表中。我们希望使用模板引擎根据我们预定义的数据库和静态字段生成HTML文件。模板还需要具有逻辑功能(if-then,foreach等)。
我们已经看过T4并且它看起来很完美,但我们看不出它是否具有在运行时使用的功能,因此用户可以创建T4模板,然后应用程序可以“编译”它并生成最终的HTML文件。这有可能,怎么样?
如果没有,是否还有其他我们应该关注的具有所有这些功能的框架?
答案 0 :(得分:16)
我有一组类似的用于此的类,将模板文本生成嵌入到软件中。
基本上,它的工作方式类似于旧式ASP,您可以在<%...%>
块中包含C#代码,并且可以使用<%= expression %>
发出结果。
您可以将单个对象传递给模板代码,当然可以是您喜欢的任何对象类型,也可以只是参数数组。如果要执行自定义代码,也可以引用自己的程序集。
以下是发布课程的方式:
<%
var parameters = (string[])data;
var namespaceName = parameters[0];
var className = parameters[1];
%>
namespace <%= namespaceName %>
{
public class <%= className %>
{
}
}
你当然可以循环使用:
<% foreach (var parameter in parameters) { %>
<%= parameter %>
<% } %>
并将代码放入if-blocks等。
类库在CodePlex上发布:
以及NuGet。
该项目附带示例,下载源代码或browse it online。
也可以通过电子邮件回答问题,让其他人看到:
data
参数对应于从应用程序作为.Generate(x)
方法的参数传入的任何参数,并且属于同一类型。如果传入已在自己的类库中定义的对象,则需要添加对模板代码的引用才能正确访问它。 (<%@ reference your.class.library.dll %>
).Generate()
的实际调用不会产生额外的开销。如果您没有自己致电.Compile()
,则第一次致电.Generate()
即可。另请注意,代码在单独的appdomain中运行,因此有一个轻微的编组开销与复制参数和结果来回相关。但是,代码以正常的JITted .NET代码速度运行。if-block示例:
<% if (a == b) { %>
This will only be output if a==b.
<% } %>
格式化代码也没有人为限制,选择最适合你的风格:
<%
if (a == b)
{
%>
This will only be output if a==b.
<%
}
%>
请注意,模板的所有非代码部分几乎都会按原样输出,这意味着还会输出标签和以下%>
块。
有一个限制,您编写的所有代码必须适合单个方法调用。
让我解释一下。
模板引擎的工作方式是它生成.cs文件并将其提供给C#编译器,这个.cs文件粗略地看起来像这样:
using directives
namespace SomeNamespace
{
public class SomeClass
{
public string Render(object data)
{
... all your code goes here
}
}
}
这意味着您无法定义新类,新方法,类级字段等。
但是,您可以使用匿名委托在内部创建函数。例如,如果您想要一种统一格式化日期的方法:
Func<DateTime, string> date2str = delegate(DateTime dt)
{
return dt.ToString("G");
};
然后您可以在模板代码的其余部分中使用它:
<%= date2str(DateTime.Now) %>
我唯一的要求就是你没有将文件上传到网上并宣称你编写了代码,除了你可以自由地用它做你想做的事。
编辑23.04.2011:修复了CodePlex项目的链接。
答案 1 :(得分:14)
如果您可以使用Visual Studio 2010进行模板创建和编辑,则可以使用预编译模板,这些模板专为此方案而设计,并且是Microsoft支持的选项。
您在Visual Studio中设计模板,预编译它并部署一个与您的应用程序一起不依赖Visual Studio的程序集。
http://www.olegsych.com/2009/09/t4-preprocessed-text-templates/
答案 2 :(得分:6)
实现T4文本转换的程序集是Microsoft.VisualStudio.TextTemplating.dll,它随Visual Studio一起提供。
如果你想从第一原则开始,你需要实现Microsoft.VisualStudio.TextTemplating.ITextTemplatingEngineHost,并将它的实现作为参数传递给Microsoft.VisualStudio.TextTemplating.Engine.ProcessTemplate(),这将执行转换。
这比调用TextTransform.exe更灵活。
但是,如果您的代码是发货产品,则不清楚此程序集的许可是什么,以及您是否有权使用您的应用程序重新分发它。
重新分发此程序集将避免安装Visual Studio。
答案 3 :(得分:3)
可以使用TextTransform.exe命令行工具编译T4模板。您 可以让你的应用程序创建一个.tt文件,然后调用TextTransform.exe来生成输出。
答案 4 :(得分:3)
完全可以在运行时使用T4。
Microsoft在.NET 3.5中没有以任何合理的方式支持这种情况。听起来.NET 4.0将得到更好的微软支持。
Mono确实在.NET 3.5中为这种情况提供了一些支持。
我已经在Mono T4实施的帮助下成功地使用.NET 3.5证明了这一概念,但是针对.NET 3.5的这个问题的现成解决方案需要比我迄今为止投入的更多努力。
您可以在此处找到Mono T4实施:
https://github.com/mono/monodevelop/tree/master/main/src/addins/TextTemplating
我已经记录了在尝试从.NET代码运行T4模板时遇到的一些问题:
答案 5 :(得分:0)
我犯的一个错误是我添加了一个“文本模板”文件。要在运行时生成文本,请选择“预处理文本模板”。如果您最初选择“文本模板”,则可以轻松地将自定义工具设置为VS中文件属性中的“TextTemplatingFilePreprocessor”。
答案 6 :(得分:0)
液体可能是个不错的选择。这是一种开源模板语言,请在此处阅读有关该语言的更多信息: https://shopify.github.io/liquid/
这是.NET的实现: https://github.com/dotliquid/dotliquid
语法非常好。这是C#的一些示例代码:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public List<string> Friends { get; set; }
}
static void Main(string[] args)
{
Template.RegisterSafeType(typeof(Person), new string[]
{
nameof(Person.Name),
nameof(Person.Age),
nameof(Person.Friends),
});
Template template = Template.Parse(
@"<h1>hi {{name}}</h1>
<p>You are{% if age > 42' %} old {% else %} young{% endif %}.</p>
<p>You have {{ friends.size }} friends:</p>
{% assign sortedfriends = friends | sort %}
{% for item in sortedfriends -%}
{{ item | escape }} <br />
{% endfor %}
");
string output = template.Render(
Hash.FromAnonymousObject(
new Person()
{
Name = "James Bond",
Age = 42,
Friends = new List<string>()
{
"Charlie",
"<TagMan>",
"Bill"
}
} ));
Console.WriteLine(output);
/* The output will be:
<h1>hi James Bond</h1>
<p>You are young.</p>
<p>You have 3 friends:</p>
<TagMan> <br />
Bill <br />
Charlie <br />
*/
}