检查编辑方法和编辑视图

本教程是ASP.NET MVC 5教程介绍的一系列Visual Basic版本的第七个 发布于www.asp.net网站。原创系列,由此产生 Scott Guthrie (twitter @scottgu. ), 斯科特·汉斯曼 (推特: @Shanselman. ), and 里克安德森 ( @rickandmsft. )使用C#语言编写。我的版本尽可能靠近原件,只改变编码语言。叙述文本从原始文本保持不变,并与Microsoft权限一起使用。

本教程系列将教导您使用构建ASP.NET MVC 5 Web应用程序的基础知识 Visual Studio 2013. 和Visual Basic。具有VB源代码的Web项目的Visual Studio Express可用于伴随您可以的系列 下载.

教程系列总共包括11个部分。它们使用ASP.NET MVC框架和用于数据访问的实体框架来涵盖Web开发的基础知识。它们旨在顺序顺序排列,因为每个部分都在上一节中赋予的知识。通过该系列的导航路径如下:

  1. 入门
  2. 添加控制器
  3. 添加视图
  4. 添加模型
  5. 创建连接字符串并使用SQL Server LocalDB
  6. 从控制器访问模型的数据
  7. 检查编辑方法和编辑视图
  8. 添加搜索
  9. 添加一个新字段
  10. 添加验证
  11. 检查详细信息并删除方法

7.检查编辑方法和编辑视图

在本节中,您将检查生成的“电影控制器的编辑操作方法和视图”。但首先将采取短期转移,使发布日期看起来更好。打开 模型\ Movie.vb. 文件并添加下面显示的突出显示的线条:

Imports System.ComponentModel.DataAnnotations
Imports System.Data.Entity

Namespace Models
    Public Class 电影
        Public Property ID As Integer
        Public Property 标题 As String
        <展示(Name:="Release Date")>
        <数据类型(数据类型.Date)>
        <displayformat.(DataFormatString:="{0:yyyy-MM-dd}", ApplyFormatInEditMode:=真的)>
        Public Property 发布日期 As DateTime
        Public Property 类型 As String
        Public Property 价格 As Decimal
    End Class

    Public Class 电影dbcontext.
        Inherits DbContext

        Public Property 电影 As DbSet(Of 电影)
    End Class

End Namespace

您还可以制作这样的日期文化,如下所示:

<displayformat.(DataFormatString:="{0:d}", ApplyFormatInEditMode:=真的)>

突出显示的线条出现在内 < > 括号是来自的属性 dataannotations命名空间。我们将在下一个教程中更详细地介绍数据注释。这 展示 属性指定显示字段名称的内容(在这种情况下"Release Date" instead of "ReleaseDate"). The 数据类型 属性指定数据的类型,在这种情况下是一个 日期,因此不显示存储在字段中的时间信息。这 displayformat. Chrome浏览器中的错误需要属性,以错误地呈现日期格式。

运行应用程序并浏览到 电影 控制器。将鼠标指针握住 编辑 链接查看它链接到的URL。

编辑方法

 

这 编辑 链接是由 html.actionLink. method in the 视图\电影\ index.vbhtml view:

@html.actionLink.("Edit", "Edit", New With {.id = item.ID }) |

编辑方法

这 HTML. 对象是一个使用属性公开的帮助者 system.web.mvc.webviewpage. base class. The ActionLink 帮助程序的方法使得可以轻松地动态生成链接到控制器上的操作方法的HTML超链接。 ActionLink方法的第一个参数是渲染的链接文本(例如,<a>Edit Me</a>)。这 second argument is the name of the action method to invoke (In this case, the 编辑 行动)。最后的论点是一个 匿名对象 生成路由数据(在这种情况下,ID为4)。

先前图像中显示的生成链接是 http:// localhost:1804 /电影/编辑/ 4。默认路线(成立于 app_start \ rateconfig.vb.)采用URL模式 {controller} / {action} / {id}。因此,ASP.NET翻译 http:// localhost:1804 /电影/编辑/ 4  进入请求 编辑 action method of the 电影 具有参数ID的控制器等于4.检查以下代码 app_start \ rateconfig.vb. 文件。这 MapRoute. 方法用于将HTTP请求路由到正确的控制器和操作方法,并提供可选的ID参数。这 MapRoute. 方法也用于 htmlhelpers. such as ActionLink. 为控制器,操作方法和任何路由数据生成URL。

Public Sub RegisterRoutes(ByVal routes As RouteCollection)
    
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}")

    routes.MapRoute(
            name:="Default",
            url:="{controller} / {action} / {id}",
            defaults:=New With {.controller = "Home", .action = "Index", .id = UrlParameter.Optional}
        )
