ASP.NET MVC

ASP.NET是使用HTML、CSS、JS和服务端脚本创建Web页面和网站的开发框架。

ASP.NET支持三种开发模式

  • Web Pages:Web页面
  • MVC:Model View Controller 模型-视图-控制器
  • Web Forms:Web窗体

基于.NET平台开发站点的框架实际上包含两部分:可视化用户界面WebForm和后台Web组件ASP.NET。两者通过命名空间区分,System.Web.UI.*命名空间下的内容可称为WebForm,而System.Web.*命名空间下的内容可称为ASP.NET。

与WebForm一样,ASP.NET MVC的类都在System.Web.Mvc命名空间下,也是基于ASP.NET平台构建的。

ASP.NET MVC_第1张图片
ASP.NET Web Form的技术堆栈

MVC 编程模型

ASP.NET MVC_第2张图片
MVC

MVC 是使用模型-视图-控制器设计创建Web程序的模式

  • Model 模型,表示应用程序核心,如数据库记录列表。
    模型是应用程序中用于处理应用程序数据逻辑的部分,模型对象负责在数据库中存取数据。
    模型是定义应用程序主题的现实对象、过程以及规则的表示,称为域(Domain)。
    模型通常被称为域模型(Domain Model),包含应用程序域中要建立的C#对象,称为域对象(Domain Object)。这些域对象构成了应用程序的全部事物以及操作这些对象的方法。视图和控制器以一致的方式将域暴露给客户端。一个设计良好的MVC应用程序,必须从设计良好的模型开始,随后添加控制器和视图的焦点。
  • View 视图,显示数据
    视图是应用程序中处理数据显示的部分,视图是依赖模型数据创建的。
  • Controller 控制器,处理输入
    控制器是应用程序中处理用户交互的部分,控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
ASP.NET MVC_第3张图片
MVC生命周期

MVC分层有助于管理复杂的应用程序,同时也简化分组开发。


ASP.NET MVC_第4张图片
MVC

MVC框架被构建成一系列独立的组件,这些组件满足一个.NET接口,或建立在一个出抽象类之上。你可以很容易地用一个自己的不同实现来替换这些组件。例如:路由系统、视图引擎、控制器工厂等。通常,MVC框架对每个组件提供三种选择:

  • 使用组件现行的默认实现
  • 派生默认实现的一个子类以调整其行为
  • 用接口或抽象基类的一个新的实现来完全替换该组件

ASP.NET MVC 开发中有一个很重要的理念叫“约定大于配置”,ASP.NET MVC中存在许多潜规则:

  • 控制器存放controller目录,命名以 Controller结尾。
  • 每个控制器都对应View中一个目录,视图目录名称跟控制器同名。控制器中的方法名都对应一个View视图,且视图名字跟Action动作的名字相同。
  • 控制器必须是非静态类,且要实现 IController接口。
  • 控制器类型可以放到其他项目中

ASP.NET MVC的请求处理流程


ASP.NET MVC_第5张图片
ASP.NET MVC

客户端请求 => IIS => Runtime => Controller => Action => ViewResult(:ActionResult) => ExecuteResult() => RazorView(:IView).RenderView => Response

ASP.NET MVC 目录结构

  • 应用程序信息
    Properties
    References
  • 应用程序目录
    App_Data
    Content 存放静态文件,如CSS、ICON、IMG。
    Controllers 负责处理用户输入和响应的控制器类,命名以Controller结尾。
    Models 包含表示应用程序模型的类,控制并操作应用程序的数据。
    Views 用于存储与应用的显示相关的HTML界面文件。该目录包含每个控制器对应的一个目录。
    Scripts 存储应用程序的JS文件
  • 配置文件
    Global.asax
    packages.config
    Web.config

ASP.NET MVC

路由

任何时候一个请求进来,URL都会与已注册的路由模板进行匹配。如果找到匹配项,就会确定处理该请求的合适控制器和操作方法。如果没有找到,请求会被拒绝,结果通常是一个404消息。

ASP.NET MVC_第6张图片
路由

应用程序路由通常是在global.asax文件中注册,并在应用程序启动时得到处理。

