ASP.NET MVC 框架实践总结
我公司开发团队采用asp.net mvc大致经过了三个阶段
1、摸索期:从今年初公司开发一个新项目时选用了asp.net MVC Preview2,然后用了几天我发现routing似乎有bug,正在这时发现了已经出现了preview2-590,我赶紧将框架“升级”到了590。
2、应用期:项目开发一个多月后我们发现了一些不方便不顺手的地方,感觉缺少一些提高效率的小功能,如当一个路径的参数经过routing路由到一个action后,action及视图页(.aspx/.ascx)上下文里获取它不符合我们的开发逻辑——在应用mvc之前我们都是用Request["id"]的方式获取,但是如果此时如果一个参数被routing"美化"后就得不到了,代码如下:
1 routeCollection.Add("0", new System.Web.Routing.Route("{id}/space/{action}/{page}/{size}",
2 new RouteValueDictionary(new { controller = "space", action = "index", id = "0", page = "3", size = "76" }),
3 new RouteValueDictionary(new { controller = "[^/]+", action = "[^/]+", id = "\\d+", page = "\\d*" }),
4 null
相应的控制器和action代码如下:
public partial class SpaceController : AjaxController
{
[Bll.Filter.SpaceViewFilter]
public void Story(long id, long? classid, int? page, int? size)
{
RenderView("Story");
}
}
控制器代码
现在story方法体内以及story.aspx里Request["id"],Request["page"] 获取不到相应的值!由于开发项目时有些路由规则没有写,打算以后总体调整路由规则,但是出错了,因为根本获取不到参数,我们非常郁闷!
于是我开始下载源码、检阅、跟踪、修改,经过一周左右的时间终于将MVC的流程及原理理了个顺,最后修改加进了一些我们急需的小功能:
修改了System.Web.Mvc的控制器、视图相关的代码,实现了在Action、.aspx/.ascx/.master里可以沿用Request["key"]的方式获取参数(不论routing怎么变都不影响),不区分key的大小
修改了ViewData类,使ViewData["key"]不区分大小写;
增加了一个路由配置类,使路由器可以能过.config文件来配置,如下:
<configuration>
<configSections>
<section name="routeTable" type="System.Web.Mvc.RouteTableSection,System.Web.Mvc" allowDefinition="Everywhere" allowExeDefinition="MachineToApplication" restartOnExternalChanges="true" />
</configSections>
<routeTable>
<routes>
<add name="StoryTaglist" url="/Story/Tag/{id}/{page}/{size}" routeHandlerType="System.Web.Mvc.MvcRouteHandler, System.Web.Mvc">
<defaults controller="Story" action="Tag" classid="0" size="null"/>
</add>
</routes>
</routeTable>
</configuration>
给ViewData增加了一些扩展方法Get<T>(key)类方法,取得viewdata里的某个值,并且转换成指定的对象类型,如果不是该类型或如果是一个数组类型而元素为0个或没有此key都将返回null,代码如下:
var ams = ViewData.Get<IList<KeyValuePair<Duw.Mod.DB.Album, Duw.Mod.DB.ViewFriendandfriendtype>>>("albumList");
if (ams != null)
{ 。。。
}
类完整代码如下:
using System;
using System.Collections;
using System.Collections.Generic;
namespace System.Web.Mvc
{
using System.Collections;
using System.Web.UI;
public static partial class CustomHelper
{
/**//// <summary>
/// 取得viewdata里的某个值,并且转换成指定的对象类型,如果不是该类型或如果是一个数组类型而元素为0个或没有此key都将返回空,
/// </summary>
/// <typeparam name="T">必须为一个非值类型</typeparam>
/// <param name="obj"></param>
/// <param name="key"></param>
/// <returns></returns>
public static T Get<T>(this System.Web.Mvc.ViewData obj, string key)
where T : class
{
if (!obj.ContainsDataItem(key))
return null;
var val = obj[key];
if (val == null)
return null;
var val2 = val as T;
if (val2 == null)
return null;
if (val2 is IEnumerable)
{
var a = (IEnumerable)(val2);
var b = a.GetEnumerator();
//try
//{
if (b.MoveNext())
return val2;
else
return null;
//}
//catch
//{
// return null;
//}
}
else
{
return val2;
}
}
/**//// <summary>
/// 如果没有此key,返回""
/// </summary>
/// <param name="obj"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string GetString(this System.Web.Mvc.ViewData obj, string key)
{
if (!obj.ContainsDataItem(key))
return "";
var val = obj[key];
if (val == null) return "";
return val.ToString();
}
/**//// <summary>
/// 如果没有此key或不能转换成数值类型,返回-1
/// </summary>
/// <param name="obj"></param>
/// <param name="key"></param>
/// <returns></returns>
public static long GetLong(this System.Web.Mvc.ViewData obj, string key)
{
if (!obj.ContainsDataItem(key))
return -1;
var val = obj[key];
if (val == null) return -1;
long v;
if (long.TryParse(val.ToString(), out v))
return v;
else
return -1;
}
/**//// <summary>
/// 如果没有此key或不能转换成数值类型,返回-1
/// </summary>
/// <param name="obj"></param>
/// <param name="key"></param>
/// <returns></returns>
public static int GetInt(this System.Web.Mvc.ViewData obj, string key)
{
if (!obj.ContainsDataItem(key))
return -1;
var val = obj[key];
if (val == null) return -1;
int v;
if (int.TryParse(val.ToString(), out v))
return v;
else
return -1;
}
/**//// <summary>
/// 如果没有此key或不能转换成布尔类型,返回false
/// </summary>
/// <param name="obj"></param>
/// <param name="key"></param>
/// <returns></returns>
public static bool GetBool(this System.Web.Mvc.ViewData obj, string key)
{
if (!obj.ContainsDataItem(key))
return false;
var val = obj[key];
if (val == null) return false;
bool v;
if (bool.TryParse(val.ToString(), out v))
return v;
else
return false;
}
/**//// <summary>
/// 如果没有此key或不能转换成数值类型,返回-1.0
/// </summary>
/// <param name="obj"></param>
/// <param name="key"></param>
/// <returns></returns>
public static double GetDouble(this System.Web.Mvc.ViewData obj, string key)
{
if (!obj.ContainsDataItem(key))
return -1.0;
var val = obj[key];
if (val == null) return -1.0;
double v;
if (double.TryParse(val.ToString(), out v))
return v;
else
return -1.0;
}
/**//// <summary>
/// 如果没有此key或不能转换成数值类型,返回0.0;如果超过float的范围并且在double范围内则自动截取为float类型值返回
/// </summary>
/// <param name="obj"></param>
/// <param name="key"></param>
/// <returns></returns>
public static float GetFloat(this System.Web.Mvc.ViewData obj, string key)
{
double val = obj.GetDouble(key);
if (val == 0.0)
return 0.0f;
else
return (float)val;
}
/**//// <summary>
/// 判断某一个key值是否存在;并且如果它是一个枚举对象还要判断它是否包含一个以上的元素
/// </summary>
/// <param name="obj"></param>
/// <param name="key"></param>
/// <returns></returns>
public static bool Has(this System.Web.Mvc.ViewData obj, string key)
{
if (!obj.ContainsDataItem(key))
return false;
var val = obj[key];
if (val == null)
return false;
if (val is IEnumerable)
{
var a = (IEnumerable)(val);
var b = a.GetEnumerator();
try
{
if (b.MoveNext())
return true;
else
return false;
}
catch
{
return false;
}
}
else
{
return true;
}
}
}
}
给controller增加一个类似.aspx里的Url.Action("story","space",{id=34})的方法Util.GetUrl():
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Web.Mvc;
using System.Web.Routing;
namespace System.Web.Mvc
{
public class Util
{
public static string GetUrl(ControllerContext context, RouteValueDictionary values)
{
string routeName = "";
VirtualPathData vpd = string.IsNullOrEmpty(routeName) ? RouteTable.Routes.GetVirtualPath(context, values) : RouteTable.Routes.GetVirtualPath(context, routeName, values);
return vpd.VirtualPath;
//return UrlRewriterHelper.GetUrl(context, values, RouteTable.Routes);
}
}
}
3、框架性能调优与重造,经过半年的应用开发、总结,发现MVC性能及routing不是很理想,于是又开始进行性能调优与修改,最后改成了现在的“版本”,详情请看下一篇性能调优。