End Sub

您还可以使用查询字符串传递操作方法参数。例如,URLhttp:// localhost:1804 /电影/编辑?ID = 3 也将参数ID的参数ID传递给 编辑 action method of the 电影 controller.

编辑方法

打开电影控制器。他们俩 编辑 操作方法如下所示。

' GET: /Movies/Edit/5
Function 编辑(ByVal id As Integer?) As ActionResult
    If IsNothing(id) 这n
        Return New HttpStatusCodeResult(HttpStatusCode.BadRequest)
    End If
    Dim 电影 As 电影 = db.Movies.Find(id)
    If IsNothing(movie) 这n
        Return httpnotfound.()
    End If
    Return View(movie)
End Function

'POST: /Movies/Edit/5
'To protect from overposting attacks, please enable the specific properties you want to bind to, for 
'more details see http://go.microsoft.com/fwlink/?LinkId=317598.
<httppost()>
<ValidateAntiforgereToken.()>
Function 编辑(<捆绑(Include := "ID,Title,ReleaseDate,Genre,Price")> ByVal 电影 As 电影) As ActionResult
    If Modelstate.Isvalid. 这n
        D b.Entry(movie).State = EntityState.Modified
        db.SaveChanges()
        Return RedirectToAction("Index")
    End If
    Return View(movie)
End Function

注意第二个 编辑 行动方法在之前 httppost 属性。此属性指定过载的 编辑 可以仅针对POST请求调用方法。你可以应用 httpGet. 属性到第一个编辑方法,但这不是必需的,因为它是默认值。 (我们将参考隐式分配的操作方法 httpGet. attribute as httpGet. methods.)  The 捆绑 属性是另一个重要的安全机制,使黑客保持过帐数据到模型。您应该仅包含属性 捆绑 您要更改的属性。您可以阅读Rick Anderson中的Outposting和Bind属性 超级安全说明。在本教程中使用的简单模型中,我们将绑定模型中的所有数据。这 ValidateAntiforgereToken. 属性用于防止伪造请求并与@HTML配对。antiforcerytoken.()在编辑视图文件中(视图\电影\ edit.vbhtml),其中一部分如下所示:

@ModelType MvcMovie.Models.电影
@Code
    ViewData("Title") = "Edit"
End Code

<h2>编辑</h2>

@Using (Html.BeginForm())
    @ html.antiforgerytoken()
    
    @<div class="form-horizontal">
        <h4>电影</h4>
        <hr />
        @HTML..ValidationSummary(true)
        @HTML..HiddenFor(Function(model) model.ID)

        <div class="form-group">
            @html.labelfor.(Function(model) model.Title, New With { .class = "control-label col-md-2" })
            <div class="col-md-10">
                @HTML.EDITINER(Function(model) model.Title)
                @html.validationMessage(Function(model) model.Title)
            </div>
        </div>

@ html.antiforgerytoken()  生成一个隐藏的形式反伪造令牌,必须匹配 编辑 method of the 电影 控制器。您可以在Rick Andersion的教程中阅读更多关于跨站点请求伪造(也称为XSRF或CSRF)的关于 MVC中的XSRF / CSRF预防.

这 httpget编辑 方法采用Movie ID参数,使用实体框架查找电影  方法,并将所选电影返回到编辑视图。如果找不到电影,  httpnotfound. 被退回。当脚手架系统创建编辑视图时,它检查了 电影 类和创建代码呈现<label> and <input> 类的每个属性的元素。以下示例显示了Visual Studio脚手架系统生成的编辑视图:

@ModelType MvcMovie.Models.电影
@Code
    ViewData("Title") = "Edit"
End Code

<h2>编辑</h2>

@Using (Html.BeginForm())
    @HTML..AntiForgeryToken()
    
    @<div class="form-horizontal">
        <h4>电影</h4>
        <hr />
        @HTML..ValidationSummary(true)
        @HTML..HiddenFor(Function(model) model.ID)

        <div class="form-group">
            @html.labelfor.(Function(model) model.Title, New With { .class = "control-label col-md-2" })
            <div class="col-md-10">
                @HTML.EDITINER(Function(model) model.Title)
                @html.validationMessage(Function(model) model.Title)
            </div>
        </div>

        <div class="form-group">
            @html.labelfor.(Function(model) model.ReleaseDate, New With { .class = "control-label col-md-2" })
            <div class="col-md-10">
                @HTML.EDITINER(Function(model) model.ReleaseDate)
                @html.validationMessage(Function(model) model.ReleaseDate)
            </div>
        </div>

        <div class="form-group">
            @html.labelfor.(Function(model) model.Genre, New With { .class = "control-label col-md-2" })
            <div class="col-md-10">
                @HTML.EDITINER(Function(model) model.Genre)
                @html.validationMessage(Function(model) model.Genre)
            </div>
        </div>

        <div class="form-group">
            @html.labelfor.(Function(model) model.Price, New With { .class = "control-label col-md-2" })
            <div class="col-md-10">
                @HTML.EDITINER(Function(model) model.Price)
                @html.validationMessage(Function(model) model.Price)
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <输入 type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
End Using

