【转载】创建定制ASP.NET MVC视图引擎
2013-04-06 11:49
405 查看
ASP.NET MVC started off with the premise of being a very ‘pluggable’ framework and we can see it almost everywhere. You can plug in any IoC container, Testing Framework even View Engines! There are two view engines provided by default - the WebForms View engine (views with .aspx extention) and the Razor view engine (view with .cshtml extension).
Today we’ll see how the pluggability of view engines can be leveraged in our own web application.
We will create a new custom view engine for MVC applications. This is just a very simple implementation that can be modified for your project requirements.
The interface IView provides a Render method. This is responsible for defining how the View is rendered. This method accepts the first argument as ‘ViewContext’. This object contains the information that is related for view rendering. Technically, from this object, the Model object containing the data to be displayed in the view can be extracted. The second object is the TextWriter which defines the HTML format strings to be used during rendering.
The interface IViewEngine defines methods for View Engine. This provides methods as below:
FindView: Finds the specific view (file) by using the specified controller context.
FindPartialView: Find the specific partial view by using the specified controller context.
ReleaseView: Releases the specified view by using the specified controller context.
Here the controller context means the information in the HTTP request that matches route expression which contains the controller name and the action method in the controller.
Add the following code in it:
namespace MVC40_CustomViewEngine.Models
{
public class EmployeeInfo
{
public int EmpNo { get; set; }
public string EmpName { get; set; }
public string DeptName { get; set; }
public string Designation { get; set; }
public int Salary { get; set; }
}
public class DataAccess
{
List<EmployeeInfo> lstEmps = new List<EmployeeInfo>();
public DataAccess()
{
lstEmps.Add(new EmployeeInfo() {EmpNo=1,EmpName="A",DeptName="D1",Designation="TL", Salary=45000 });
lstEmps.Add(new EmployeeInfo() { EmpNo = 2, EmpName = "B", DeptName = "D1", Designation = "TL", Salary = 45000 });
lstEmps.Add(new EmployeeInfo() { EmpNo = 3, EmpName = "C", DeptName = "D2", Designation = "PM", Salary = 55000 });
lstEmps.Add(new EmployeeInfo() { EmpNo = 4, EmpName = "D", DeptName = "D2", Designation = "PM", Salary = 55000 });
lstEmps.Add(new EmployeeInfo() { EmpNo = 5, EmpName = "E", DeptName = "D3", Designation = "PH", Salary = 65000 });
lstEmps.Add(new EmployeeInfo() { EmpNo = 6, EmpName = "F", DeptName = "D3", Designation = "PH", Salary = 65000 });
}
public List<EmployeeInfo> GetEmps()
{
return lstEmps;
}
}
}
Step 2: In the MVC project, add a new folder, name it as ‘CustomViewEngine’. Add the class file of name DataView.cs in it. Write the following code in it:
using MVC40_CustomViewEngine.Models;
using System.Collections.Generic;
using System.Web.Mvc;
namespace MVC40_CustomViewEngine.CustomViewEngine
{
/// <summary>
/// Class for defining the actual View. This class is actual responsible for defining the HTML layouting
/// of the view.
/// </summary>
public class DataView : IView
{
/// <summary>
/// The Method used to Render the HTML
/// </summary>
/// <param name="viewContext"></param>
/// <param name="writer"></param>
public void Render(ViewContext viewContext, System.IO.TextWriter writer)
{
//Step 1 => Get the Model Bind with the View. (Note, this value is received from the controller)
var Model = viewContext.ViewData.Model;
var Emps = Model as List<EmployeeInfo>;
//Step 2 => Now Geterate the HTML Table
writer.Write("<table border=1><tr><th>EmpNo</th><th>EmpName</th><th>
DeptName</th><th>Designation</th><th>Salary</th></tr>");
foreach (EmployeeInfo Emp in Emps)
{
writer.Write("<tr><td>"+Emp.EmpNo+"</td><td>"+Emp.EmpName+"</td><td>"+
Emp.DeptName+"</td><td>"+Emp.Designation+"</td></tr>");
}
writer.Write("</table>");
}
}
}
The DataView class implements the IView interface and implements its ‘Render’ method. The method reads the model object received from the controller. The TextWriter instance is used to create the HTML table for displaying the information.
Step 3: In the folder created in Step 2, add a new class file of name ‘DataViewEngine’. Add the following code in it:
using System;
using System.Web.Mvc;
namespace MVC40_CustomViewEngine.CustomViewEngine
{
/// <summary>
/// The class Implementing 'IViewEngine' interface. This Interface methods for ViewEngine
/// </summary>
public class DataViewEngine : IViewEngine
{
/// <summary>
/// Method for Partial Viuew
/// </summary>
/// <param name="controllerContext"></param>
/// <param name="partialViewName"></param>
/// <param name="useCache"></param>
/// <returns></returns>
public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
{
throw new NotImplementedException();
}
/// <summary>
/// Method for View
/// </summary>
/// <param name="controllerContext"></param>
/// <param name="viewName"></param>
/// <param name="masterName"></param>
/// <param name="useCache"></param>
/// <returns></returns>
public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
if (viewName == "DataView")
{
return new ViewEngineResult(new DataView(), this);
}
else
{
return new ViewEngineResult(new string[] {"This View Engine is Currently in design, will be launched soon"});
}
}
/// <summary>
/// Release the view
/// </summary>
/// <param name="controllerContext"></param>
/// <param name="view"></param>
public void ReleaseView(ControllerContext controllerContext, IView view)
{
}
}
}
The class DataViewEngine, implements IViewEngine interface and implements its FindView method. This method checks the ViewName specified by the controller’s action method and if the name matches it returns an object of ViewEngineResult object. This object is responsible for locating the IView typed object, in this case it is DataView class.
If you provided markup files for providing design-time markup, the FindView and the FindPartialView methods are the points to load the markup file.
Step 4: Open the Global.asax.cs and register the view engine in Application_Start method as below:
ViewEngines.Engines.Add(new DataViewEngine());
Step 5: In the controller folder, add a new controller of name EmployeeInfoController and add the following code in the index method:
public ActionResult Index()
{
var Emps = new DataAccess().GetEmps();
ViewData.Model = Emps;
return View("DataView");
}
The method returns the ViewResult by accepting the View name as string. The MVC view engine matches this string with the Custom View class and executes the corresponding Render method.
Run the application and navigate to the EmployeeInfo/Index the result will be as below:
It shows the HTML table with Employee data in it.
Building reporting engines to create reports as we saw above, is just one such use case.
Download the entire source code (Github)
Today we’ll see how the pluggability of view engines can be leveraged in our own web application.
We will create a new custom view engine for MVC applications. This is just a very simple implementation that can be modified for your project requirements.
Internals of a View Engine
As we know, in controllers each action method has the return type of ‘ActionResult’. This is an abstract class which forms a basic implementation for various classes and one of the derived class from ActionResult is ‘ViewResult’. This class is used to render a View using the IView instance that is returned by an implementation of the IViewEngine. This means that if we want to create our custom view engine, we must use the IView and IViewEngine interfaces.The interface IView provides a Render method. This is responsible for defining how the View is rendered. This method accepts the first argument as ‘ViewContext’. This object contains the information that is related for view rendering. Technically, from this object, the Model object containing the data to be displayed in the view can be extracted. The second object is the TextWriter which defines the HTML format strings to be used during rendering.
The interface IViewEngine defines methods for View Engine. This provides methods as below:
FindView: Finds the specific view (file) by using the specified controller context.
FindPartialView: Find the specific partial view by using the specified controller context.
ReleaseView: Releases the specified view by using the specified controller context.
Here the controller context means the information in the HTTP request that matches route expression which contains the controller name and the action method in the controller.
Building the ‘Report Engine’
Step 1: Open Visual Studio 2012 and create a new MVC application. Name it as ‘MVC40_CustomViewEngine’. In the Models folder, add a new class file, name it as ‘DataClasses’.Add the following code in it:
namespace MVC40_CustomViewEngine.Models
{
public class EmployeeInfo
{
public int EmpNo { get; set; }
public string EmpName { get; set; }
public string DeptName { get; set; }
public string Designation { get; set; }
public int Salary { get; set; }
}
public class DataAccess
{
List<EmployeeInfo> lstEmps = new List<EmployeeInfo>();
public DataAccess()
{
lstEmps.Add(new EmployeeInfo() {EmpNo=1,EmpName="A",DeptName="D1",Designation="TL", Salary=45000 });
lstEmps.Add(new EmployeeInfo() { EmpNo = 2, EmpName = "B", DeptName = "D1", Designation = "TL", Salary = 45000 });
lstEmps.Add(new EmployeeInfo() { EmpNo = 3, EmpName = "C", DeptName = "D2", Designation = "PM", Salary = 55000 });
lstEmps.Add(new EmployeeInfo() { EmpNo = 4, EmpName = "D", DeptName = "D2", Designation = "PM", Salary = 55000 });
lstEmps.Add(new EmployeeInfo() { EmpNo = 5, EmpName = "E", DeptName = "D3", Designation = "PH", Salary = 65000 });
lstEmps.Add(new EmployeeInfo() { EmpNo = 6, EmpName = "F", DeptName = "D3", Designation = "PH", Salary = 65000 });
}
public List<EmployeeInfo> GetEmps()
{
return lstEmps;
}
}
}
Step 2: In the MVC project, add a new folder, name it as ‘CustomViewEngine’. Add the class file of name DataView.cs in it. Write the following code in it:
using MVC40_CustomViewEngine.Models;
using System.Collections.Generic;
using System.Web.Mvc;
namespace MVC40_CustomViewEngine.CustomViewEngine
{
/// <summary>
/// Class for defining the actual View. This class is actual responsible for defining the HTML layouting
/// of the view.
/// </summary>
public class DataView : IView
{
/// <summary>
/// The Method used to Render the HTML
/// </summary>
/// <param name="viewContext"></param>
/// <param name="writer"></param>
public void Render(ViewContext viewContext, System.IO.TextWriter writer)
{
//Step 1 => Get the Model Bind with the View. (Note, this value is received from the controller)
var Model = viewContext.ViewData.Model;
var Emps = Model as List<EmployeeInfo>;
//Step 2 => Now Geterate the HTML Table
writer.Write("<table border=1><tr><th>EmpNo</th><th>EmpName</th><th>
DeptName</th><th>Designation</th><th>Salary</th></tr>");
foreach (EmployeeInfo Emp in Emps)
{
writer.Write("<tr><td>"+Emp.EmpNo+"</td><td>"+Emp.EmpName+"</td><td>"+
Emp.DeptName+"</td><td>"+Emp.Designation+"</td></tr>");
}
writer.Write("</table>");
}
}
}
The DataView class implements the IView interface and implements its ‘Render’ method. The method reads the model object received from the controller. The TextWriter instance is used to create the HTML table for displaying the information.
Step 3: In the folder created in Step 2, add a new class file of name ‘DataViewEngine’. Add the following code in it:
using System;
using System.Web.Mvc;
namespace MVC40_CustomViewEngine.CustomViewEngine
{
/// <summary>
/// The class Implementing 'IViewEngine' interface. This Interface methods for ViewEngine
/// </summary>
public class DataViewEngine : IViewEngine
{
/// <summary>
/// Method for Partial Viuew
/// </summary>
/// <param name="controllerContext"></param>
/// <param name="partialViewName"></param>
/// <param name="useCache"></param>
/// <returns></returns>
public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
{
throw new NotImplementedException();
}
/// <summary>
/// Method for View
/// </summary>
/// <param name="controllerContext"></param>
/// <param name="viewName"></param>
/// <param name="masterName"></param>
/// <param name="useCache"></param>
/// <returns></returns>
public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
if (viewName == "DataView")
{
return new ViewEngineResult(new DataView(), this);
}
else
{
return new ViewEngineResult(new string[] {"This View Engine is Currently in design, will be launched soon"});
}
}
/// <summary>
/// Release the view
/// </summary>
/// <param name="controllerContext"></param>
/// <param name="view"></param>
public void ReleaseView(ControllerContext controllerContext, IView view)
{
}
}
}
The class DataViewEngine, implements IViewEngine interface and implements its FindView method. This method checks the ViewName specified by the controller’s action method and if the name matches it returns an object of ViewEngineResult object. This object is responsible for locating the IView typed object, in this case it is DataView class.
If you provided markup files for providing design-time markup, the FindView and the FindPartialView methods are the points to load the markup file.
Step 4: Open the Global.asax.cs and register the view engine in Application_Start method as below:
ViewEngines.Engines.Add(new DataViewEngine());
Step 5: In the controller folder, add a new controller of name EmployeeInfoController and add the following code in the index method:
public ActionResult Index()
{
var Emps = new DataAccess().GetEmps();
ViewData.Model = Emps;
return View("DataView");
}
The method returns the ViewResult by accepting the View name as string. The MVC view engine matches this string with the Custom View class and executes the corresponding Render method.
Run the application and navigate to the EmployeeInfo/Index the result will be as below:
It shows the HTML table with Employee data in it.
Conclusion
As we saw, building a custom view engine is pretty easy in ASP.NET MVC. It is one of the heavily used extension feature in MVC.Building reporting engines to create reports as we saw above, is just one such use case.
Download the entire source code (Github)
相关文章推荐
- ASP.NET MVC自定义视图引擎ViewEngine 创建Model的专属视图
- ASP.NET MVC 3: Razor视图引擎中 @: 和<text> 语法【转载】
- 转载:ASP.NET MVC扩展自定义视图引擎支持多模板&动态换肤skins机制
- ASP.NET MVC 5 Web编程4 -- Razor视图引擎
- Asp.net MVC 3 之 Razor 视图引擎
- ASP.NET MVC Razor 视图引擎
- ASP.NET MVC 3 Razor 视图引擎 基本语法
- AspNet MVC与T4,我定制的视图模板
- 【转载】介绍“Razor”— ASP.NET的一个新视图引擎
- ASP.NET MVC——Razor视图引擎
- 如何创建强类型的ASP.NET MVC视图
- ASP.NET MVC :实现我们自己的视图引擎
- asp.net mvc (4) - 自定义视图引擎 View/ViewEngine
- 逃脱Asp.Net MVC框架/枷锁,使用Razor视图引擎
- (转)Asp.Net Mvc视图引擎Razor介绍
- ASP.NET mvc 自定义XSLT视图引擎 遇到的问题【高手请进有疑难杂症】
- ASP.NET MVC 视图引擎
- 一步一步学习asp.net mvc 1.0 创建NerdDinner程序Part1(转载)
- ASP.NET MVC 现在已有四种主要的视图引擎 razor,aspx,spark,nhaml
- ASP.Net MVC开发基础学习笔记(3):Razor视图引擎、控制器与路由机制学习