MVC笔记

来源:互联网 发布:国信炒股软件 编辑:程序博客网 时间:2024/06/05 11:49

MVC基础介绍

MVC是一种架构模式(Architectural pattern),用以描述应用程序的结构以及结构中各部分的职责和交互方式.

MVC模式的目的是实现一种动态的程式设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。除此之外此模式通过对复杂度的简化使程序结构更加直观

 

二、MVC各层次职责分解:
模型-视图-控制器架构模式背后的思想非常简单:我们的应用程序中必须区分下面这些职责:

 

 

模型(Model):

模型是指运用于数据之上的数据规则和数据内容,它一般对应于应用程序所要管理的对象。在软件系统中,任何事物都可以被抽象成可以对其以某种方式进行处理的数据模型。应用程序中的用户,信息以及图书是什么?它们只是一堆必须按照对应规则处理的数据(日期不能是未来的日期,电子邮件有特定的格式,名字的长度不能超过多少字符等等)模型给控制器提供了一个用户请求内容对应的数据表达(比如信息,书,相册)。不管我们如何向用户展示,这个数据模型都不会变。这也是我们为什么可以随意选择使用哪个视图来展示数据的原因。模型包含我们应用程序逻辑中最重要的组成部分,这些逻辑运用于我们要处理的问题过程中。控制器更多的是包含应用程序自身的内部组织逻辑(更像管家)。

 

视图(View):

视图提供了展示模型数据的不同方式。它可能是数据填充的模板。视图可以有多个,而控制器则决定使用哪个视图。一个网络应用通常由许多控制器,模型和视图组成。控制器可以被看成是一个主控制器,用于接收用户的所有请求,然后在调用特定的控制器来处理不同的情况。

 

控制器(Controller):

控制器掌管着用户的请求(当用户点击图形用户界面(GUI)上的元素执行操作时,控制器会收到HTTP GET或者POST请求)。它的主要功能就是调用并协调需要的资源/对象来执行用户请求。通常控制器会为任务调用合适的模型,以及选择合适的视图。

 

 

各层间调用关系:

我们先来看一下当用户访问mvc框架站点时的序列图

 

 

现在我们假设正在开发一个人事系统的员工展示业务,首先Controller收集用户提交过来的条件信息,根据条件信息调用Model,在Model中会把条件传给业务逻辑层,业务逻辑层会根据条件从数据库中获得相应的数据,然后将数据返回给Model,在Model中会将数据进行封装后传给Controller,然后Controller再根据需要显示的格式将相应的数据传给View,在View中执行显示逻辑,最后Controller将所要的View传给用户。

 

 

Controller可以直接控制ViewModelView中可以直接控制Model,但Model中不要强依赖View中的内容只能通过弱依赖,比方说可以有些Model是专门为某些View而设计的,但不能在Model中直接调用View逻辑,从Model中应该看不到任何Controller的逻辑。

 

 

 

强关联视图类型使用关键字必须包含ViewModel

 

 

 

先编写Model需要编译一下,然后创建的controller,再action中创建强关联视图才能找到model

 

进行分层结构设计:

Model类可以为实体类,对应增加一个逻辑类处理逻辑,再添加逻辑的controller,最后由controller添加对应的强关联视图。

controller中尽量少用requestresponse

 

 

使用部分类来验证输入的数据跟数据库是否重复:例如插入和更新:

 

 

 

 

Controller类:

 

 

 

动作名称选取器:

ActionName:使用这个标注的动作方法,在浏览器中需要输入actionname的指定值如:

浏览器需要输入PPOO方法才可以执行到write方法,还有要注意返回的view,默认是查找/View/Controller/PPOO而不是/View/Controller/Write,故如果要查找到相应的aspx文件的话,需要指定目录。

同名的Action主要用法如下:一个用于显示窗口的HTML还有一个用于接收窗口传送出来的值。

 

 

 

 

 

 

 

 

 

 

 

 

动作过滤器:

 

执行顺序:

 

 

 

 

VIEW数据

 

 

 

在aspx页面跳转方式:

 

在coNtroller中的页面跳转方式:

Return  Redirect(“aspx”)OR  return redirecttoaction“action”,”controller”)

 

 

 

 

 

项目开发过程:

1先进行model类的开发:使用linq to sql类,把数据表拖进dbml文件中。