<div>
    @html.actionLink.("Back to List", "Index")
</div>

@Section Scripts 
    @Scripts.Render("~/bundles/jqueryval")
End Section

这 @modeltype mvcmovie.models.movi​​e. 文件顶部的语句指定视图期望查看模板的模型是类型的 电影.

脚手架代码使用几个 帮手方法 简化HTML标记。这 html.labelfor. 帮助程序显示字段的名称("Title", "ReleaseDate", "Genre", or "Price"). The HTML.EDITINER 帮手渲染HTML <input> element. The html.validationMessage Helper显示与该属性关联的任何验证消息。

运行应用程序并导航到 /电影 URL. Click an 编辑 关联。在浏览器中,查看页面的源。表单元素的生成HTML如下所示。

<形式 行动="/Movies/Edit/4" method="post">
    <输入 name="__RequestVerificationToken" type="hidden" value="2woDzftMzbwwv1BFDqGL4CRGJKc-Y72RCnnTZmKoBPBP_MNhM4XVu5dl6p9CV7S4yqv3yhtbqFzyJKLd3gqRRYNnfyP6Zy3DxtOXKf1p3ok1" />    
    <div class="form-horizontal">
        <h4>电影</h4>
        <hr />

        <输入 data-val="true" data-val-number="The field ID must be a number." data-val-required="The ID field is required." id="ID" name="ID" type="hidden" value="4" />

        <div class="form-group">
            <标签 class="control-label col-md-2" for="Title">标题</标签>
            <div class="col-md-10">
                <输入 class="text-box single-line" id="Title" name="Title" type="text" value="Up" />
                <span class="field-validation-valid" data-valmsg-for="Title" data-valmsg-replace="true"></span>
            </div>
        </div>

        <div class="form-group">
            <标签 class="control-label col-md-2" for="ReleaseDate">发布日期</标签>
            <div class="col-md-10">
                <输入 class="text-box single-line" data-val="true" data-val-date="The field Release Date must be a date." data-val-required="The Release Date field is required." id="ReleaseDate" name="ReleaseDate" type="date" value="2009-10-09" />
                <span class="field-validation-valid" data-valmsg-for="ReleaseDate" data-valmsg-replace="true"></span>
            </div>
        </div>

        <div class="form-group">
            <标签 class="control-label col-md-2" for="Genre">类型</标签>
            <div class="col-md-10">
                <输入 class="text-box single-line" id="Genre" name="Genre" type="text" value="Animation" />
                <span class="field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
            </div>
        </div>

        <div class="form-group">
            <标签 class="control-label col-md-2" for="Price">价格</标签>
            <div class="col-md-10">
                <输入 class="text-box single-line" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Price" name="Price" type="text" value="6.99" />
                <span class="field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <输入 type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
</形式>

这 <input> 元素在HTML中 <form> element whose 行动 属性设置为发布到 /电影/编辑 URL。表单数据将发布到服务器时 保存 单击按钮。第二行显示隐藏的 XSRF. 由此产生的令牌 @ html.antiforgerytoken() method call.

处理POST请求

以下列表显示 httppost version of the 编辑 action method.

<httppost()>
<ValidateAntiforgereToken.()>
Function 编辑(<捆绑(Include := "ID,Title,ReleaseDate,Genre,Price")> ByVal 电影 As 电影) As ActionResult
    If Modelstate.Isvalid. 这n
       D b.Entry(movie).State = EntityState.Modified
       db.SaveChanges()
       Return RedirectToAction("Index")
    End If
    Return View(movie)
End Function

这 ValidateAntiforgereToken. 属性验证  XSRF. 由此产生的令牌 @ html.antiforgerytoken() call in the view.