$ vim global.asax
protected void Application_Start()
{
  AreaRegistration.RegisterAllAreas();
}

URL路由引擎是一个把PostResolveRequestCache事件串联起来的HTTP模块,在检查出请求的响应不在ASP.NET缓存中以后,就会出发该事件。

$ vim App_Start/RouteConfig.cs

using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace Movie
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

框架所支持的路由必须添加到由ASP.NET MVC管理的路由对象的静态集合中,该集合就是RouteTable.Routes。通常使用便捷的MapRoute()方法来填充该集合。如果需要在路由上做一些MapRoute()并不支持的设置,需要使用

var route = new Route(...);
RouteTable.Routes.Add("RouteName", route);

路由约束

routes.MapRoute(
  "Product",
  "{controller}/{id}/{locale}",
  new {controller = "Product", action="Index", locale="en-us"},
  // 路由约束
  new {id = @"\d{8}", locale="[a-z]{2}-[a-z]{2}"}
)
ASP.NET MVC_第7张图片
路由
ASP.NET MVC_第8张图片
VS开启反编译

从技术角度看,路由处理程序是一个实现IRouteHandler接口的类

public interface IRouteHandler
{
  IHttpHandler GetHttpHandler(RequestContext requestContext);
}

System.Web.Routing命名空间中定义的 RequestContext
类,封装了请求的HTTP上下文及任何可用的路由专用信息,比如Route对象本身、URL参数和约束条件。这些数据被分组到一个RouteData对象。

ASP.NET MVC_第9张图片
RequestContext
public class RequestContext
{
  public RequestContext(HttpContextBase httpContext, RouteData routeData);
  // properties
  public HttpContextBase HttpContext {get; set;}
  public RouteData RouteData {get; set;}
}

阻止已定义的URL路由

  1. 为需要阻止的URL定义一个模式并保存到一个路由
  2. 将该路由链接到一个专门的路由处理程序StopRoutingHandler

其结果就是在调用GetHttpHandler()时会抛出一个NotSupported异常。

$ vim /App_Start/RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes)
{
    // 强制路由系统处理所有的请求
    // routes.RouteExistingFiles = true;

    // 指示路由系统忽略任何.axd请求
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
        namespaces:new[] { "App.Controllers"}
    );
}

IgnoreRoute所作的就是将StopRoutingHandler路由处理程序关联到围绕指定URL模式所构建的路由上。

控制器

ASP.NET MVC_第10张图片
控制器

控制器主要负责响应用户的输入,关注的是应用程序流、输入数据的处理以及对相关视图输出数据的提供。

控制器的特征

  • 继承自System.Web.Mvc.Controller,实现IController接口。
  • 一个Controller可包含多个Action,每个Action都是一个方法,返回一个ActionResult实例。

控制器本身是一个类,该类只要是public公开的方法就会被是为是一个动作方法Action,只要动作存在就可以接收客户端传来的请求,经过处理后返回响应的视图View

public string Text()
{
    return "hello world";
}

在定义一个方法时会根据方法有无返回值来划分,但是控制器的本质是类,控制器的动作action本质是方法。从数学集合的角度来看,控制器是类的子集,控制器的动作是方法的子集。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace Movie.Controllers
{
    public class TestController : Controller
    {
        // http://localhost:49184/test
        public string Index()
        {
            return "hello";
        }

        // http://localhost:49184/test/welcome?name=superman&age=30
        public string Welcome(string name, int age = 0)
        {
            //  HttpServerUtility.HtmlEncode 来保护应用从malacious输入的(也就是JavaScript)
            return HttpUtility.HtmlEncode("welcome "+name+" age is "+age);
        }
    }
}

控制器的基本条件

  1. 控制器必须为public公开类别
  2. 控制器名称以Controller结尾
  3. 控制器必须继承ASP.NET MVC内置Controller类或实现IController接口
  4. 控制器内的所有动作必须为 public 公开方法,任何非public方法均不会被视为动作方法。

控制器的运行原理

