T4模板使用心得
TextTemplatingFilePreprocessor 和TextTemplatingFileGenerator 的区别
TextTemplatingFilePreprocessor 是运行时模板(run-time),在模板保存时生成的是根据模板生成的cs代码,在客户端进行调用才能生成想要的文件。
TextTemplatingFileGenerator 是设计时模板 design-time,保存模板之后,就直接生成想要的代码。
**TextTemplatingFileGenerator 在项目中的应用**
创建一个帮助类,从DbContext中读取实体类名。
```
public class TemplateUtil { public class TemplateName { public string ModelName { get; set; } public string EntityName { get; set; } } public static List<TemplateName> GetModelNames() { List<TemplateName> ModelNames = new List<TemplateName>(); Type t = new DbContext().GetType(); PropertyInfo[] PropertyList = t.GetProperties(); foreach (PropertyInfo item in PropertyList) { if (item.Name != "Database" && item.Name != "ChangeTracker"&&item.Name != "Configuration"&&item.Name!= "SysAccountRoles"&&item.Name!= "SysRoleMenus"&&item.Name!= "SysRoleFunctions") { ModelNames.Add(new TemplateName { ModelName= TemplateUtil.ToSingular(item.Name) ,EntityName=item.Name}); } } return ModelNames; } /// <summary> /// 单词变成单数形式 /// </summary> /// <param name="word"></param> /// <returns></returns> public static string ToSingular(string word) { Regex plural1 = new Regex("(?<keep>[^aeiou])ies$"); Regex plural2 = new Regex("(?<keep>[aeiou]y)s$"); Regex plural3 = new Regex("(?<keep>[sxzh])es$"); Regex plural4 = new Regex("(?<keep>[^sxzhyu])s$"); Regex plural5= new Regex("(?<keep>[u])s$"); if (word.ToLower() == "news") return word; else if(plural1.IsMatch(word)) return plural1.Replace(word, "${keep}y"); else if (plural2.IsMatch(word)) return plural2.Replace(word, "${keep}"); else if (plural3.IsMatch(word)) return plural3.Replace(word, "${keep}"); else if (plural4.IsMatch(word)) return plural4.Replace(word, "${keep}"); else if (plural5.IsMatch(word)) return plural5.Replace(word, "${keep}"); return word; } /// <summary> /// 单词变成复数形式 /// </summary> /// <param name="word"></param> /// <returns></returns> public static string ToPlural(string word) { Regex plural1 = new Regex("(?<keep>[^aeiou])y$"); Regex plural2 = new Regex("(?<keep>[aeiou]y)$"); Regex plural3 = new Regex("(?<keep>[sxzh])$"); Regex plural4 = new Regex("(?<keep>[^sxzhy])$"); if (plural1.IsMatch(word)) return plural1.Replace(word, "${keep}ies"); else if (plural2.IsMatch(word)) return plural2.Replace(word, "${keep}s"); else if (plural3.IsMatch(word)) return plural3.Replace(word, "${keep}es"); else if (plural4.IsMatch(word)) return plural4.Replace(word, "${keep}s"); return word; } }
```
从DbContext中读取DbSet属性,获取全部的实体。
创建一个tangible t4 blank模板 ISvcTemplate.tt
```
<#@ template debug="true" hostSpecific="true" #> <#@ output extension=".cs" #> <#@ Assembly Name="System.Core" #> <#@ Assembly Name="System.Windows.Forms" #> <#@ Assembly Name="$(TargetDir)TemplateUtil.dll" #> <#@ import namespace="System" #> <#@ import namespace="System.IO" #> <#@ import namespace="System.Diagnostics" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Collections" #> <#@ import namespace="System.Collections.Generic" #> using System.Collections.Generic; using Models; using Models.DTOS; using Tools; <#List<TemplateUtil.TemplateName> ModelNames=TemplateUtil.GetModelNames(); foreach (var item in ModelNames) {#> namespace Services.Template { public interface I<#=item.ModelName#>Svc { #region I<#=item.ModelName#>Svc /// <summary> /// 获取模型 /// </summary> /// <param name="id">主键</param> /// <returns></returns> <#=item.ModelName#> GetModel(int? id); /// <summary> /// 分页查询 /// </summary> /// <param name="pager">分页model</param> /// <param name="search">查询model</param> /// <returns></returns> object GetPager(GridPageModel pager, SearchModel search); /// <summary> /// 保存 /// </summary> /// <param name="model">model</param> /// <returns></returns> ResultEx Save(<#=item.ModelName#> model); /// <summary> /// 删除 /// </summary> /// <param name="ids">主键列表</param> /// <returns></returns> ResultEx Delete(List<int> ids); #endregion } } <#}#>
```
以上是项目中使用的代码,保存之后生成IService代码
创建一个SvcTemplate.tt
```
<#@ template debug="true" hostSpecific="true" #> <#@ output extension=".cs" #> <#@ Assembly Name="System.Core" #> <#@ Assembly Name="System.Windows.Forms" #> <#@ Assembly Name="$(TargetDir)TemplateUtil.dll" #> <#@ import namespace="System" #> <#@ import namespace="System.IO" #> <#@ import namespace="System.Diagnostics" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Collections" #> <#@ import namespace="System.Collections.Generic" #> using System.Linq; using System.Collections.Generic; using EntityFramework.Extensions; using Mehdime.Entity; using Models; using Models.DTOS; using Services.Interfaces; using Tools; namespace Services.Template { <#List<TemplateUtil.TemplateName> ModelNames=TemplateUtil.GetModelNames(); foreach (var item in ModelNames) {#> public class <#=item.ModelName#>Svc : I<#=item.ModelName#>Svc { private readonly IDbContextScopeFactory _dbScopeFactory = new DbContextScopeFactory(); #region I<#=item.ModelName#>Svc public <#=item.ModelName#> GetModel(int? id) { using (var dbScope = _dbScopeFactory.Create()) { var db = dbScope.DbContexts.Get<ThirdIndustryAssociationDbContext>(); if (id == null) return null; else return db.<#=item.EntityName#>.SingleOrDefault(p => p.Id == id.Value); } } public object GetPager(GridPageModel pager, SearchModel search) { using (var dbScope = _dbScopeFactory.Create()) { var db = dbScope.DbContexts.Get<ThirdIndustryAssociationDbContext>(); var query = from p in db.<#=item.EntityName#> select p; return new PagedList<<#=item.ModelName#>>(query, pager).ToPager(); } } public ResultEx Save(<#=item.ModelName#> model) { using (var dbScope = _dbScopeFactory.Create()) { var db = dbScope.DbContexts.Get<ThirdIndustryAssociationDbContext>(); if (model.Id == 0) { db.<#=item.EntityName#>.Add(model); } else { db.Entry(model).State = System.Data.Entity.EntityState.Modified; } return ResultEx.Init(db.SaveChanges() > 0); } } public ResultEx Delete(List<int> ids) { using (var dbScope = _dbScopeFactory.Create()) { var db = dbScope.DbContexts.Get<ThirdIndustryAssociationDbContext>(); db.<#=item.EntityName#>.Where(p => ids.Contains(p.Id)).Delete(); return ResultEx.Init(); } } #endregion } <#}#> }
```
以上的代码保存后生成Service代码
**TextTemplatingFilePreprocessor的使用创建一个控制台Demo,实现批量编写文件**
新建一个文本模板MultiArticle.tt,自定义工具改为TextTemplatingFilePreprocessor,然后保存修改,生成一个空的MultiArticle.cs
新建一个MultiArticleCode.cs类
```
public class Article { public string Title { get; set; } public string Content { get; set; } } public partial class MultiArticle { public string Subject { get; set; } public List<Article> ArticleList { get; set; } public MultiArticle(string subject, List<Article> articles) { Subject = subject; ArticleList = articles; } }
```
创建的MultiArticle类必须和tt模板生成的类在相同的命名空间下。
添加模板内容如下:
```
<#@ template language="C#" #> <div style="text-align:center;"> <table width="600" cellpadding="0" cellspacing="0" border="0" style="margin:0 auto;"><tbody><tr><td> <div style="600px;text-align:left;font:12px/15px simsun;color:#000;background:#fff;"> <!-- 水平居中的邮件 --> <h1><#=Subject #></h2> <table> <# foreach(Article item in ArticleList) { #> <tr><td> <#= item.Title #> </td><td> <#= item.Content #> </td></tr> <# } #> </table> </div> </td></tr></tbody></table> </div>
```
在控制台的main方法中
```
class Program { static void Main(string[] args) { string subject = "最新消息"; var artList = new List<Article>(); for (int i = 0; i < 4; i++) { Article art = new Article(); art.Title = "标题" + i + ":" + Guid.NewGuid(); art.Content = "内容" + i + ":" + Guid.NewGuid(); artList.Add(art); } MultiArticle mod = new MultiArticle(subject, artList); //TransformText方法是模板编译时自动产生的, //这也是前面有提到的,模板MultiArticle.tt的命名要与MultiArticleCode.cs中的类名相同的原因, //利用分部类partial,就可以调用该TransformText方法了。 String pageContent = mod.TransformText(); //将pageContent保存到任何你想保存的地方 System.IO.File.WriteAllText("outputPage.html", pageContent, Encoding.UTF8); } }
```
运行代码,就可以看到生成的文件了。