2进行controller开发,先定义功能框架,内部功能后面再定,注意好action filter的使用。

3进行view的开发,先进行模板以及跟窗口无关的页面的开发。

 

 

进行数据的验证,我们可以通过创建部分类来增加验证功能。:

Partial class member();

 

Forms的票证验证什么时候执行?即Application_AuthenticateRequest什么时候执行??

 

MVClinq to sqlCURD

INSERT:

                    using (LiuYanBan.Models.LiuYanBanDataContext db = new Models.LiuYanBanDataContext())

                    {

                        M1 = db.Member.Where(p => p.Account == member.Account).FirstOrDefault();

                        if (M1 != null)

                        {

                            ModelState.AddModelError("Account""您ú注痢?册á的?账?号?已?经-被?使?用?,?请?重?新?设Θ?定¨另ⅷ?一?组哩?账?号?");

                            //return Content("注痢?册á失骸?败悒?);

 

                            return View(member);//返う?回?界?面?数簓据Y?

                        }

                        using (TransactionScope trans = new TransactionScope())

                        {

                            member.IsAdmin = false;

                            //member.CreateTime = DateTime.Now;

                            member.Password = EnCode(member.Password);

 

                            db.Member.InsertOnSubmit(member);

                            db.SubmitChanges();

                        }

                    }

                    return Content("注痢?册á成é功|");

                }

 

Read(select ):

            List<Models.Message> listMessage = new List<Models.Message>();

            using (LiuYanBan.Models.LiuYanBanDataContext db = new Models.LiuYanBanDataContext())

            {

                var messagessql = from mes in db.Message select mes;

                listMessage = messagessql.ToList();

            }

            return View(listMessage);

 

此处要注意把查询到的数据放入list中,否则当执行到view代码时,原本在controller中的使用connection资源链接的数据库一旦释放,将读不到查询到的数据messagessql 

 

 

 

删除:

 NorthwindDataContext ctx = new NorthwindDataContext();

 

 Customer test1 = ctx.Customers.Single(c => c.CustomerID == "TEST1");

 

ctx.Customers.DeleteChanges(test1 );
ctx.SubChanges();

 

 

更新:

1、修改
public void Update(Product product)
{
var prod=db.Product.SingleOrDefault(a=>a.Id==product.Id);
if(prod!=null)
{
Name=product.Name;
Price=product.Price;

db.SubChanges();
}

}

 

 

 

ASP.NET MVC Framework支持四种不同类型的Filter

Authorization filters – 实现IAuthorizationFilter接口的属性.

Action filters – 实现IActionFilter接口的属性.

Result filters – 实现IResultFilter接口的属性.

Exception filters – 实现IExceptionFilter接口的属性.

 

 