当控制器被MvcHandler选中后,通过ActionInvoker选定适当地Action来运行。在Controller中每个Action可定义0到n个参数,ActionInvoker会根据当前的RouteValue与客户端传递来的数据,准备可传入Action参数的数据,最后调用Controller中被选中的Action方法。

HTTP动词

ASP.NET MVC可让你将方法绑定到用于特定HTTP动词的操作,要将控制器方法与HTTP动词关联,可使用参数化的AcceptVerbs特性,也可以直接使用特性。使用AcceptVerbs特性,可以指定需要哪个HTTP动词来执行给定的方法。

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Update(Customer customer)
{
  ...
}

AcceptVerbs特性会从HttpVerbs枚举类型中提取,HttpVerbs枚举由Flags特性修饰。

public enum HttpVerbs
{
  Get = 1,
  Post = 2,
  Put = 4,
  Delete = 8,
  Head = 0x10
}

可通过按位OR(|)运算符将来自枚举类型的枚举值结合到一起,同时获得另一个HttpVerbs值。

[AcceptVerbs(HttpVerbs.Post|HttpVerbs.Put)]
public ActionResult Edit(Customer customer)
{
  ...
}

控制器的方法类别

  • 动作方法选定器

当通过ActionInvoker选定Controller控制器中的public公开方法时,ASP.NET MVC的“动作方法选定器(Action Method Selector)”便会运行在动作方法上,以便ActionInvoker选择对应的Action

  1. NonAction 属性

若控制器的动作方法上的特性为NonAction,则表示该Action是“公开方法”,即告知ActionInvoker不要选择此Action来运行。

ASP.NET MVC_第11张图片
NonAction属性

NonAction属性的作用:

保护Controller中特定的公开方法不要发布到Web上

功能尚未开发完毕就要进行部署,但暂时不想将此方法删除。

可将public修改为private达到同样的保护效果

private ActionResult Contact()
{
    ViewBag.Message = "Your contact page.";

    return View();
}
  1. HTTP动词限定属性

HTTP动词限定属性包括HttpGetHttpPostHttpDeleteHttpPutHttpHeadHttpOptionsHttpPatch,它们都是动作方法选定器的一部分。

// 当客户端浏览器发送的是HTTP GET请求时,ActionInvoker才会选定此Action。
[HttpGet]
public ActionResult Contact()
{
    ViewBag.Message = "Your contact page.";

    return View();
}
ASP.NET MVC_第12张图片
HttpGet
[HttpPost]
public ActionResult Contact()
{
    ViewBag.Message = "Your contact page.";

    return View();
}
ASP.NET MVC_第13张图片
HttpPost 404
  • 操作过滤器

一个操作方法 一旦被选中就会立即执行,且返回一个结果,返回的结果也会随之执行。

ASP.NET MVC 提供5种操作过滤器:身份验证、授权、操作前后处理、结果前后处理、处理处理。此外还有一种是重写过滤器,它允许为全局或控制器的默认集合制定例外规则。

操作过滤器可直接使用操作方法或控制器的特性来编写,也可以作为在全局过滤器列表中注册的单独类来编写。如果打算将编写的操作过滤器作为特性来使用,就必须继承FilterAttribute类或其子类,例如ActionFilterAtrribute。当然不作为特性使用的全局操作过滤器对这个基类是没有要求的。注意的是,无论采用哪个路由,操作过滤器支持的过滤活动都由实现的接口所决定。

MvcHandlerController得到ActionResult之后,开始运行ActionResult提供的ExecuteResult方法,并将运行结果响应到客户端,此时Controller的任务完成。

控制器的动作过滤机制

  • 授权过滤器 AuthorizationFilters
  • 动作过滤器 ActionFilters
  • 结果过滤器 ResultFilters
  • 例外过滤器 ExceptionFilters

动作

Action本质是类中的公共方法可重载,要求参数不同。Action可通过路由规则传递数据。Action方法接收浏览器传递的参数。若希望方法只处理某种请求,可在方法前添加特性[HttpGet][HttpPost],处理请求时会根据参数调用对应方法。

获取Request对象中的输入数据

