千家信息网

如何理解ASP.NET MVC中的FluentHtml与连续接口

发表于:2024-12-13 作者:千家信息网编辑
千家信息网最后更新 2024年12月13日,这篇文章将为大家详细讲解有关如何理解ASP.NET MVC中的FluentHtml与连续接口,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。我们力求页面
千家信息网最后更新 2024年12月13日如何理解ASP.NET MVC中的FluentHtml与连续接口

这篇文章将为大家详细讲解有关如何理解ASP.NET MVC中的FluentHtml与连续接口,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

我们力求页面层代码简洁并具有较好的可读性,在ASP.NET MVC的平台上,我们以新的起点来实现这一目标.MvcContrib.FluentHtml和Spark ViewEngine给我们做出了榜样.本文将以MvcContrib.FluentHtml为例探究它的实现机制:Fluent Interface.

在MvcContrib.FluentHtml的应用中,我们随处可以见到下面的代码:

< %= this.TextBox(x => x.Person.Name).Title("Enter the person's name").Label("Name:") %> ……    < %= this.Select(x => x.Person.Gender).Options(Model.Genders).Size(5).Label("Gender:")  .Title("Select the person's gender") %>

浏览器中生成的代码为:

< LABEL id=Person_Name_Label for=Person_Name>Name:< /LABEL> < INPUT id=Person_Name title="Enter the person's name" value=Jeremy maxLength=50 name=Person.Name>  .  < SELECT id=Person_Gender title="Select the person's gender" size=5 name=Person.Gender>< OPTION selected value=M>Male< /OPTION>< OPTION value=F>Female< /OPTION>< /SELECT>

上面对动态生成TextBox和Select的代码很有意思,我们使用普通的方式在页面上生成同样的客户端代码,CS代码大致是这样的:

Label label = new Label();   label.Text = "Name";   TextBox textbox= new TextBox();   textbox.ToolTip ="Enter the person's name";   textbox.ID = "No.10001";   textbox.ID = "Person.Name";

而FluentHtml创建页面元素的方式让我们很容易联想到StringBuilder的使用:

StringBuilder stringbuilder = new StringBuilder();   stringbuilder.Append("Hello").Append(" ").Append("World!");

Fulent Interface 这种实现编程方式就是"Fluent Interface",这并不是什么新概念,2005年Eric Evans 和Martin Fowler就为这种实现方式命名.源文档 可以通过维基百科中对Fluent Interface的描述获得一个基本的了解:In software engineering, a fluent interface (as first coined by Eric Evans and Martin Fowler) is a way of implementing an object oriented API in a way that aims to provide for more readable code.

我们分解上面的话:

它是面向对象API的一种实现方式,目的是增加代码的可读性.。既然我们最熟悉的是StringBuilder,我们就从这个线索追下去:打开Reflector,很容易找到StringBuilder的Append方法:

public StringBuilder Append(string value)  {  if (value != null)  {   string stringValue = this.m_StringValue;   IntPtr currentThread = Thread.InternalGetCurrentThread();   if (this.m_currentThread != currentThread)   {   stringstringValue = string.GetStringForStringBuilder(stringValue, stringValue.Capacity);   }   int length = stringValue.Length;   int requiredLength = length + value.Length;   if (this.NeedsAllocation(stringValue, requiredLength))   {   string newString = this.GetNewString(stringValue, requiredLength);   newString.AppendInPlace(value, length);   this.ReplaceString(currentThread, newString);   }   else   {   stringValue.AppendInPlace(value, length);   this.ReplaceString(currentThread, stringValue);   }  }  return this;  }

阅读这段有两个特别要注意的点:1.方法的返回值是StringBuilder类型 2.***一句:return this;为了深刻理解,我们写一个简单的StringBuilder:

public interface IContentBuilder  {   void WriteContent();   IContentBuilder Append(string partialContent);  }  public class TestContentBuilder : IContentBuilder  {   string temp;   #region IContentBuilder Members    void IContentBuilder.WriteContent()   {   Console.Write(temp);   }    IContentBuilder IContentBuilder.Append(string partialContent)   {   temp += partialContent;   return this;   }    #endregion  }  … …  //调用代码  IContentBuilder t = new TestContentBuilder();   t.Append("test").Append("Hello").WriteContent();

跑一下代码,和StringBuilder效果是一样的.从上面的应用也可以看出:Fluent Interface经常用来完成对象的构造和属性赋值.

言归正传:FluentHTML了解了Fluent Interface,我们来看一下MVCContrib.FluentHTML的实现,这里以TextBox为例进行考察,首先看一下它的继承关系:

public class TextBox : TextInput  public abstract class TextInput : Input, ISupportsMaxLength where T : TextInput  public abstract class Input : FormElement where T : Input, Ielement

泛型是一种高层次的算法抽象,我们就通过Input一窥端倪:

public abstract class Input : FormElement where T : Input, IElement  {  protected object elementValue;  protected Input(string type, string name) : base(HtmlTag.Input, name)  {   builder.MergeAttribute(HtmlAttribute.Type, type, true);  }  protected Input(string type, string name, MemberExpression forMember, IEnumerable behaviors)   : base(HtmlTag.Input, name, forMember, behaviors)  {   builder.MergeAttribute(HtmlAttribute.Type, type, true);  }  ///   /// Set the 'value' attribute.  ///   /// The value for the attribute.  public virtual T Value(object value)  {   elementValue = value;   return (T)this;  }  ///   /// Set the 'size' attribute.  ///   /// The value for the attribute.  public virtual T Size(int value)  {   Attr(HtmlAttribute.Size, value);   return (T)this;  }  protected override void PreRender()  {   Attr(HtmlAttribute.Value, elementValue);   base.PreRender();  }  }  以Size方法为例,可以看出这是一种典型的Fluent Interface实现:  public virtual T Size(int value)  {  Attr(HtmlAttribute.Size, value);  return (T)this;  }

分析到这里,上面的语句中还有一点比较奇怪,就是Lambda表达式的部分:

this.TextBox(x => x.Person.Name).Title("Enter the person's name").Label("Name:")

TextBox的实现代码里面我们没有看到对Lambda表达式的支持.那是在什么地方完成的呢?通过跟进,我们来到了ViewDataContainerExtensions,它是IViewDataCon

namespace MvcContrib.FluentHtml  {  ///   /// Extensions to IViewDataContainer  ///   public static class ViewDataContainerExtensions  {   ///    /// Generate an HTML input element of type 'text' and set its value from ViewData based on the name provided.   ///    /// The view.   /// Value of the 'name' attribute of the element.Also used to derive the 'id' attribute.   public static TextBox TextBox(this IViewDataContainer view, string name)   {   return new TextBox(name).Value(view.ViewData.Eval(name));   }  … …

tainer 的Extension Method:

看一下return new TextBox(name).Value(view.ViewData.Eval(name));所以这里就成了TextBox定义方法链的***步.

FluentHtml与连续接口总结

为了能够在View中能够简洁清晰的构造HTML元素,Asp.net MVC中通过htmlHelper.InputHelper来实现页面元素的构造. 页面层所使用的<%=>,HTML也是htmlHelper的Extension Method.相比较起来,htmlHelper提供了基础的页面控件定义和构造,而FluentHTML表现的更为灵活。

关于如何理解ASP.NET MVC中的FluentHtml与连续接口就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

0