zoukankan      html  css  js  c++  java
  • MVC笔记

    1.MVC概念 

    --Model:用于存储数据的组件

    --View:根据Model数据进行内容展示的组件
    --Controller:接受并处理用户指令(操作Model),选择一个View并输出内容。
    Controller对View进行引用,但是View不知道Controller的存在。Controller和View都是单向引用Model

    MVC变种:Observer模式,MVP模式。

    2.mvc路由机制 

    MVC中重要的路由处理,默认情况是在Global.asax文件中,我们也可以把这块内容独立出来。

    代码
    复制代码
     1 public  class MyMvcAppliation:HttpApplication 
     2     {
     3         public static void RegisterRoutes(RouteCollection routes)
     4         {
     5             routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
     6 
     7             routes.MapRoute(
     8                 "Default",                                              // Route name
     9                 "{controller}/{action}/{id}",                           // URL with parameters
    10                 new { controller = "Home", action = "Index", id = "" },  // Parameter defaults
    11                 new string[] { "GuestBook.MVC.Controller" }
    12             );
    13            
    14         }
    15         protected void Application_Start()
    16         {
    17             ControllerBuilder.Current.DefaultNamespaces.Add("GuestBook.MVC.Controller");
    18             RegisterRoutes(RouteTable.Routes);
    19         }
    复制代码

    3. 把Controller类和业务逻辑分离,这里可以采用Repository模式

     创建一个Repository接口:IRepository.cs,里面包含些常见数据处理操作方法:这个接口是一个泛型接口,以实现所有实体类的通用性。public interface IRepository<T>

    复制代码
        {
            List
    <T> FindAllInfo();
            T GetInfo(T model);
            
    bool  Add(T model);
            
    bool  Delete(T model);
            
    bool  Edit(T model);
        }
    复制代码

    4.MVC中的ViewData 

     View在MVC模式中与用户进行最直接的接触,负责数据的呈现。注意:view只是负责数据的呈现,我们要尽量让view中不涉及业务逻辑的处理。既然View与后台代码是相分离的,但View和Controller是如何联系在一起的呢,答案就是ViewData。

      ASP.NET MVC默认使用WebForm来作为view。新建的aspx页面继承自ViewPage,所有的aspx页面都必须继承自ViewPage。我们再看一下ViewPage的部分代码:

     

    public class ViewPage : Page, IViewDataContainer 

       
       我们使用传统的asp.net开发时,经常会为了开发的需要,会写一个类似PageBase类,例如会把部分比较通用的方法写入基类。同样在MVC中,我们也可以这样做。

       第一:创建一个ViewPage<T>类(扩展ViewPage)这 个类主要是完成一个继承功能,对 MvcContrib.FluentHtml.ModelViewPage,MvcContrib.FluentHtml.ModelViewUserControl 的继承,实现System.Web.Mvc.ViewPage的功能。还有一个非常重要的作用就是把所有的扩展方法都体现在这个类中。

    复制代码

        
    public class ViewPage<T> : MvcContrib.FluentHtml.ModelViewPage<T> where T : class
        {
            
    public ViewPage()
            {

            }
        }
        
    public class ViewUserControl<T> : MvcContrib.FluentHtml.ModelViewUserControl<T> where T : class
        {
            
    public ViewUserControl()
            {

            }
        }
    复制代码

     第二.对MVC进行扩展(对ViewData)。例如对Html的扩展,我们在做增删改查类似操作时,当用户提交后一般都会根据系统处理结果显示一段提示文字给用户。

             1:创建扩展类:HtmlHelperExtensions,主要包含两个方法,一个是操作成功后的处理方法,另一个则是失败后的处理结果。

    复制代码
    public static class HtmlHelperExtensions
          {
            
    public static string ErrorBox(this HtmlHelper htmlHelper, ViewDataBase  errorViewData)
            {
                
    if (errorViewData.ErrorMessage == nullreturn string.Empty;

                HtmlTextWriter writer = new HtmlTextWriter(new StringWriter());

                writer.AddAttribute("class""error");
                writer.RenderBeginTag(HtmlTextWriterTag.Div);
                writer.Write(errorViewData.ErrorMessage);
                writer.RenderEndTag();
                
    return writer.InnerWriter.ToString();
            }

            
    public static string MessageBox(this HtmlHelper htmlHelper, ViewDataBase messageViewData)
            {
                
    if (messageViewData.Message == nullreturn string.Empty;

                HtmlTextWriter writer = new HtmlTextWriter(new StringWriter());

                writer.AddAttribute("class""message");
                writer.RenderBeginTag(HtmlTextWriterTag.Div);
                writer.Write(messageViewData.Message);
                writer.RenderEndTag();
                
    return writer.InnerWriter.ToString();
            }
        }  
    复制代码


      1 public  class ViewDataBase

    复制代码
     2     {
     3         public string Message { getset; }
     4         public string ErrorMessage { getset; }
     5 
     6         public ViewDataBase WithErrorMessage(string errorMessage)
     7         {
     8             this.ErrorMessage = errorMessage;
     9             return this;
    10         }
    11         public ViewDataBase WithMessage(string message)
    12         {
    13             this.Message = message;
    14             return this;
    15         }
    16     }
    复制代码

    5.MVC中的ModelBinder 

    MVC提交表单时我们并不用对表单中各个对象进行一一对应,MVC会 自动把表单的相关值赋给对象。这点看起来特别神奇,MVC 为我们提供了一个自动化的操作,这一切都归功于IModelBinder 接口,系统默认会找它DefaultModelBinder来完成这一神圣的任务。DefaultModelBinder 内部通过大量的反射完成最终的赋值操作,基本上能适应开发所需。至于如何实现大家可以到网上去搜索下资料,既然有默认的,我们也可以自定义 ModelBinder。 

     1:创建GuestBookBinder,让它继承IModelBinder,并实现其方法。这里我们可以根据实际业务需要,修改方法,这里只是一个简单实现。

    复制代码
    public class GuestBookBinder : IModelBinder
        {
            
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
            {
                var info 
    = bindingContext.Model ?? new GuestBookInfo();

                var properties 
    = bindingContext.ModelType.GetProperties();

                
    foreach (var item in properties)
                {
                    
    if (bindingContext.PropertyFilter(item.Name))
                    {
                        var result 
    = bindingContext.ValueProvider[item.Name];
                        
    if (null == result)
                        { 
    break; }
                        var value 
    = result.ConvertTo(item.PropertyType);

                        item.SetValue(info, value, 
    null);
                    }
                }

                
    return info;
            }

        }

    复制代码

        
           2:注册GuestBookBinder,自定义Binder写好后,系统并不会自动识别,需要在应用程序初始化进行注 册,ControllerActionInvoker.GetParameterValue 根据 ModelBinders.Binders.GetBinder() 来找对应的 IModelBinder,如没找到则返回默认的 DefaultModelBinder。    

    protected void Application_Start()
            {
                ControllerBuilder.Current.DefaultNamespaces.Add(
    "GuestBook.MVC.Controller");
                ModelBinders.Binders.Add(
    typeof(GuestBookInfo ), new GuestBookBinder ());
                RegisterRoutes(RouteTable.Routes);
            }

        
          3:除了上面的注册方法外,可以直接把 ModelBinderAttribute 用在对应的实体上 ,但不推荐这样做。

     

    [ModelBinder(typeof(GuestBookBinder))]
    public class GuestBookInfo

         
          4:除了由 ControllerActionInvoker.GetParameterValue() 自动完成 BindModel 操作外,还提供了两个方法:这两个方法唯一的区别在于,TryUpdateModel不会抛异常,前者会。 
            1>:Controller.UpdateModel()
            2>:Controller.TryUpdateModel()

          示例:例如更新一则留言时,我们可以这样写:
         

    复制代码
    [AcceptVerbs(HttpVerbs.Post)]
           
    public ActionResult Edit(int id, FormCollection formValues)
           {
               GuestBookInfo model 
    = new GuestBookInfo();
               model.ID 
    = id;
               model 
    = inter.GetInfo(model);
               UpdateModel(model );
               inter.Edit(model);
               
    return RedirectToAction("Index");
           }
    复制代码

     6.ViewData与TempData

    ViewData 局限于当前Action,TempData跨Action.

    TempData因为并不是通过网页参数传值,所以肯定是把数据存储在某个地方的原因 

       第一:查看Controller类的源码,其中包含一个重要的方法:在这个方面开始前就调用了基类的TempData.Load方法。

    复制代码
    protected override  void ExecuteCore()
    {
        
    base.TempData.Load(base.ControllerContext, this.TempDataProvider);
        
    try
        {
            
    string requiredString = this.RouteData.GetRequiredString("action");
            
    if (!this.ActionInvoker.InvokeAction(base.ControllerContext, requiredString))
            {
                
    this.HandleUnknownAction(requiredString);
            }
        }
        
    finally
        {
            
    base.TempData.Save(base.ControllerContext, this.TempDataProvider);
        }
    }
    复制代码

       
           第二:TempData.Load方法:可以看到最终是由ITempDataProvider这个接口来完成。

    复制代码
    public void Load(ControllerContext controllerContext, ITempDataProvider tempDataProvider)
    {
        IDictionary
    <stringobject> dictionary = tempDataProvider.LoadTempData(controllerContext);
        
    this._data = (dictionary != null? new Dictionary<stringobject>(dictionary, 

    StringComparer.OrdinalIgnoreCase) : 
    new Dictionary<stringobject>(StringComparer.OrdinalIgnoreCase);
        
    this._initialKeys = new HashSet<string>(this._data.Keys);
        
    this._modifiedKeys.Clear();
    }

    复制代码

        
          第三:ITempDataProvider:我们可以在第一条中的代码中发现,接口是这样取的:

    复制代码
    public ITempDataProvider TempDataProvider
    {
        
    get
        {
            
    if (this._tempDataProvider == null)
            {
                
    this._tempDataProvider = new SessionStateTempDataProvider();
            }
            
    return this._tempDataProvider;
        }
        
    set
        {
            
    this._tempDataProvider = value;
        }
    }
    复制代码


            第四:SessionStateTempDataProvider,从这个名字我们就可以猜测,数据应该是用Session方式保存。主要包含了两个方法,分别用于加载数据和保存数据。

    复制代码
    public virtual IDictionary<stringobject> LoadTempData(ControllerContext controllerContext)
    {
        HttpContextBase httpContext 
    = controllerContext.HttpContext;
        
    if (httpContext.Session == null)
        {
            
    throw new InvalidOperationException(MvcResources.SessionStateTempDataProvider_SessionStateDisabled);
        }
        Dictionary
    <stringobject> dictionary = httpContext.Session["__ControllerTempData"as Dictionary<string

    object>;
        
    if (dictionary != null)
        {
            httpContext.Session.Remove(
    "__ControllerTempData");
            
    return dictionary;
        }
        
    return new Dictionary<stringobject>(StringComparer.OrdinalIgnoreCase);
    }

    public virtual void SaveTempData(ControllerContext controllerContext, IDictionary<stringobject> values)
    {
        HttpContextBase httpContext 
    = controllerContext.HttpContext;
        
    if (httpContext.Session == null)
        {
            
    throw new InvalidOperationException(MvcResources.SessionStateTempDataProvider_SessionStateDisabled);
        }
        httpContext.Session[
    "__ControllerTempData"= values;
    }

    复制代码

       
          小结:TempData虽然用Session来实现数据的存储,但对服务器来讲,代价虽然有,但并不高,因为从代码上看TempData用完一次就会被消 除掉。看到这,我们可以想,是否可以看定义一个TempDataProvider,当然可以。这里我创建一个示例,并没有做功能上的改变,可以根据实际情 况修改:

          1:创建MyTempDataProvider,让它继承ITempDataProvider ,并且实现LoadTempData和SaveTempData。
      
          2:将MyTempDataProvider与Controller联系上,我们可以选择扩展默认控制器工厂(DefaultControllerFactory) ,重写IController CreateController方法:

    复制代码
    public override IController CreateController(RequestContext requestContext, string controllerName)
            {
                Controller controller 
    = base.CreateController(requestContext, controllerName) as Controller ;
                
    if (null != controller)
                {
                    controller.TempDataProvider 
    = new MyTempDataProvider();
                }
                
    return controller;

            }

    复制代码

        
           3:注册我们自定义的MyControllerFactory,这也是最后一步。

    复制代码
    protected void Application_Start()
            {
                ControllerBuilder.Current.DefaultNamespaces.Add(
    "GuestBook.MVC.Controller");
                ModelBinders.Binders.Add(
    typeof(GuestBookInfo ), new GuestBookBinder ());
                ControllerBuilder.Current.SetControllerFactory(
    typeof(MyControllerFactory ));
                RegisterRoutes(RouteTable.Routes);
            }
    复制代码

    7.Action和Filter

      Filter在Asp.net MVC中它只能限制于Action,Controller。 继承于ActionFilterAttribute,且可以覆写如下几个重要方法。
           1:void OnActionExecuting(ActionExecutingContext):Action执行前的操作

           2:void OnActionExecuted(ActionExecutedContext):Action执行后的操作

           3:void OnResultExecuting(ResultExecutingContext):解析ActionResult前执行

        4:void OnResultExecuted(ResultExecutedContext):解析ActionResult后执行 

    系统提供的比较常见的Filter:
           1:AcceptVerbs
           2:ActionName,上面两个都限制了对Action的访问条件;

           3:OutputCache,设置缓存;      

       4:ValidateInput,增加数据验证。 

     如:[AcceptVerbs(HttpVerbs.Get )]

         public ActionResult Index()

      3:ActionNameAttribute的用法,和 AcceptVerbsAttribute 方式差不多,如果不指定ActionName,则系统会默认找名称和方法名相同之处的View。

    [ActionName ("Edit")]

    public ActionResult Edit(int id)

      自定义Filter:

                  这里创建一个没有客户端缓存的NoClientCacheAttribute。需要继承ActionFilterAttribute,且重写OnActionExecuting方法。

    复制代码
        public class NoClientCacheAttribute : ActionFilterAttribute
        {
            
    public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                HttpContext.Current.Response.CacheControl 
    = "No-Cache";
            }

        }
    复制代码

       
         应用在Action上,特别简单,像C#中的变通特性用法一样。

    [NoClientCache]
    public ActionResult Details(int id)


    8. System.Web.Mvc.Html下的HtmlHelper 

       System.Web.Mvc.Html下的HtmlHelper只能完成大部分html控件的输出,但像img标签默认是没有提供的,这里需要我们自行来扩展下Helper,毕竟上面的众多方法都是扩展出来的。

            扩展Helper,我们可以利用TagBuilder,它能输出所有标签及属性。TagBuilder提供下如下重要方法:

    复制代码
    // Methods
        public TagBuilder(string tagName);
        
    public void AddCssClass(string value);//增加样式
        public void GenerateId(string name);//设置控件ID
        private string GetAttributesString();
        
    public void MergeAttribute(string key, string value);//设置属性值
        public void MergeAttribute(string key, string value, bool replaceExisting);
        
    public void MergeAttributes<TKey, TValue>(IDictionary<TKey, TValue> attributes);
        
    public void MergeAttributes<TKey, TValue>(IDictionary<TKey, TValue> attributes, bool replaceExisting);
        
    public void SetInnerText(string innerText);//设置显示文本
        public override string ToString();
        
    public string ToString(TagRenderMode renderMode);//输出控件html
    复制代码

        
           1:创建ImageHelper,利用TagBuilder部分方法最终输出img标签。

    复制代码
    public static class ImageHelper
        {
            
    public static string Image(this HtmlHelper helper, string id, string url, string alternateText)
            {
                
    return Image(helper, id, url, alternateText, null);
            }

            
    public static string Image(this HtmlHelper helper, string id, string url, string alternateText, object 

    htmlAttributes)
            {
                
    // 创建IMG标签
                var builder = new TagBuilder("img");

                
    // 增加ID属性
                builder.GenerateId(id);

                
    // 增加属性
                builder.MergeAttribute("src", url);
                builder.MergeAttribute(
    "alt", alternateText);
                builder.MergeAttributes(
    new RouteValueDictionary(htmlAttributes));

                
    // 输出完整的img标签
                return builder.ToString(TagRenderMode.SelfClosing);
            }

        }

    复制代码

        
           2:页面调用。

    <%= Html.Image("img1""http://a.lakequincy.com/img/633820582974214892.jpg""这是一张图片"new 

    {border
    ="4px"})%>

    9.MVC下开发ajax程序

      MVC有个特点,一般情况下一个页面文件都会对应一个Controller,类似于web form模式下的页面后台代码。Conntroller里面的每个公共方法(私有方法不行)都可以通过页面地址中访问,例如我们在 HomeController中有这样一个方法:

            

            public   void Test(int i)
            {
                System .Web .HttpContext .Current .Response .Write (
    "aaa"+i .ToString ());
            }

      

           我们可以在浏览器中输入/Home/Test?i=1,此时页面上就会输出我们想要的内容,这也是web form模式没有办法直接实现的。即然MVC能够直接调用Controller中的方法,也就是我们不用单独创建一些类来实现,这点和ajaxpro的功 能有点相似。下面我们就来实现在asp.net mvc中应用ajax,当然我选用jquery做为js框架,熟悉jquery的朋友看起来就非常容易了。
         
          1:创建一个学生类的集合,学生类结构如下:
         

        public class student
        {
            
    public string sname { getset; }
            
    public int ID { getset; }
            
    public int Grade { getset; }
        }

     

         2:写一个根据学生ID查找学生信息的方法。这里注意下,这个方法的返回类型为JsonResult,它能够给客户端以json类型输出数据(MVC能够把目标对象转换成json格式),这个和平时常见的ActionResult有所区别。
         

    复制代码
    代码
    public JsonResult TestMVC(int i, int j)
            {
                
    int I = 0;
                List
    <student> list = new List<student>();
                
    for (int k = 0; k < 10; k++)
                {
                    student sd 
    = new student() { sname = "aaa" + k.ToString() + j.ToString(), ID = k, Grade = k * 10 };
                    list.Add(sd);
                }
                var stu 
    = (from m in list
                           
    where m.ID == i
                           select m
                             ).FirstOrDefault();

                JsonResult J 
    = new JsonResult();
                J.Data 
    = stu;
                
    return J;
            }
    复制代码

          
          3:客户端代码:从后台取得数据后,填充到div中。
           

    $.getJSON('/Home/TestMVC',{i:1,j:2},
                    function(data) {
                        $(
    "#divStudent").html(data.sname);
                    }
                    );

                 
           分析:以上三步基本上就可以实现一般的ajax程序,如有不同,也只可能是程序写法问题,大体流程都差不多应该相同。这种写法已经非常简洁了,但还有可以提高的地方。


                 第一:开发人员需要拼接ajax请求的地址。本例中为Home/TestMVC
                 第二:开发人员需要准备构建ajax方法使用的data参数。本例中为,{i:1,j:2}
           
          解决思路:让程序自动为我们完成上面两步。可以参考ajaxpro的实现原理,每个方法异步请求的方法上 加一个自定义特性标签,编译器遇到自定义标签后,自动生成一些js方法,来让开发者前端调用更加方便。例如生成如下代码:i,j分别是异步请求方法的两个 参数,callback为异步请求后的回调方法。
           

    复制代码
    代码
       var HomeController = {
                TestMVC: function(i, j,callback)
                                                    {
                                                         $.getJSON(
    '/Home/TestMVC?id=&',{i:i, j:j}, callback);
                                                    }
            }
    复制代码

      

         我们可以这样调用:我们只需要输入相应参数,以及完成回调方法即可。是不是简单了点。下一篇来讲讲具体实现方法。
            

    HomeController.TestMVC(j,j+1, function(data) {
                 $(
    "#divStudent").html(data.sname);
                 });    
    文章的出处:http://www.cnblogs.com/ASPNET2008/archive/2010/03/07/1680061.html
  • 相关阅读:
    Qt 学习之路 :自定义只读模型
    Qt 学习之路:QSortFilterProxyModel
    Qt 学习之路 :可视化显示数据库数据
    Qt 学习之路 :访问网络(4)
    Qt 学习之路:QFileSystemModel
    高级Bash脚本编程指南
    CGI
    shell学习
    【shell】while read line 与for循环的区别
    管道技巧-while read line
  • 原文地址:https://www.cnblogs.com/yeagen/p/2700719.html
Copyright © 2011-2022 走看看