ASP.NET中Request.Params字典产生于4个不同字典的组合,即QueryStringFormCookiesServerVariables。可使用Request对象的Item索引器属性。

POST数据接收方法包括:Request.FormForm.Collection、同名参数、Model。GET数据接收方式可直接通过Request.QueryString获取。

public ActionResult Echo()
{
  var data = Request["param"] ?? String.Empty;
}
public ActionResult Echo()
{
  var data = Request.Params["param"] ?? String.Empty;
}

从路由中获取输入数据库

ASP.NET MVC会通过URL提供输入的参数,参数值由路由模块捕获以供应用程序使用。路由值不通过Request对象向应用程序空开。

public ActionResult Echo()
{
  var data = RouteData.Values["param"] ?? String.Empty;
}

路由数据是通过Controller类的RouteData属性公开的,对匹配项的搜索不区分大小写。RouteData.Values字典是一个字符串/对象字典,大多数时候该字典只包含字符串。但是,若以编程方式填充该字典,那么它就可以包含其他类型的值。

public ActionResult Echo()
{
  var data = RouteData.Values["data"] ?? (Request.Params["data"] ?? String.Empty);
}

ValueProvider字典

Controller类中ValueProvider属性只会为从各种来源收集到的输入数据提供单个容器。默认情况下,ValueProvider字典来自下列源的输入值填充:

  • 子操作值
  • 表单数据 Request.Form
  • 路由数据
  • 查询字符串
  • 提交的文件

ValueProvider字典提供了一个以GetValues()方法为中心的自定义编程接口。

var result = ValueProvider.GetValue("param");

GetValue()不会返回StringObject类型,而会返回ValueProviderResult类型的一个实例。该类型有两个用于实际读取真实参数值的属性:RawValueAttemptedValue,前者是Object类型,包含来源所提供的原始值。AttemptedValue属性却是一个字符串,代表了强制转换为String类型的结果。

public ActionResult Echo()
{
  var data = ValueProvider.GetValue("param").AttemptedValue ?? (ValueProvider.GetValue("param").AttemptedValue ?? String.Empty);
}

ValueProviderRequestRouteData在参数名称上的要求更高一些,如果参数大小写输入错误,会得到一个从GetValue返回的null对象。如果之后只是读取值而不检查为空的结果对象,就会导致一个异常。最后要注意的是,默认情况下,不能通过ValueProvider字典获得对Cookies的访问权。可通过定义一个实现IValueProvider接口的类,值提供器列表可以以编程方式得到扩展。

参数传入的属性均通过模型绑定机制(Model Binding),从RequestContext请求上下文中获取数据,并将数据传入对应的方法参数中,让Action动作方法不再像ASP或ASP.NET Web Forms中使用的Request.FormRequest.QueryString等对象来获取客户端的数据。

产生操作结果

操作方法通常会返回一个ActionResult类型对象,但它的类型并不是一个数据容器。确切地说,它是一个抽象类,提供通用编程界面,代表操作方法进一步的操作。

public abstract class ActionResult
{
  protected ActionResult(){}
  public abstract void ExecuteResult(ControllerContext context);
}

通过重写ExecuteResult()方法,派生类会获得访问任何由操作方法的执行所产生的数据的权限,并触发一些后续操作。一般来说,这些后续操作与一些浏览器的响应生成有关。

预定义操作结果类型

Action动作方法运行完毕后的回传值,通常是ActionResult类别或其衍生类别Derived Class。事实上,ActionResult是一个抽象类,下列均是继承自ActionResult

  • ViewResult用来回传一个View
  • RedirectResult用来将网页重定向
  • Content用来回传文件内容
  • FileResult用来回传二进制文档等

执行操作结果的机制

public JavaScriptResult GetScript()
{
  return JavaScript(js);
}
// JavaScript是Controller类的一个辅助器方法,充当JavaScriptResult对象工厂的角色
protected JavaScriptResult JavaScript(string js)
{
  // JavaScriptResult类提供公共属性Script,它包含会写入输出流的脚本代码。
  return new JavaScriptResult(){Script = script};
}
/**JavaScriptResult**/
public class JavaScriptResult:ActionResult
{
  public String Script {get; set;}
  public override void ExecuteResult(ControllerContext context)
  {
    if(context == null) throw new ArgumentNullException("context");
    // Prepare the response
    HttpResponseBase response = context.HttpContext.Response;
    response.ContentType = "application/x-javascript";
    if(Script != null)
    {
        response.Write(Script);
    }
  }
}

