DotLiquid-Asp.net模板引擎

 以前用过一段时间的PHP,感觉非常不错,其中最让我难忘的就是Smarty模板引擎,当时就微微地想Asp.net里有没有像这样的模板引擎呢?不过由于之后的工作内容都用不到,或者说没有想到用模板,这想法也没导致我做一些事情,就不了了之了。

    现在也是工作需要,用模板是一个不错的选择。之前没用过这种东西,盲搜一片没找到自己想要的,于是自己就试着写写,大思路用的是Smarty的,用html页面做为模板,生成aspx页面,把数据放在HttpContext.Items里,代码如下:

html模板:

< div > {$title} </ div >
< select >
    {foreach $l in $list}
    
< option  value ="{$l.Age}" > {$l.Name} </ option >
    {/foreach}
</ select >

    生成的aspx页面:

复制代码
<% @ Page Language = " C# "   %>
<%
    
if  (HttpContext.Current.Items[ " SMARTY_TEMPLATE_DIR " ] == null )
    {
        Response.Write(
" no direct access allowed " );
        Response.End();
    }
%>
< div > <% = DotSmarty.Smarty.GetTemplateArg( " title " %> </ div >
<%  var list  =  DotSmarty.Smarty.GetTemplateArg( " list " as  System.Collections.Generic.IList < SmartyTest.User > %>
< select >
    
<%  foreach (var l in list){  %>
    
< option  value ="<%=l.Age %>" > <% = l.Name  %> </ option >
    
<% } %>
</ select >
复制代码

     调用如:

复制代码
Smarty smarty  =   new  Smarty();
List
< User >  list  =   new  List < User > ();
list.Add(
new  User() {  Age = 1 , Name = " name111 " });
list.Add(
new  User() { Age  =   2 , Name  =   " name222 "  });
smarty.Assign(
" title " " 标题 " );
smarty.Assign(
" list " , list, TemplateArgType.List);
smarty.Display(
" user/userInfo.htm " );
复制代码

     看起来很像Smarty,可越写难度越大!唉,能力有限,将来有能力再说吧,现在只能放弃。

 

     前几天幸运地听说了DotLiquid,网址是:http://dotliquidmarkup.org。上面曰:“DotLiquid is a templating system ported to the .net framework from Ruby’s Liquid Markup.It’s easy to learn, fast and safe"。我想我终于找到了asp.net中的smarty了,更有图说明:

 

这里先介绍一下她的几个主要的概念:

 Filter:"Filters are simple methods(过滤器是一些简单的方法)"

     如标准Filter中的upcase,{{ "looGn" | upcase }}  值为"LOOGN"。 

 Tag:"Tags are used for the logic in your template(标签用于实现模板中的逻辑)"。 

     如标准Tag中的assign,{% assign freestyle = false %} 定义值为false的freestyle变量。

 Block:其实block也是tag,如if..else,for..in, 可以说Block是有endtag的Tag。

    如:{% for i in (1..5) %}

          {{ i }}

      {% endfor %} 

 

    下面跟大家分享一下这几天对她的理解及代码实现:

    下载过发布的压缩包DotLiquid v1.5.zip里会有v3.5和v4.0两个版,引用DotLiquid.dll的对应版本到自己项目即可。其实她真的是easy to learn!看一个handler的代码:

复制代码
public   void  ProcessRequest(HttpContext context)
{
    context.Response.ContentType 
=   " text/plain " ;
    Template template 
=  Template.Parse( " 模板内容:{{hw}} " ); // 用模板内容做为参数解析得到Template对象
     string  result  =  template.Render(Hash.FromAnonymousObject( new  { hw  =   " Hello World! "  })); // 用模板所需的元素做为参数呈现处理后的结果
    context.Response.Write(result);
}
复制代码

    一切的一切,其实就这两步!关键是!我们如何应用!"技术不是秘密,秘密是如何善用技术!" 不记得在哪看得一句话,不过无所谓啦!

 

    第一步: 从文件读入模板内容。模板大多数不是程序中的一个字符串变量,可能存在文件、数据库里等,这里说的是html文件模板。TemplateHelper如下

复制代码
     public   static   class  TemplateHelper
    {
        
#region  Template路径

        
static  TemplateHelper()
        {
            
// 可用文件配置,例子中用了字典
            _map  =   new  Dictionary < string string > ( 50 );
            _map.Add(
" master " " ~/template/master.htm " );
            _map.Add(
" index_content_main " " ~/template/index_content_main.htm " );
            _map.Add(
" list_content_main " " ~/template/list_content_main.htm " );
            _map.Add(
" list_content_script " " ~/template/list_content_script.htm " );
            _map.Add(
" detail " " ~/template/uc/detail.htm " );
        }

        
#endregion

        
private   static  Dictionary < string string >  _map;

        
public   static   bool  ContainsKey( string  key)
        {
            
return  _map.ContainsKey(key);
        }
        
public   static   string  GetTemplateURL( string  key)
        {
            
try
            {
                
return  _map[key];
            }
            
catch  (KeyNotFoundException e)
            {
                KeyNotFoundException ne 
=   new  KeyNotFoundException(e.Message  +   " key: "   +  key);
                
throw  ne;
            }
            
catch  (Exception e)
            {
                
throw  e;
            }
        }
        
/* 这个方法限制了文件模板路径必要配置,如果需要可以添加直接以文件路径为参数的方法,
         *不过感觉这里配置起来是个好的习惯 
*/
        
public   static  Template GetFileTemplate( string  templateKey, Encoding encoding)
        {
            Template template 
=  HttpContext.Current.Cache[templateKey]  as  Template;
            
if  (template  ==   null )
            {
                
string  path  =  HttpContext.Current.Server.MapPath(GetTemplateURL(templateKey));
                template 
=  Template.Parse(File.ReadAllText(path, encoding));
                CacheDependency dependency 
=   new  CacheDependency(path);
                HttpContext.Current.Cache.Add(templateKey, template, dependency, Cache.NoAbsoluteExpiration,
                    Cache.NoSlidingExpiration, CacheItemPriority.Default, 
null ); // 把模板缓存起来
            }
            
return  template;
        }

        
public   static  Template GetFileTemplate( string  templateKey)
        {
            
return  GetFileTemplate(templateKey, Encoding.UTF8);
        }
    }
复制代码

   

    第二步:include文件。DotLiquid的include是一个标准Tag,如{% include top %}。调用include需要给Template.FileSystem赋值,它是一个IFileSystem接口,在IFileSystem里只有一个方法:

     public   interface  IFileSystem
    {
        
string  ReadTemplateFile(Context context,  string  templateName);
    }

     很显然,解析到include top时会把top做为templateName调用Template.FileSystem.ReadTemplateFile方法,以此来实现include。所以实现IFileSystem的类要以templateName参数返回对应的内容:

复制代码
     public   class  IncludeFileSystem : IFileSystem
    {
        
private  Encoding _encoding  =  Encoding.Default;

        
public  IncludeFileSystem(){}

        
public  IncludeFileSystem(Encoding encoding)
        {
            _encoding 
=  encoding;
        }

        
public   string  ReadTemplateFile(Context context,  string  templateName)
        {
            
bool  isOptional  =   false // 是否可选
             string  templateKey  =  templateName;
            
if  (templateName.EndsWith( " _optional " ))
            {
                isOptional 
=   true ;
                templateKey 
=  templateKey.Replace( " _optional " "" );
            }
            
if  (templateKey.StartsWith( " content_ " ))
            {
                
object  ns  =  context.Environments[ 0 ][ " ns " ];
                
if  (ns  ==   null )
                {
                    ns 
=  Path.GetFileNameWithoutExtension(HttpContext.Current.Request.RawUrl);
                }
                templateKey 
=  ns  +   " _ "   +  templateKey;
            }
            
object  result  =  HttpContext.Current.Cache[templateKey];
            
if  (result  ==   null )
            {
                
if  (isOptional  &&   ! TemplateHelper.ContainsKey(templateKey))
                {
                    
return   string .Empty;
                }
                
string  path  =  HttpContext.Current.Server.MapPath(TemplateHelper.GetTemplateURL(templateKey));
                result 
=  File.ReadAllText(path, Encoding.UTF8);
                CacheDependency dependency 
=   new  CacheDependency(path);
                HttpContext.Current.Cache.Add(templateKey, result, dependency, Cache.NoAbsoluteExpiration, 
                    Cache.NoSlidingExpiration, CacheItemPriority.Default, 
null );
            }
            
return  result.ToString();
        }
    }
复制代码

    这里的ReadTemplateFile有点复杂,其实就是根据templateName来读文件,缓存,至于开始的判断后面再说。在适当的地方设置一下Template.FileSystem可。Template.FileSystem = new IncludeFileSystem();我写在了Application_Start事件处理程序里。

 

     第三步:提供测试数据。下面为了简单,没从数据库读取:

复制代码
     public   static   class  WebHelper
    {
        
public   static  Family GetFamily()
        {
            Family family 
=   new  Family()
            {
                Host 
=   " 孙悟空 " ,
                Address 
=   " 大佛山小石村 " ,
                Count 
=   4 ,
                Desc 
=   " 快乐的一家人! "
            };
            
return  family;
        }

        
public   static  List < Member >  GetMembers()
        {
            List
< Member >  members  =   new  List < Member > () { 
                
new  Member(){ ID = 1 , Name = " 孙悟空 " , Age = 42 , Sex = true , Relation = " 本人 " , Desc = " 下等战士,重情重义、绝不欺骗朋友、喜欢帮助人,就算对着敌人也会帮助他。 多次救了地球和全人类。 "  },
                
new  Member(){ ID = 2 , Name = " 牛琪琪 " , Age = 40 , Sex = false , Relation = " 妻子 " , Desc = " 孙悟空和琪琪结婚了,孙悟空没老可琪琪老了! " },
                
new  Member(){ ID = 3 , Name = " 孙悟饭 " , Age = 22 , Sex = true  , Relation = " 长子 " , Desc = " 拥有极高的潜力,每次遇到危险时都会发挥出强大力量来保护自己。 " },
                
new  Member(){ ID = 4 , Name = " 孙悟天 " , Age = 15 , Sex = true  , Relation = " 次子 " , Desc = " 天赋极高,可老想着泡妞! " },
            };
            
return  members;
        }

        
public   static  Member GetMemberInfo( int  id)
        {
            
return  GetMembers().Single(m  =>  m.ID  ==  id);
        }
    }
    
public   class  Family:Drop
    {
        
public   string  Host {  get set ; }

        
public   string  Address {  get set ; }

        
public   int  Count {  get set ; }

        
public   string  Desc {  get set ; }

    }
    
public   class  Member : Drop
    {
        
public   int  ID {  get set ; }

        
public   string  Name {  get set ; }

        
public   int  Age {  get set ; }

        
public   bool  Sex {  get set ; }

        
public   string  Relation {  get set ; }

        
public   string  Desc {  get set ; }
    }
复制代码

 

    第四步:实现母版编程 。一直感觉Asp.net中母版很不错,Asp.net页面的对象模型来实际母版和用户控件也是顺理成章的事。要用DotLiquid的include标签来实现母版应该怎么做呢?这里说说我的解决方法。先看母版模板文件master.htm

复制代码
<! DOCTYPE html PUBLIC  " -//W3C//DTD XHTML 1.0 Transitional//EN "   " http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd " >
< html xmlns = " http://www.w3.org/1999/xhtml " >
< head >
    
< title > {{title}} </ title >
    
< link href = " /css/style.css "  rel = " stylesheet "  type = " text/css "   />

    
< script type = " text/javascript "  src = " /js/jquery-1.6.1.min.js " ></ script >

    {
%  include content_script_optional  % }
</ head >
< body >
    
< div id = " root " >
        
< div  class = " top " >
            
< h2 >
                Top 
in  master </ h2 >
        
</ div >
        {
%  include content_main  % }
        
< div  class = " bottom " >
            
< h2 >
                Bottom 
in  master
            
</ h2 >
        
</ div >
    
</ div >
</ body >
</ html >
复制代码

   

    对,关键还是在templateName上,"content_main"和"content_script_optional" 中的"content"和"optional"是两个约定,还记得IncludeFileSystem.ReadTemplateFile方法吧,就是有点复杂的那个!content指明这里是包含"内容模板(名词来自内容窗体)",optional指明这个include可以没有,模板里到这就可以了,再看ReadTemplateFile方法有个object ns;默认是请求文件名,因为a页面可以用master.htm,b页面也可以用master.htm,ns默认就是"a"或"b",这样做只是为了找到a或b的模板。假如index_content_main.htm首页模板: 

复制代码
< div  class ="center" >
    
< table  class ="tb"  style ="width:400px;" >
        
< caption > 家庭:{{f.Host}}
        
< href ="/list.ashx" > 查看成员 </ a >
        
</ caption >
        
< tr >
            
< th > 户主: </ th >< td > {{f.Host}} </ td >
        
</ tr >
        
< tr >
            
< th > 地址: </ th >< td > {{f.Address}} </ td >
        
</ tr >
        
< tr >
            
< th > 家庭成员数: </ th >< td > {{f.Count}} </ td >
        
</ tr >
        
< tr >
            
< th > 描述: </ th >< td > {{f.Desc}} </ td >
        
</ tr >
    
</ table >
</ div >
复制代码

    index.ashx为访问接口:

复制代码
     public   void  ProcessRequest(HttpContext context)
    {
        context.Response.ContentType 
=   " text/plain " ;
        Template template 
=  TemplateHelper.GetFileTemplate( " master " );
        
string  html  =  template.Render(Hash.FromAnonymousObject( new  { title  =   " dotliquid demo index " ,f = WebHelper.GetFamily()}));
        context.Response.Write(html);
    }
复制代码

    嘿嘿,这里有点怪吧,代码里看不出来和index页面有半点关系,template是根据master.htm得到的。这主要归功于那两个约定和一个ns默认值,如果把index.ashx改名为abc.ashx,上面呈现的代码就要这样写了:

string  html  =  template.Render(Hash.FromAnonymousObject( new  {ns = " index "  , title  =   " dotliquid demo index " ,f = WebHelper.GetFamily()}));

     这几步到些完结!完整例子会附下载!

    

    扩展:还记得代码图右边的几个主要概念吧,下面是三个例子,我写的一个,他们的两个!

复制代码
     public   class  TemplateFilters
    {
        
public   static   string  Text( bool ?  input,  string  trueText,  string  falseText,  string  nullText)
        {
            
if  (input  ==   null return  nullText;
            
return  input  ==   true   ?  trueText : falseText;
        }
        
public   static   string  Text( bool  input,  string  trueText,  string  falseText)
        {
            
return  input  ?  trueText : falseText;
        }
    }
复制代码

     这个是自己的Filters类,里面的每个方法都可以是一个Filter,{% true | text: "男" , "女" %} 此值为"男" ,调用第二个重载,text为方法名称(注意大小写),true是第一个参数input,"男"是第二个参数trueText,"女"是第三个参数falseText。Filter要注册才可用,Template.RegisterFilter(typeof(TemplateFilters));这个我也写在Application_Start。

 

复制代码
     public   class  Rd : Tag  // 随机数
    {
        
int  _max;
        
public   override   void  Initialize( string  tagName,  string  markup, List < string >  tokens)
        {
            
base .Initialize(tagName, markup, tokens);
            _max 
=  Convert.ToInt32(markup);
        }
        
public   override   void  Render(Context context, StreamWriter result)
        {
            result.Write(
new  Random().Next(_max).ToString());
        }
    }

    
public   class  Scale : Block // 概率出现 ,用的单词应该不当!~
    {
        
int  _max;
        
public   override   void  Initialize( string  tagName,  string  markup, List < string >  tokens)
        {
            
base .Initialize(tagName, markup, tokens);
            _max 
=  Convert.ToInt32(markup);
        }
        
public   override   void  Render(Context context, StreamWriter result)
        {
            
if  ( new  Random().Next(_max)  ==   0 )
                
base .Render(context, result);
        }
    }
复制代码

    还是要先注册,Template.RegisterTag<Rd>("rd");Template.RegisterTag<Scale>("scale");

    用法分别是  {% rd 10 %} 值为0到10任意一个数字, {% scale 10 %}这里有10%的概率出现{% endscale %}。

    下载

 

     其实MVC也不错哦

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ASP.NET模板引擎是一种用于生成动态内容的工具。它允许开发人员在Web应用程序中使用模板文件来定义和组织页面布局和结构。该引擎模板和数据结合,生成最终的动态HTML内容,并将其发送给客户端浏览器。 ASP.NET模板引擎的主要功能包括模板定义和数据绑定。模板定义通常使用标记或代码来描述页面的结构和外观。开发人员可以在模板中定义HTML标记,以及使用ASP.NET的特定标记和语法,如服务器控件和数据绑定表达式。 数据绑定是模板引擎的核心功能。它允许开发人员将动态数据与模板文件中的相应区域进行绑定。这使得开发人员能够通过简单的代码和表达式实现动态内容的生成和更新。数据可以来自各种来源,如数据库、Web服务或用户输入。 ASP.NET模板引擎还支持模板继承和重用。开发人员可以定义主模板和子模板,通过继承和重写的方式实现页面布局的模块化和可复用性。这有助于减少代码量,提高开发效率。 除了以上功能,ASP.NET模板引擎还提供了一些辅助功能,如验证、安全性、输出缓存等。这些功能可帮助开发人员提高应用程序的性能和安全性。 总之,ASP.NET模板引擎是一种强大的工具,可用于生成动态的Web内容。它使开发人员能够更轻松地定义和组织页面结构,实现数据和界面的动态绑定,提高开发效率和用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值