玩转Asp.net MVC 的八个扩展点
作者:网络转载 发布时间:[ 2016/3/25 9:44:37 ] 推荐标签:测试开发技术 编程语言
二、Filter
MVC中有四种类型的Filter:IAuthorizationFilter,IActionFilter,IResultFilter,IExceptionFilter
这四个接口有点拦截器的意思,例如:当有异常出现时会被IExceptionFilter类型的Filter拦截,当Action在执行前和执行结束会被IActionFilter类型的Filter拦截。
通过实现IExceptionFilter我们可以自定义一个用来记录日志的Log4NetExceptionFilter:
public class Log4NetExceptionFilter : IExceptionFilter
{
private readonly ILog _logger;
public Log4NetExceptionFilter()
{
_logger = LogManager.GetLogger(GetType());
}
public void OnException(ExceptionContext context)
{
_logger.Error("Unhandled exception", context.Exception);
}
}
后需要将自定义的Filter加入MVC的Filter列表中:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new Log4NetExceptionFilter());
}
}
为了记录Action的执行时间,我们可以在Action执行前计时,Action执行结束后记录log:
public class StopwatchAttribute : ActionFilterAttribute
{
private const string StopwatchKey = "StopwatchFilter.Value";
private readonly ILog _logger= LogManager.GetLogger(typeof(StopwatchAttribute));
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Items[StopwatchKey] = Stopwatch.StartNew();
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var stopwatch = (Stopwatch)filterContext.HttpContext.Items[StopwatchKey];
stopwatch.Stop();
var log=string.Format("controller:{0},action:{1},execution time:{2}ms",filterContext.ActionDescriptor.ControllerDescriptor.ControllerName,filterContext.ActionDescriptor.ActionName,stopwatch.ElapsedMilliseconds)
_logger.Info(log);
}
}
ActionFilterAttribute是一个抽象类,它不但继承了IActionFilter, IResultFilter等Filter,还继承了FilterAttribute类型,这意味着我们可以将这个自定义的类型当作Attribute来标记到某个Action或者Controller上,同时它还是一个Filter,仍然可以加在MVC的Filter中起到全局拦截的作用。
三、HtmlHelper
在Razor页面中,如果需要写一段公用的用来展示html元素的逻辑,你可以选择使用@helper标记,例如:
@helper ShowProduct(List products, string style)
{
@foreach (var product in products)
{
@product.Name
}
}
这一段代码有点像一个方法定义,只需要传入一个list类型和字符串会按照定义的逻辑输出html:
Product list using helper
@ShowProduct(Model.SportProducts, "list-group-item-info")
@ShowProduct(Model.BookProducts, "list-group-item-warning")
@ShowProduct(Model.FoodProducts, "list-group-item-danger")
这样抽取的逻辑只对当前页面有效,如果我们想在不同的页面公用这一逻辑如何做呢?
在Razor中输入@Html即可得到HtmlHelper实例,例如我们可以这样用:@Html.TextBox(“name”)。由此可见我们可以将公用的逻辑扩展在HtmlHelper上:
public static class HtmlHelperExtensions
{
public static ListGroup ListGroup(this HtmlHelper htmlHelper)
{
return new ListGroup();
}
}
public class ListGroup
{
public MvcHtmlString Info(List data, Func getName)
{
return Show(data,getName, "list-group-item-info");
}
public MvcHtmlString Warning(List data, Func getName)
{
return Show(data,getName, "list-group-item-warning");
}
public MvcHtmlString Danger(List data, Func getName)
{
return Show(data,getName, "list-group-item-danger");
}
public MvcHtmlString Show(List data, Func getName, string style)
{
var ulBuilder = new TagBuilder("ul");
ulBuilder.AddCssClass("list-group");
foreach (T item in data)
{
var liBuilder = new TagBuilder("li");
liBuilder.AddCssClass("list-group-item");
liBuilder.AddCssClass(style);
liBuilder.SetInnerText(getName(item));
ulBuilder.InnerHtml += liBuilder.ToString();
}
return new MvcHtmlString(ulBuilder.ToString());
}
}
有了上面的扩展,可以这样使用了:
Product list using htmlHelper
@Html.ListGroup().Info(Model.SportProducts,x=>x.Name)
@Html.ListGroup().Warning(Model.BookProducts,x => x.Name)
@Html.ListGroup().Danger(Model.FoodProducts,x => x.Name)
效果:
四、RazorViewEngine
通过自定义RazorViewEngine可以实现同一份后台代码对应不同风格的View。利用这一扩展能够实现不同的Theme风格切换。再比如站点可能需要在不同的语言环境下切换到不同的风格,也可以通过自定义RazorViewEngine来实现。
下面让我们来实现一个Theme切换的功能,首先自定义一个ViewEngine:
public class ThemeViewEngine: RazorViewEngine
{
public ThemeViewEngine(string theme)
{
ViewLocationFormats = new[]
{
"~/Views/Themes/" + theme + "/{1}/{0}.cshtml",
"~/Views/Themes/" + theme + "/Shared/{0}.cshtml"
};
PartialViewLocationFormats = new[]
{
"~/Views/Themes/" + theme + "/{1}/{0}.cshtml",
"~/Views/Themes/" + theme + "/Shared/{0}.cshtml"
};
AreaViewLocationFormats = new[]
{
"~Areas/{2}/Views/Themes/" + theme + "/{1}/{0}.cshtml",
"~Areas/{2}/Views/Themes/" + theme + "/Shared/{0}.cshtml"
};
AreaPartialViewLocationFormats = new[]
{
"~Areas/{2}/Views/Themes/" + theme + "/{1}/{0}.cshtml",
"~Areas/{2}/Views/Themes/" + theme + "/Shared/{0}.cshtml"
};
}
}
当我们启用这一ViewEngine时,Razor会在/Views/Themes/文件夹下去找View文件。为了启用自定义的ViewEngine,需要将ThemeViewEngine加入到ViewEngines
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
if (!string.IsNullOrEmpty(ConfigurationManager.AppSettings["Theme"]))
{
var activeTheme = ConfigurationManager.AppSettings["Theme"];
ViewEngines.Engines.Insert(0, new ThemeViewEngine(activeTheme));
};
//...
}
}
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11