控制器的动作结果

控制器动作结果ActionResult是控制器动作返回的结果,即控制器返回给浏览器请求的响应内容。

ASP.NET MVC框架支持6种标准类型的动作结果

EmptyResult表示无结果

ViewResult表示返回HTML及标记

public ViewResult About()
{
    ViewBag.Message = "Your application description page.";

    return View();
}

JsonResult表示返回JSON结果

public JsonResult TestJson()
{
    var jsonResult = new JsonResult();

    jsonResult.Data = new object[]
    {
        new {UserID = 10010,UserName = "IronMan"},
        new {UserID = 10012,UserName = "AntMan"},
    };
    jsonResult.Data = new { UserID = 100, UserName = "SuperMane" };

    jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
    return jsonResult;
}

ContentResult表示返回文本结果

public ContentResult Content()
{
    return Content("Hello World");
}

RedirectResult表示重定向到新的URL

public RedirectResult Goto(string url)
{
    return Redirect(url);
}

RedirectToRouteResult表示重定向到新的控制器动作上

public RedirectToRouteResult Reload()
{
    return RedirectToAction("Index");
}

控制器的视图数据

View和Action之间前后台数据传递的方式

  • 弱类型 ViewData[""]
  • 动态型dynamicViewBag
  • 动态类型 Model
  • 临时存储 TempData[""]
  • 后台 return View(data) 存入 ViewData.Model
  • 前台 ModelWebViewPage.Model

使用强类型视图@model 类型写在View最顶部,@ViewData.Model简写为@Model@Html.xxFor(x=>x.**)。使用强类型的好处是提供智能提示,实现编译时错误检查,防止写错字段。

ViewBag.Message = "Your application description page.";

ViewData、TempData、ViewBag的区别

三者都是容器,能存储常量和变量,也能存储集合。

  • ViewDataViewBag

ViewBagViewData属性是同一份数据的不同表现形式,本质上都是ViewDataDictionary,二者之间数据共享。

ViewData为对象型,ViewBagDynamic动态对象,动态类型会在程序运行时动态解析,可为其指定任意属性,最终动态属性名作为数据字典的键名。动态类型dynamic和对象型object的区别是在dynamic使用时会自动根据数据类型转换,object则需要我们自己去强制转换。

ViewBag只是在ViewData上多了一层Dynamic控制,可以说是访问ViewData的另一种方式。理论上ViewBag要比ViewData慢一点儿。

  • ViewDataTempData

ViewDataTempData属性均返回一个具有字典键值对结构的数据容器,TempData存储临时数据,且设置的变量在被第一次读取后会被移除,也就是说TempData设置的变量只能被读取一次。ViewDataViewBag只对当前View有用,TempData则可以在不同的Action中进行传值,类似Webform中的SessionTempData的值在取了一次后会自动删除。TempData用来在一次请求中同时执行的多个Action方法之间共享数据。

视图

ASP.NET MVC 3引入Razor视图引擎(Razor view engine)。Razor视图模板使用.csshtml文件扩展名,使用C#创建所要输出的HTML。

// 使用视图模板生成HTML返回给浏览器
// 控制器方法(ActionMethod 操作方法)一般返回一个ActionResult或从ActionResult所继承的类型
// 而非原始类型如字符串
public ActionResult Default()
{
  return View();
}


