刚用MVC完成一个小项目,总结一些MVC技巧
2010-04-08 02:06
393 查看
刚用MVC完成了一个小项目,MVC技术又有了一次提升,所以,再次写一点总结性的东西。
开发环境:Visual Studio 2010 RC, MVC 2 RC, Entity Framework, SQL Server 2008
(原创,和微软官方做法不同,可以不修改IIS设置就达到目的)
传送门:/article/5207506.html
而在网站MapRoute的时候却只能识别 Controller,因此会出现错误。
假设,我在新建一个MVC项目后,直接新建一个Areas,并且命名为Admin,新建一个Home Controller
运行,弹出以下错误:
“/”应用程序中的服务器错误。
The controller name 'Home' is ambiguous between the following types:
遇到这种情况,只要这样就可以了
调用 MapRoute 的时候在后面多传入一个 String[] ,并且填入你需要 Route 的那个 Areas 的 Controller 所在的命名空间
注意!2个地方都要改
虽然可以在传入的 filterContext 中调用到,但是很不方便。
这时候,其实可以把4个Filter继承一下,自己写一个新的,并在内部放入ViewData等私有字段
用 IAuthorizationFilter 来举个例子:
然后需要使用 IAuthorizationFilter 的时候只要继承上面的 AuthorizationFilter 即可
旧版本:
大家觉得MVC的架构变了,但其实原理和Asp.net一样,还是用 Response来输出数据
所以,只要在 Action 的 Return 函数前调用 Response.Write("text"); 即可实现。
其实和以前一样,下面举个例子,在一个页面中弹出一个对话框后再跳转到别的页面
修改版:
这里,我换了一种思路来实现:
然后返回一个 用户控件
可以在不同环境下生成3中不同的Web.config版本
在VS中调试的时候,直接使用Web.config
用Debug发布的时候,使用Web.Debug.config
用Release发布的时候,使用Web.Release.config
然后,这三个文件怎么用呢?
你可以实现 Web.config 存在一个字段,然后当发布的时候用 Web.Debug.config 内的字段替换掉
也可以本来不存在,发布的时候添加
更可以本来存在,发布的时候删除
这里就做简单的介绍,介绍一种替代的方法:
代码
这样,在用Debug发布的时候,那个字段就会被替换掉,具体用法在Web.Debug.config文件内写了一个网站,上面有全部的语法
其实理论上所有的错误肯定产生于Controller中,但有2种情况下,就不会被捕捉了
1、页面不存在的时候,找不到对应的Controller,那没有任何Controller被执行,所以自然也不会捕捉到错误了
2、在 IAuthorizationFilter 下发生错误的时候,错误捕捉代码在IExceptionFilter中,而IAuthorizationFilter的优先权高于IExceptionFilter,所以也就捕捉不到了
那有没有别的方法?参考了一个老外的代码,发现了一种完美的方法
把这段代码放到 Global.asax 中,并且新建一个 Controller 叫做 Error
这样,就可以捕捉所有错误了。
但其实,这样也不是完美的,因为如果你参考了我第一个问题中,在IIS6下不修改IIS设置,运行了MVC,那当后缀名不是.aspx的时候,错误不会被捕捉
因为这时候输入的地址根本没有交给网站来处理,IIS直接抛出了错误,因为IIS认为这个后缀名不是你所能执行的
而这些页面中的主要Model类型是不同的,所以,这个View User Control肯定不能用强类型了
不能用强类型了,那怎么用 TextBoxFor 等强类型方法呢?
其实我的理解,强类型主要就是利用了 lambda表达式和反射,对Model进行了类型判断,防止出错
lambda中是何如识别Model类型的呢? vs编译器会自动根据上下文来判断,所以,如果绑定了强类型,那么
<%= Html.TextBoxFor(Model => Model.Passport)%>
就会被自动识别出来
但是上面那个场景,View User Control 中使用的Model和页面中的不同,如果强制绑定了Model,就会出错,提示Model类型不正确,其实可以这样做:
在View User Control中不绑定强类型,然后这样调用强类型方法
这里有什么区别呢?因为不绑定强类型,编译器不能识别传入的参数是什么类型,那我手动指定一下即可
这样既可以用强类型方法,也不会和主页面有冲突了
这里最好不要用Model,如果你的页面Model类型也是User,并且传入了Model数据,那个这个View User Control中的表单也会被填充
如有错误,或者有疑问,可以直接留言,我会及时答复
或者发我邮箱:dozer@dozer.net.cn
开发环境:Visual Studio 2010 RC, MVC 2 RC, Entity Framework, SQL Server 2008
1、不对IIS做任何修改,如何在IIS6下运行MVC?
这个可以参考我前面一篇文章(原创,和微软官方做法不同,可以不修改IIS设置就达到目的)
传送门:/article/5207506.html
2、不同Areas的Controller重复导致的问题
两个不同的Areas会有不同的命名空间,但是会有相同的 Controller而在网站MapRoute的时候却只能识别 Controller,因此会出现错误。
假设,我在新建一个MVC项目后,直接新建一个Areas,并且命名为Admin,新建一个Home Controller
运行,弹出以下错误:
“/”应用程序中的服务器错误。
The controller name 'Home' is ambiguous between the following types:
MvcApplication1.Controllers.HomeController
MvcApplication1.Areas.Admin.Controllers.HomeController
遇到这种情况,只要这样就可以了context.MapRoute( "Web_default", "{controller}/{action}/{id}", new {controller="Home", action = "Index", id = "" }, new string[] { "MvcApplication1.Areas.Web.Controllers" } );
调用 MapRoute 的时候在后面多传入一个 String[] ,并且填入你需要 Route 的那个 Areas 的 Controller 所在的命名空间
注意!2个地方都要改
3、关于Filter
MVC提供的4个Filter很方便,但是有一个问题,Filter中不能直接调用 ViewData,TempData等字段。虽然可以在传入的 filterContext 中调用到,但是很不方便。
这时候,其实可以把4个Filter继承一下,自己写一个新的,并在内部放入ViewData等私有字段
用 IAuthorizationFilter 来举个例子:
public abstract class BaseFilterAttribute : FilterAttribute { //这里可以根据自己的喜好来设定 protected HttpSessionStateBase Session; protected ModelStateDictionary State; protected ViewDataDictionary ViewData; protected TempDataDictionary TempData; protected HttpRequestBase Request; protected Dictionary<string, string> RouteValues; protected UrlHelper Url; protected void Initialize(ControllerContext filterContext) { //初始化 Request = filterContext.RequestContext.HttpContext.Request; RouteValues = new Dictionary<string, string>(); foreach (var v in filterContext.RequestContext.RouteData.Values) { RouteValues.Add(v.Key,v.Value.ToString()); } ViewData = filterContext.Controller.ViewData; TempData = filterContext.Controller.TempData; State = ViewData.ModelState; Session = filterContext.RequestContext.HttpContext.Session; Url = new UrlHelper(filterContext.RequestContext); } } public abstract class AuthorizationFilter : BaseFilterAttribute, IAuthorizationFilter { public void OnAuthorization(AuthorizationContext filterContext) { //调用初始化函数 Initialize(filterContext); onAuthorization(filterContext); } //这里把原来的 OnAuthorization 替换了一下 public abstract void onAuthorization(AuthorizationContext filterContext); }
然后需要使用 IAuthorizationFilter 的时候只要继承上面的 AuthorizationFilter 即可
4、MVC中控制js代码(修改版)
很多网友留言,说我这一块不好。我也发现的确如此,所以想了另一种方法,虽然不是最完美,但坐到了MVC的宗旨,view和controller分离旧版本:
大家觉得MVC的架构变了,但其实原理和Asp.net一样,还是用 Response来输出数据
所以,只要在 Action 的 Return 函数前调用 Response.Write("text"); 即可实现。
其实和以前一样,下面举个例子,在一个页面中弹出一个对话框后再跳转到别的页面
public ActionResult Test() { //弹出对话框 Response.Write(<script>alert('test');</script>)); //跳转到index Response.Write("<script>window.location.href='" + Url.Action("index") + "';</script>"); return null; }
修改版:
这里,我换了一种思路来实现:
public ActionResult Test() { ViewData["JSAlert"] = "保存成功"; ViewData["JSHref"] = "保存成功"; return PartialView("JS"); }
然后返回一个 用户控件
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> <script type="text/jscript"> alert('<%=ViewData["JSAlert"] %>'); window.location.href = '<%=ViewData["JSHref"] %>'; </script>
5、Web.Debug.config 和 Web.Release.config 的用法
利用 Web.config, Web.Debug.config, Web.Release.config可以在不同环境下生成3中不同的Web.config版本
在VS中调试的时候,直接使用Web.config
用Debug发布的时候,使用Web.Debug.config
用Release发布的时候,使用Web.Release.config
然后,这三个文件怎么用呢?
你可以实现 Web.config 存在一个字段,然后当发布的时候用 Web.Debug.config 内的字段替换掉
也可以本来不存在,发布的时候添加
更可以本来存在,发布的时候删除
这里就做简单的介绍,介绍一种替代的方法:
代码
//Web.config下,假设有这个字段 <connectionStrings> <add name="ModelContainer" connectionString="metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient;provider connection string="Data Source=192.168.174.131,1433;Initial Catalog=Port80;User ID=port80;Password=port80;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient"/> </connectionStrings> //在Web.Debug.config下 <connectionStrings> <add name="ModelContainer" connectionString</span>="metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient;provider connection string="Data Source=.\sqlexpress;Initial Catalog=Port80;Integrated Security=True"" providerName="System.Data.EntityClient" xdt:Transform="Replace" xdt:Locator="Match(name)"/> </connectionStrings>
这样,在用Debug发布的时候,那个字段就会被替换掉,具体用法在Web.Debug.config文件内写了一个网站,上面有全部的语法
6、MVC中捕捉错误
MVC中,有一个Filter可以捕捉错误,但是它的用法是利用Attribute来实现的,而且只能加在Controller和Action上,所以不能捕捉别出的错误其实理论上所有的错误肯定产生于Controller中,但有2种情况下,就不会被捕捉了
1、页面不存在的时候,找不到对应的Controller,那没有任何Controller被执行,所以自然也不会捕捉到错误了
2、在 IAuthorizationFilter 下发生错误的时候,错误捕捉代码在IExceptionFilter中,而IAuthorizationFilter的优先权高于IExceptionFilter,所以也就捕捉不到了
那有没有别的方法?参考了一个老外的代码,发现了一种完美的方法
protected void Application_Error(object sender, EventArgs e) { Exception exception = Server.GetLastError(); Response.Clear(); HttpException httpException = exception as HttpException; RouteData routeData = new RouteData(); routeData.Values.Add("controller", "Error"); if (httpException == null) { routeData.Values.Add("action", "Index"); } else //It's an Http Exception, Let's handle it. { switch (httpException.GetHttpCode()) { case 404: // Page not found. routeData.Values.Add("action", "HttpError404"); break; case 500: // Server error. routeData.Values.Add("action", "HttpError500"); break; // Here you can handle Views to other error codes. // I choose a General error template default: routeData.Values.Add("action", "General"); break; } } // Pass exception details to the target error View. routeData.Values.Add("error", exception.Message); // Clear the error on server. Server.ClearError(); // Call target Controller and pass the routeData. IController errorController = new WEB.Controllers.ErrorController(); errorController.Execute(new RequestContext( new HttpContextWrapper(Context), routeData)); }
把这段代码放到 Global.asax 中,并且新建一个 Controller 叫做 Error
namespace WEB.Controllers { public class ErrorController : Controller { public ActionResult Index(string error) { ViewData["Title"] = "WebSite 网站内部错误"; ViewData["Description"] = error; return View("Index"); } public ActionResult HttpError404(string error) { ViewData["Title"] = "HTTP 404- 无法找到文件"; ViewData["Description"] = error; return View("Index"); } public ActionResult HttpError500(string error) { ViewData["Title"] = "HTTP 500 - 内部服务器错误"; ViewData["Description"] = error; return View("Index"); } public ActionResult General(string error) { ViewData["Title"] = "HTTP 发生错误"; ViewData["Description"] = error; return View("Index"); } } }
这样,就可以捕捉所有错误了。
但其实,这样也不是完美的,因为如果你参考了我第一个问题中,在IIS6下不修改IIS设置,运行了MVC,那当后缀名不是.aspx的时候,错误不会被捕捉
因为这时候输入的地址根本没有交给网站来处理,IIS直接抛出了错误,因为IIS认为这个后缀名不是你所能执行的
7、View User Control中的强类型
在这样一个场景中,页面的右侧有一个ajax表单用来登陆,放在View User Control中,所有的页面中都存在这个VUC而这些页面中的主要Model类型是不同的,所以,这个View User Control肯定不能用强类型了
不能用强类型了,那怎么用 TextBoxFor 等强类型方法呢?
其实我的理解,强类型主要就是利用了 lambda表达式和反射,对Model进行了类型判断,防止出错
lambda中是何如识别Model类型的呢? vs编译器会自动根据上下文来判断,所以,如果绑定了强类型,那么
<%= Html.TextBoxFor(Model => Model.Passport)%>
就会被自动识别出来
但是上面那个场景,View User Control 中使用的Model和页面中的不同,如果强制绑定了Model,就会出错,提示Model类型不正确,其实可以这样做:
在View User Control中不绑定强类型,然后这样调用强类型方法
<%= Html.TextBoxFor(u => (u as User).Passport)%>
这里有什么区别呢?因为不绑定强类型,编译器不能识别传入的参数是什么类型,那我手动指定一下即可
这样既可以用强类型方法,也不会和主页面有冲突了
这里最好不要用Model,如果你的页面Model类型也是User,并且传入了Model数据,那个这个View User Control中的表单也会被填充
如有错误,或者有疑问,可以直接留言,我会及时答复
或者发我邮箱:dozer@dozer.net.cn
相关文章推荐
- (转)刚用MVC完成一个小项目,总结一些MVC技巧
- 刚用MVC完成一个小项目,总结一些MVC技巧
- iOS 自己项目中的一些总结(tableview 避免重用以及多选状态下判断数组中的bool值是不是同一个状态以及自定义控件的原因)
- 刚完成一个项目的总结
- 曾经到一个电子商务网站的项目,让我总结了一些不足
- 对刚刚完成的一个winform的小项目的总结
- 刚完成了一个ASP.NET 项目,简单的总结一下
- 对近期使用Nhibernate开发的一个项目的一些总结(一)
- 对近期使用Nhibernate开发的一个项目的一些总结(一)
- 最近做一个SSH项目总结出来的一些程序执行流程
- ASP.NET MVC WebApi 返回数据类型序列化控制(json,xml) 用javascript在客户端删除某一个cookie键值对 input点击链接另一个页面,各种操作。 C# 往线程里传参数的方法总结 TCP/IP 协议 用C#+Selenium+ChromeDriver 生成我的咕咚跑步路线地图 (转)值得学习百度开源70+项目
- 一个小项目后的一些技术小总结
- 利用 java.awt.Robot 类来自动完成一些键盘或鼠标的动作,下面是一个小例子
- 团队开发经验:如何带领一个项目团队并做好项目总结
- 如何架构一个ios项目 个人经验总结
- 项目管理心得:一个项目经理的个人体会、经验总结 .
- 同一个项目的不同的项目工作经验总结--程序员丙
- 个人总结的一个中高级Java开发工程师或架构师需要掌握的一些技能
- 任务五:一个项目多文件组织完成任务四
- 项目总结---- imageLoder 的2个Bug解决方法、1.9.4如何选择性删除disk缓存和其它一些错误。