Filter的默认的执行顺序按上面的列表中顺序进行。如验证(authorizationFilter永远都是最开始执行的,异常(exceptionFilter永远都是最后执行的,当然你也可以根据需要通过Order属性设定过滤器执行的顺序。

 

验证(authorizationfilter用于实现在controller action上的验证和授权,如Authorize filter就是一个验证filter的例子;

Action filter包含一些逻辑,用于该action执行之前或者之后。比如可以使用一个action filter来修改action返回的view data

Result filter包含一些逻辑,用于该actionview result执行之前和之后。比如可以修改一个view resultview被呈现到浏览器之前;

异常(ExceptionAction用于处理异常信息,同样可以使用异常filter记录错误日志。

你同时可以创建自己的Action filter,比如说要实现一个自定义的验证系统,那么可能需要创建一个自定义的action filter,或者说当你需要改变controller action返回的view data的时候,也可以通过创建自定义action filter实现。

为了让用户更简单的创建一个自定义Action filterASP.NET MVC Framework提供了一个基类ActionFilterAttribute,这个类实现了IActionFilterIResultFilter接口,并且继承了FilterAttribute类。从广义上来说,在ASP.NET MVC Framework中,任何实现filter的类型都是action filter

ActionFilterAttribute类有以下的方法可以重写:

OnActionExecuting – 在controller action执行之前调用

OnActionExecuted – 在controller action执行之后调用

OnResultExecuting – 在controller action result执行之前调用

OnResultExecuted – 在controller action result执行之后调用

 

 

MVC引用文件路径:

默认系统会在站点目录下寻找。

 

 

 

数据库中的自增长变量,如果更新不及时进解决方案,就无法识别是自增长,会造成:验证数据的时候排除了自增长变量,但是插入数据库的时候还是会报错,此时需要在相应的models自增长字段中加上:IsDbGenerated=true

/UploadFile/qqq.mp4

 

 

 

MVC项目中在项目属性的web属性中设置了“特定页”,会在启动的时候先启动特定页,再初始化global.asax文件.

 

 

 

程序中读取配置文件web.config,读取是根据Name来读取。对于文件路径的读取,会现在本项目根目录下读取,没有找到则会到调用该项目的另一个项目的根目录下读取。读取视项目类型而定,asp.net网页开发为web.configwinformapp.config

 

 

 

 

 

MVC   VC数据互传

V-->C

1\建立强关联视图,submit提交表单(using(Html.BeginForm)),使用lablefortextboxfor等关联model类,提交表单的在接收的action中使用关联的model类接收即可。

2\本质上是使用querystring,使用路由参数,如idname传值。如

Html.ActionLink("尝¢试?参?数簓传?递蘗""GetParams",  new { name="dddd",age=24,price=22.3 })

在控制器的对应接收方法中,参数名称必须对上传过来的名称。

当不是强关联视图时,如:

 

 

3、使用ajax

使用ajax可以使用post类型,也可以使用get类型,get类型会在url中显示参数,同时由于写入参数到html页面,会造成页面文件过大,一般情况下采用post,既不会在url中产生数据,同时也不会写入到html页面。

 

Second

$(function(){

 $(“#btn”).click(function(){

$.post(“/home/getparam”,

{

Text:”somestring”,

Number:23

},

Function(data)//接收后台处理后的返回数据处理

{

Alert(“接收成功”);

 

}

 

 

});

})

 

/home/getparam

Public actionresult getparam()

{

String text=requset[“Test”];

}

 

 

 

 

 

C-->V

1使用viewdata【】,tempdata[]

2使用强关联视图,关联的类可以再视图中使用”model”来引用相应的属性。

3使用json

public JsonResult get_json()

        {

            IList<object> list = new List<object>()

            {

                new { name="aa",age=23,ismale=true},

                new {name="dd",age=24,ismale=false}

            };

            return Json(list);

 

        }

 

前端:

$(function(){

$.getJSON(“/home/get_json”,

Function(data)

{

$.each(data,function(index,p)

{

Var html=”<tr><td>”+p.name+”</td><td>”+p.age+”</td><td>”+

(p.ismale?”male”:”female”)+”</td></tr>”;

$(“tbody”).append(html);

});

});

 

});

 

 

 

 

VIEW视图引入命名空间,使用帮助类或者其他项目资源:

view文件夹下的web.config进行配置,如果有多个要进行配置的话,可以放入全局的网站配置文件web.config中。

 

 

 

 

 

MVC内部登录API使用:

使用 FormsAuthenticationTicket

        public static void CreateFormsTicket(string key, string role, bool isRemember)

        {

            //1):创洹?建¨一?个?验é证¤票±据Y

            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(

               1, //版?本?号?

               key, //与?票±据Y相à关?的?用?户§名?(在ú此?保馈?存?ID)

               DateTime.Now,

               DateTime.Now.AddMinutes(30),

               false,//是?否?保馈?存?票±据Y

               role //用?户§数簓据Y 保馈?存?用?户§角?色?

               );

            //2):加ó密ü票±据Y

            string enTicket = FormsAuthentication.Encrypt(ticket);

 

            //3): 创洹?建¨Cookie(辍?注痢?意癮Cookie名?称?,与?web.config 文?件t中D设Θ?置?的?一?致?)? 

            System.Web.HttpCookie cookie = new System.Web.HttpCookie(FormsAuthentication.FormsCookieName, enTicket);

 

            //4:) 记?住?状痢?态?

            if (isRemember)

            {

                cookie.Expires = System.DateTime.MaxValue;

            }

 

            //5): Cookie存?放?路·径?

            cookie.Path = FormsAuthentication.FormsCookiePath;

 

 

            System.Web.HttpContext.Current.Response.Cookies.Add(cookie);

        }

 

使用:if (!User.Identity.IsAuthenticated)

            {

                return Content("您ú尚未′登?录?,?请?先è登?录?!?");

            }

 

 

 

MVC下载文件方式:

public FileStreamResult DownFile(string filePath, string fileName)
{
      string absoluFilePath = Server.MapPath(System.Configuration.ConfigurationManager.AppSettings["AttachmentPath"] + filePath);
       return File(new FileStream(absoluFilePath, FileMode.Open), "application/octet-stream", Server.UrlEncode(fileName));
}

方式二:

 

public ActionResult DownFile(string filePath, string fileName)
{
filePath = Server.MapPath(System.Configuration.ConfigurationManager.AppSettings["AttachmentPath"] + filePath);
FileStream fs = new FileStream(filePath, FileMode.Open);
byte[] bytes = new byte[(int)fs.Length];
fs.Read(bytes, 0, bytes.Length);
fs.Close();
Response.Charset = "UTF-8";
Response.ContentEncoding = System.Text.Encoding.GetEncoding("UTF-8");
Response.ContentType = "application/octet-stream";

Response.AddHeader("Content-Disposition", "attachment; filename=" + Server.UrlEncode(fileName));
Response.BinaryWrite(bytes);
Response.Flush();
Response.End();
return new EmptyResult();

}

View调用:

<a href="/Document/DownFile?filePath=@item.Value&fileName=@item.Key">下载</a>  

 

 

 

 

 

 

 

MVC上传文件

1页面使用<input type=”file” name=”fileContent”/>,同时Form标签属性要设置enctype = "multipart/form-data",即文件以二进制形式传送,否则上传不成功。

2改变上传文件4M的限制:webConfig节点<system.web>下的节点<httpRuntimemaxRequestLength="1048576" executionTimeout="3600" targetFramework="4.5" />

3后台上传submit接收方法,接收文件必须使用类HttpPostedFileBase,同时参数名必须与<input file>标签的name属性一致,否则提交上去的接收不到。

4后台保存上传文件路径:fileContent.saveAs(path);

5上传图片预览功能:使用第三方js脚本zxxFile.js

 

MVC 延迟加载:

EF延迟加载:就是使用Lamabda表达式或者Linq 从 EF实体对象中查询数据时,EF并不是直接将数据查询出来,而是在用到具体数据的时候才会加载到内存。

 

1EF中的DbQuery对象操作数据库的时候发生延迟加载,而直接使用List<T>来接受对象时则不会;

2)延迟加载不会立即去查询数据库,而是在使用数据的时候才EF才会去查询数据库。

 

 

 

 

 

MVC使用EF的数据迁移功能:

首次为三步走:

1Enable-Migrations  -ProjectName XXX

2add-migration -ProjectName XXX

3update-database 

以后做23步就好:

1先把修改的字段(model)写好,默认值可以再Seed方法中指定,假如初始为Null则不需要在Seed方法中定义。

2执行第一次的23步即可。注意第二步的命名,XXX必须与前面的命名一致,框架会根据命名递归找到以前的cs文件,最终合并编译成一个cs文件,命名自动从第二次开始变成XXX1XXX2等递增上去。

 

 

 

Func是内置的定义委托方法的方式,省去了自定义的麻烦:Func<方法参数,方法返回值>;

 

 

 

MVC使用automapper

原因:在ORM中,与数据库交互用的Model模型是具有很多属性的。而当我们与其它系统(或系统中的其它结构)进行数据交互时,出于耦合性考虑或者安全性考虑或者性能考虑(总之就是各种考虑),我们不希望直接将这个Model模型传递给它们

使用方法:

1写好model和其对应的modelDto类

2编写自定义profile类,要继承自profile类,重写属性profiName,重写方法configure(),重点在方法中注册映射creatMap<sourceClass,DesClass>();

3在程序运行初始化处进行注册(初始化)自定义profile类,使其运行。

报错:dll内部错误,一般是由于本地的model类与modelDto类对应上面出了问题,可能字段定义的类型不一致,还有一个就是可能没有在程序运行前注册profile。

 

MVC使用区域

1须有MVC.Area模板支撑,否则框架搭建不全。

2访问路由变为/Area/Controller/action

3使用Area中的一个控制器Index为默认页:

Glable的路由路径注册改为:

     routes.MapRoute(

    name: "Default",

    url: "{controller}/{action}/{id}",

    defaults: new { controller = "BookBaseInfo", action = "Index", id = UrlParameter.Optional },

    namespaces: new string[] { "TestLearn1.Areas.BookStore.Controllers" }//针对Area设置默认访问路径

        ).DataTokens.Add("Area", "区域名称");

 

MVC前端对象数据转成json

1使用第三方js脚本:jQueryJSON.js,传之前先序列化对象:

var product1 = new Array();

 product1[1] = { ID: 1, Name: "王而之" };

 product1[2] = { ID: 2, Name: "选型号" };

 var product = $.toJSON(product1);

2通过Ajax传到后台,接收类型为string

        public ActionResult GetJson(string product)

        {

 

            JavaScriptSerializer JSS = new JavaScriptSerializer();

            List<Product> p = JSS.Deserialize<List<Product>>(product);

 

            return Content("dddd");

 

        }

重点在于使用JavaScriptSerializer 反序列化接收的字符串。

 

MVC级联查询

1使用EF三种导航加载方式:延迟加载,贪婪加载,显示加载

延迟加载会把导航属性延迟加载,在用到的时候才执行SQL语句;贪婪加载使用include句式,把相关表的数据一并查出;显示加载与延迟加载效果相似,区别未知。

使用贪婪加载时,include表名,假如是本类内定义有导航属性的,EF默认为inner join,如果要查询include(A)A中的相关表B(已在A中定义导航属性),则使用include(A.导航属性),此默认为left join

2使用linq语法

Var data= From  a in context.tb2 join b in context.tb3 on a.xid=b.xid select new

{ a.属性1,a.属性2,b.属性1b.属性2};

目标SQL语句(多表 LEFT JOIN 查询)  

SELECT id, name, jname, cname   

    FROM userinfo u   

    LEFT JOIN job j on u.job = j.jid   

    LEFT JOIN city c on u.city = c.cid  

 

 

var list = (  

from u in dc.userinfos  

    join j in dc.jobs on u.job equals j.jid into j_join  

from x in j_join.DefaultIfEmpty()  

    join c in dc.cities on u.city equals c.cid into c_join  

from v in c_join.DefaultIfEmpty()  

select new  

{  

    id = u.id,  

    name = u.name,  

    jname = x.jname,  

    cname = v.cname,  

    /*u1=u,x1=x,v1=v*/  

    //不要用对象的方式 因为对象可能为null那么对象.属性就会抛异常  

}  

).ToList(); 

注:使用linq 在代码中较为灵活,程序员可以控制使用各种内外链接,同时控制取什么样的字段属性,而使用EF的加载方式可以省略很多脚本语法麻烦,但是取出了查询表的所有字段数据,同时对于导航加载方式不熟的,无法知道框架生成的内外链接是怎么样的。

 

MVC增删改:

1使用EF

使用上下文的DBSet数据集find\delete\add\setvalues方法,同时操作完要使用上下文的saveChanges()方法,才能保存到数据库。

2使用linq

上下文表数据集(dbset.insertonsubmit(entity)/deleteonsubmit(entity),修改直接对属性修改就好,最后也要进行上下文的submitchanges();

 

 

MVC验证机制

1一般在controller中进行验证:ModelState.IsValid

不通过的话一般返回View()验证机制中的错误信息将会显示到输入控件后面。如果验证一直为false,要检查提交的数据是否合法。这种验证机制方便程序员不必在后台写更多的验证代码。前台使用js进行验证。

 

 

MVC表单提交

1使用强关联类型,在提交后可以再后台使用对应的model类来接收。可以不使用@using(html.beginform()){},使用标签<form></form>也可,主要是字段需要用@html.textboxfor(),这样才能使强关联类对应上标签的name,后台才能用类接收。

2表单可以禁止提交:获取表单对象,对表单对象的提交事件:onsubmitreturn false;即可。可以用在验证字段属性失败的时候禁止提交。

 

MVC分页

分页:

对查询到的数据dbset.asQueryable()转成Iqueryable,通过skip(页面数量*(页数-1)).take(页面数量)分页:

var query = db.Customer.OrderBy(customer=> customer.CustomerID)

                .Skip(pageSize * (pageIndex - 1)).Take(pageSize);

 

MVC后台管理界面侧面菜单不变

1使用MVC母板应用,每一张页面都应用母板

2使用iframe:页面中先用标签<iframe>占位,通过js得到菜单<a>的点击事件,在点击事件中设置标签<iframe>属性srcsrc指向指定路由界面即可。结合菜单,通常指向菜单<a>标签的data-src属性值。

 

 

 

 

 

0 0