# http://localhost:49184/Test/Welcome?message=hello&count=3
public ActionResult Welcome(string message, int count = 0)
{
    ViewBag.Message = message;
    ViewBag.Count= count;
    return View();
}
# Welcome.cshtml
@{
    ViewBag.Title = "Welcome";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

Welcome

    @for (int i = 0; i < ViewBag.Count; i++) {
  • @ViewBag.Message
  • }

向浏览器输出HTML源码

# System.Web.IHtmlString
@Html.Raw("")

Razor布局的部分视图

ASP.NET MVC中的部分视图相当于WebForm中的User Control,由于页面中会有许多重用的地方,可进行封装重用。使用部分视图的好处是既可以简写代码,又可以使页面代码更加清晰更好维护。

  • Razor中的@Html.Partial()@{Html.RenderPartial();}

Partial可直接输出内容,在内部将HTML转换为MVCHtmlString字符串,然后缓存起来,最后一次性输出到页面。显然,转换过程会降低效率,通常使用RenderPartial代替。

  • Razor中的@{Html.RenderPartial();}@{Html.RenderAction();}

RenderPartial不需要创建Controller的Action,而RenderAction需要在Controller中创建加载的Action。RenderAction会先去调用Controller的Action再呈现视图,所以这里会在发起一个链接。除了有HTML代码外,还需通过读取数据库来渲染,就必须使用RenderAction,因此它可以在Action里调用Model里的方法读取数据库,渲染视图后再呈现,而RenderPartial没有Action。

  • Razor中的@{Html.RenderAction();}@Html.Action();
    Action是直接输出和Partial一样存在一个转换的过程,但是不如RenderAction直接输出到当前HttpContext的效果高。

  • Razor中的@{Html.RenderPartial();}@RenderPage()

使用RenderPage来呈现部分,不能使用原来视图的Model和ViewData,只能通过参数来传递。而RenderPartial可使用原来视图的Model和ViewData。

模型

使用.NET Framework数据访问技术Entity Framework,定义和使用模型类。

Entity Framework, EF是支持代码优先(Code First)的开发模式,是相对于原始的CLR Object(POCO类)而言。

using System;
using System.Data.Entity;

namespace MovieManage.Models
{
    //MovieDBContext类代表Entity Framework的电影数据库类
    //负责在数据库中获取、存储、更新、处理Movie类的实例
    //MovieDBContext继承自EF的DbContext基类
    //为了能够引入DbContext和DbSet,需要添加using System.Data.Entity;
    public class MovieDBContext : DbContext
    {
        public DbSet Movies { get; set; }
    }
    //Movie表示数据库中的电影,Movie对象的每个实例,将对应数据库表的一行,Movie类的每个属性将对应表的一列。
    public class Movie
    {
        //属性
        public int ID { get; set; }
        public string Title { get; set; }
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }
}
ASP.NET MVC_第14张图片
image.png

MovieDBContext类负责处理连接到数据库,并将Movie对象映射到数据表记录的任务中。那么如何指定它将连接到数据库呢?实际上,默认EF将预设使用LocalDB

SQL Server Express LocalDB,简称LocalDB是SQLServer Express轻量级版本的数据库引擎。在用户模式下启动、执行。LocalDB运行在一个特殊的SQL Server Express的执行模式,所以运行使用MDF文件数据库。通常LocalDB的数据库文件都保存在web项目的App_Data目录下。

默认的EF命名为对象上下文类的一个连接字符串,连接字符串connectionString的名称必须匹配DbContext类的名称。

# web.config
  
    
  

CTRL+SHIFT+B 编译并生成代码后创建控制器

ASP.NET MVC_第15张图片
image.png

VS自动创建CRUD操作、视图被称为scaffolding

System.Data.SqlClient.SqlException:“在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。未找到或无法访问服务器。请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接。 (provider: SQL Network Interfaces, error: 50 - 发生了 Local Database Runtime 错误。无法创建自动实例。有关错误详细信息,请参阅 Windows 应用程序事件日志。
)”

EF

EFEntity Framework中会为每个管理的实体对象创建一个代理包装类对象,其中会跟踪实体对象的状态和每个属性的状态。

EF对象管理器

每个通过EF数据上下文操作的实体对象,都需要存在上下文的容器中,一旦通过上下文的某个方法操作了实体对象后,上下文就会给它加上一个状态标识。

调用上下文的SaveChange()方法时,上下文context会遍历容器中的所有对象,并检查它们的状态标识,并依照标识的值进行相应的SQL增删改查操作。

  1. 通常使用EF更新的方式,先查询出要修改的数据,然后再修改新值。实体对象被修改的属性在代理类对象里的对应属性状态会被修改记录下修改状态。等到调用SaveChange()方法时,EF会遍历其管理的每个实体对象,并根据其包装类对象的状态,生成增删改查的SQL语句并执行。
//实体上下文对象
EFEntities ctx= new EFEntities();
// 查询出要修改的数据
User user= ctx.Users.Find(id);
//设置修改后的值
user.UpdatedAt = DateTime.Now;
//更新到数据库
ctx.SaveChanges();
  1. 为了避免先查询数据库,可直接将被修改的实体对象添加到EF中管理,此时为附加状态Attached,手动设置为未修改状态Unchanged。若修改为Modified那么将执行更新全部列,不过没有赋新值的列,执行生成的UPDATE SQL语句时SET的值仍旧是原来的值。同时,设置被修改的实体对象的包装类对象对应属性为修改状态。
User user = db.Users.Find(id);
if(user!=null){
  // 将实体对象user添加到EF对象容器中,并获取伪包装类对象
  DbEntityEntry entry = db.Entry(user);
  // 将伪包装类对象的状态设置为Unchanged
  entry.State = System.Data.EntityState.Unchanged;
  // 对要修改的列Visited进行赋值
  user.Visited = user.Visited + 1;
  //设置被改变的属性
  entry.Property(a=>a.Visited).IsModified = true;
  //提交到数据库完成修改
  int i = db.SaveChanges();//返回执行修改的行数
  if(i>0){
    //...
  }
}
// 执行修改
[HttpPost]

public ActionResult Modify(BlogArticle model)
{
  try
  {
    //将实体对象model加入EF对象容器中,并获取伪包装类对象entry。
    DbEntityEntry entry =  db.Entry(model);
    //将包装类对象entry的状态设置为unchanged
    entry.State = System.Data.EntityState.Unchanged;
    //设置被修改的属性
    entry.Property(a=>a.Title).IsModified = true;
    entry.Property(a=>a.Author).IsModified = true;
    entry.Property(a=>a.Category).IsModified = true;
    //提交到数据库以完成修改
    db.SaveChanges();
    //更新成功后重定向
    return RedirectToAction("Index","Home");
  }
  catch(Exception e)
  {
    return Content("修改失败..."+e.Message);
   }
}
//执行删除
public ActionResult Delete(int id)
{
  try
  {
    // 创建待删除对象
    BlogArticle ba = new BlogArticle();
    ba.Id = id;
    //将待删除对象添加到EF对象管理容器
    db.BlogArticles.Attach(ba);
    //将对象包装类的状态标识设置为删除状态
    db.BlogArticles.Remove(ba);
    //更新到数据库
    db.SaveChanges();
    //跳转重定向
    return RedirectToAction("Index","Home");
  }
  catch(Exception e)
  {
    return RedirectToAction("友好提示页面");
  }
}

创建数据库上下文
协调为给定的数据模型的实体框架功能的主类是数据库上下文类。通过从派生来创建此类System.Data.Entity.DbContext类。该类中可指定数据模型中包含哪些实体。

ashx

ashx用于处理程序HttpHandler,是.NET众多Web组件的一种,.ashx是其扩展名。一个httpHandler接受并处理一个HTTP请求,类似于Java中的Servlet,Java中需继承HttpServlet类。在.NET中需要实现IHttpHandler接口,此接口有一个IsReusable成员,一个待实现的方法ProcessRequest(HttpContextctx)。程序在ProcessRequest()方法中接收到HTTP请求。成员IsReusable指定此IHttpHanlder实例是否可被用来处理多个请求。

.ashx文件用于编写web handlerashx必须包含IsReuseable属性,代表是否可复用。如果要在.ashx文件中使用SESSION必须实现IRequiresSessionState接口。

.ashx程序适合产生供浏览器处理的、无需回发处理的数据格式,例如用于生成动态图片、动态文本等内容。

你可能感兴趣的:(ASP.NET MVC)