这 ASP.NET MVC.模型粘合剂 采用发布的表单值并创建一个 电影 从价值观传递的对象 电影 parameter. The Modelstate.Isvalid. property is set to 真的 如果表单中提交的数据可用于修改(编辑或更新)a 电影 目的。如果数据有效,则 电影 data is saved to the 电影 collection of the D b (电影dbcontext. 实例)。新电影数据通过调用来保存到数据库 保存更改 method of 电影dbcontext.。保存数据后,代码将用户重定向到 指数 action method of the 电影控制器 显示电影集合的类,包括更改。

一旦客户端验证确定字段的值无效,就会显示错误消息。如果禁用JavaScript,则不会有客户端验证,但服务器将检测到过帐值无效,并且表单值将被重新显示错误消息。后来在教程中,我们将更详细地检查验证。

 The html.validationMessage helpers in the 编辑.vbhtml. 查看模板要小心显示适当的错误消息。

编辑方法

所有 httpGet. 方法遵循类似的模式。他们得到了一个 电影 对象(或对象列表,在案例中) 指数),并将模型传递给视图。这 创造 方法将空的电影对象传递给Create View。在该方法的HTTPPOST过载中创建,编辑,删除或以其他方式修改数据的所有方法。在HTTP GET方法中修改数据是安全风险,如博客文章条目中所述 ASP.NET MVC.提示#46 - 不要使用删除链接,因为它们会创建安全漏洞。在GET方法中修改数据也违反了HTTP最佳实践和架构 休息 图案,指定Get请求不应更改应用程序的状态。换句话说,执行Get操作应该是一个安全操作,其没有副作用,并且不会修改持久数据。

如果您使用的是美国英语计算机,则可以跳过本节并转到下一个教程。您可以下载本教程的全球化版本 这里。有关国际化的一个优秀的两部分教程,请参阅 Nadeem的ASP.NET MVC 5国际化.

 

笔记 支持使用逗号的非英语语言环境的jQuery验证(",")对于小数点,而非美国英语日期格式,您必须包含 globalize.js and your specific文化/ globalize.cultures.js. file(from //github.com/jquery/globalize 使用globalize.parsefloat的javascript。您可以从Nuget获取jQuery非英语验证。 (如果您使用英语区域设置,请不要安装全球化。)

  1. From the 工具 菜单点击 图书馆包管理器,然后单击 管理解决方案的Nuget包.

    编辑方法

  2. 在左窗格中,选择在线。 (参见下面的图像。)
  3. 在“搜索已安装的包输入”框中,输入 全球化.

    编辑方法

  4. 点击 安装。脚本\ jquery.globalize \ globalize.js文件将添加到您的项目中。脚本\ jquery.globalize \ Cultures \ folder将包含许多文化JavaScript文件。注意,安装此包可能需要五分钟。

以下代码显示了对视图\ Movies \ Edit.vbhtml文件的修改:

@Section Scripts 
    @Scripts.Render("~/bundles/jqueryval")

<script src="~/Scripts/globalize/globalize.js"></script>
    <script src="~/Scripts/globalize/cultures/globalize.culture.@(System.Threading.Thread.CurrentThread.CurrentCulture.Name).js"></script>
    <script>
    $.validator.methods.number = function (value, element) {
        return this.optional(element) ||
            !isNaN(Globalize.parseFloat(value));
    }
    $(document).ready(function () {
        Globalize.culture('@(System.Threading.Thread.CurrentThread.CurrentCulture.Name)');
    });
    </script>
    <script>
        jQuery.extend(jQuery.validator.methods, {
            range: function (value, element, param) {
                //Use the Globalization plugin to parse the value
                var val = Globalize.parseFloat(value);
                return this.optional(element) || (
                    val >= param[0] && val <= param[1]);
            }
        });
        $.validator.methods.date = function (value, element) {
            return this.optional(element) ||
                Globalize.parseDate(value) ||
                Globalize.parseDate(value, "yyyy-MM-dd");
        }
    </script>
    }
End Section

为避免在每个编辑视图中重复此代码,您可以将其移动到布局文件中。要优化脚本下载,请参阅我的教程 捆绑和缩小.

有关更多信息,请参阅 ASP.NET MVC. 3国际化 and ASP.NET MVC. 3国际化 - 第2部分(Nerddinner).

作为临时修复,如果您无法在您的区域设置中验证工作,则可以强制您的计算机使用美国英语,或者您可以在浏览器中禁用JavaScript。要强制您的计算机使用美国英语,可以将全球化元素添加到项目根目录 web.config. 文件。以下代码显示了与文化设置为美国英语的全球化元素。

<system.web>
    <globalization culture ="en-US" />
    <!--elements removed for clarity-->
</system.web>

在下一个教程中,我们将实现搜索功能。