MVC Beta 做的网站实践总结(上)

 

最近自己亲自用MVC Beta版+DLinq 做了个网站:

51乡音网(各种方言翻唱的流行歌等) 当作是实践。都是一些平时自己在MVC实践过程中遇到一些问题,现在总结如下,希望对大家有所帮助。   

目录:

一, MVC Route的配置

     1. 好好想想需求,看是不是可以把某些参数配置在Route里.

     2. Route冲突的情况,使用加前缀的方法解决.

     3. 配置Route,以便使用自定义的Handler.

二, Action方法的参数

    1.参值的来源的优先顺序

    2.BindAttributer使用及其注意事项

三, MVC如何手动清除所有的OutPutCache

四, 谈谈MVC的可扩展性,如何创建自定义 ViewUserControl

五. AcceptVerbs的使用.

 

一, MVC Route的配置

1. 好好想想需求,看是不是可以把某些参数配置在Route里.

例 做一个小型CMS系统,支持多用户支持。

刚开始想把用户userName做为Request.Query参数来处理。后来发现这样子做浪费了不少时间。于是我把userName参数配置在Route里.

代码如下:  

routes.MapRoute(
                
new UserMvcRouteHandler(),
                
"Default",                                              // Route name
                "{userName}/{controller}/{action}/{id}",                           // URL with parameters
                new { userName = "Leegool", controller = "Home", action = "Index", id = @"^\d" }                  
            );

2.  Route冲突的情况,使用加前缀的方法解决.

例子 :加了个 "p." 在pageNumber参数 

routes.MapRoute(
                “viewInfo
",                                            

               
"{userName}/{controller}/{action}/c.{categoryId}",                          

               
new { userName = "Leegool", controller = "Info", action = "List"));    

这个时候 如何访问  Leegool/List/Info/c.1, 它就会定位到 viewInfo这个Route,而不是上例的 Default Route.

 3. 配置Route,以便使用自定义的Handler.

在Global.asax.cs里  

public static void RegisterRoutes(RouteCollection routes)
        {
          routes.IgnoreRoute(
"{resource}.ashx/{*pathInfo}"); 
        }

这个时候你就可以使用自己的比如验证码生成之类的Handler,如:使用HIP.ashx?width=100&height=200

就不会被Route拦截到。

 

二, Action方法的参数

1.参数值的来源的优先顺序

从MVC 源代码中得到如下文字:

 // Try to get a value for the parameter. We use this order of precedence:
            // 1. Values from the RouteData (could be from the typed-in URL or from the route's default values)
            // 2. URI query string
            // 3. Request form submission (should be culture-aware)

也就是Action方法的参数值的来源顺序是

1.从RouteData中获得,如果没有就从2中获取

2.URL的QueryString获得,如果没有就从3中获取

3.从Form页面获得

从代码逻辑中也可以弄清这一点,相信应该很有帮助。

 

2.BindAttributer使用及其注意事项

先看个BindAttributer的使用例子:

 public ActionResult Update([Bind(Include = "InformationId,Title,Abstract,KeyWord,Detail,CategoryId", Prefix = "")]Information information)

{
.

}

这样子,网页上只要绑定就ok了

<%= Html.TextBox("KeyWord"nullnew { style = "width:85%;" })%>

BindAttributer使用注意事项是

a.  注意使用Prefix = "",如果不定义Prefix,则Prefix为null。因为是string类型,默认新一个string对象是null.这又回到编码细节的问题了。呵。

从MVC源代码里看到 

private static string GetFieldPrefix(ParameterInfo parameterInfo) {
            BindAttribute attr 
= (BindAttribute)Attribute.GetCustomAttribute(parameterInfo, typeof(BindAttribute));
            
return ((attr != null&& (attr.Prefix != null)) ? attr.Prefix : parameterInfo.Name;
        }

它是null,所以会返回参数名.这里的例子就是返回information。

所以到后面去找InformationId,Title,Abstract,KeyWord,Detail,CategoryId的值的时候,它实践上就是找

information.InformationId,information.Title...

结果是Action的参数information为null。

b.  不要绑定自引用结构的类,

比如当一个Information(文章)都有一种Category(类别),这个类别的表结构是自引用的。

Category的表结构如下

CategoryId Content ParentCategoryId 

这个时候如果使用Bind(Include = Category)就会出现死循环(Category会去寻找ParentCategory,而ParentCategory又会去寻找它的ParentCategory....),导致一个异常。

我自己用的时候是尽量不是去Include一个对象.

 

三, MVC如何手动清除所有的OutPutCache

首先, 介绍一下ASP.NET中AddCacheItemDependency方法,这个方法是将页面的输出缓存 依赖于 Cache对象。

也就是说,如果Cache对象过期,页面输出缓存也就过期。

使用方法:

通常在PageLoad事件中加入如下代码:

Cache.Insert(“key”,DateTime.UtcNow);
 Response.AddCacheItemDependency(
"key");

在页面上配置了输出缓存后,

手动清除输出缓存的代码: 

Cache.Remove("key");

这个时候就会把与 关键字为"key"的Cache对象清除,同时把与之相关联的页面输出缓存都清除掉.

 

然后, 我们要看看MVC源代码,发现了OutputCachedPage类。

我的方法是扩展修改OutputCachedPage类。

由于OutputCachedPage类是private sealed, 并且是继承: Page类。即 private sealed class OutputCachedPage : Page  由于我懒得去写个wrapper。就直接修改它的源代码了。

代码如下 

protected override void OnLoad(EventArgs e)
            {
                
try
                {
                  
string cacheKey =  "key" ;
                  HttpContext.Current.Cache[cacheKey] 
= DateTime.UtcNow.ToString();
                   

                   Response.AddCacheItemDependency(cacheKey);
                }
                
catch (Exception ex)
                {
                    
throw new Exception(ex.Message);
                }

                
base.OnLoad(e);
            }

清除缓存代码如下: 

                foreach (DictionaryEntry item in HttpRuntime.Cache)
                {
                    HttpRuntime.Cache.Remove(item.Key.ToString());                    
                }

当然建议还是写个包装类出来,这样在新版本出来的时候移植也方便些。

 

四, 谈谈MVC的可扩展性,如何创建自定义 ViewUserControl

比如说51音乡网刚开始考虑的是可以注册多用户,就像是小型的CMS一样。我需要对用户名做一些额外处理,这个时候就可以自定义UserViewUserControl 类: 

public class UserViewUserControl : ViewUserControl
    {

          
protected internal string UserName
        {
            
get
            {  
               ...  
               
return _userName;
            }
        }

      }

使用方法如下:

本来是 public partial class LogoTitle : ViewUserControl

改成 public partial class LogoTitle : UserViewUserControl 就可以用了.

其它如ViewPage/ViewMasterPage等类推.

当然还可以自己定义MVCHandler.

 

第五. AcceptVerbs的使用。

需求如下:

可以通过类别来Search产品,并可以分页。其实UI很简单:一个类别DropDownList,一个Search Button,一个分页控件。

解决方案:

遇到这种情况,应该放在两个Action方法中实现。但两个Action的ActionName是一样的。区别在于一个有AcceptVerbs(HttpVerbs.Post)标签,另一个Action方法没有。

代码如下:

单击Search Button的时候,触发了Post动作,执行的是Search1方法  

        [ActionName("Search")]
        [AcceptVerbs(HttpVerbs.Post)]
        
public ActionResult Search1(string userName, int pageNumber)
        {
            
int categoryId = Convert.ToInt32(this.ControllerContext.HttpContext.Request.Form["CategoryId"]);
            ...
            
return View(gridViewData);
        }

当你点击分页的时候,没有Post动作。触发的是Search2方法。MVC会自动根据AcceptVerbs标签去执行匹配的方法。 

        [ActionName("Search")]
        
public ActionResult Search2(string userName, int pageNumber)
        {
            
int categoryId = Convert.ToInt32(this.ControllerContext.HttpContext.Request.QueryString["CategoryId"]);
            ....   

            return View(gridViewData);
        }

 

第一次写博客文章,可能写的不好,请大家见谅了。后面如果有时间我想再写个MVC Beta 做的网站实践总结(下)。比如分页控件,MVC的页面生命周期等等。

posted on 2009-01-19 13:58  leegool  阅读(843)  评论(1编辑  收藏  举报

导航