基于Asp.Net Core Mvc和EntityFramework Core 的实战入门教程系列-4-阿里云开发者社区

开发者社区> wer_ltm> 正文

基于Asp.Net Core Mvc和EntityFramework Core 的实战入门教程系列-4

简介: 来个目录吧:第一章-入门第二章- Entity Framework Core Nuget包管理第三章-创建、修改、删除、查询第四章-排序、过滤、分页、分组第五章-迁移,EF Core 的codefirst使用 暂时就这么多。
+关注继续查看

来个目录吧:
第一章-入门
第二章- Entity Framework Core Nuget包管理
第三章-创建、修改、删除、查询
第四章-排序、过滤、分页、分组
第五章-迁移,EF Core 的codefirst使用
暂时就这么多。后面陆续更新吧

本次教程是完成排序、过滤、分页和分组功能

在上一个教程中,学生实体的基本CRUD操作实现了一套网页。在本教程中,您将向学生索引页面添加排序,过滤和分页功能。您还将创建一个简单分组的页面。

下图显示了完成后页面的外观。用户可以单击列标题以按该列排序的链接。重复单击列标题可在升序和降序之间切换。

img_81ec808b5940bbe58098f2aec303c318.png
Paste_Image.png

给学生Index页添加一个排序方法

打开SchoollController.cs 文件,将Index方法,替换为以下代码:

public async Task<IActionResult> Index(string sortOrder)
{
    ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
    ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
    var students = from s in _context.Students
                   select s;
    switch (sortOrder)
    {
        case "name_desc":
            students = students.OrderByDescending(s => s.LastName);
            break;
        case "Date":
            students = students.OrderBy(s => s.EnrollmentDate);
            break;
        case "date_desc":
            students = students.OrderByDescending(s => s.EnrollmentDate);
            break;
        default:
            students = students.OrderBy(s => s.LastName);
            break;
    }
    return View(await students.AsNoTracking().ToListAsync());
}

给index方法添加了个sortOrder参数,可以从Url接收值。查询字符串的值由ASP.NET Core MVC的action方法的参数提供而来。
该参数会是一个字符串,“Name”或者“Date”,可以在后面添加下划线与"desc",指定为降序。默认排序为升序。

第一次加载Index页面的时候,没有查询字符串。学生列表按照升序排序,这个是通过switch的默认值提供的。当用户点击列标题超链接的时候,讲标题的值赋予sortOrder参数。

ViewData 视图使用两个元素(NameSortParm和DateSortParm)来配置列标题超链接与对应的查询字符串值。

public async Task<IActionResult> Index(string sortOrder)
{
    ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";//手动高亮
    ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";//手动高亮
    var students = from s in _context.Students
                   select s;
    switch (sortOrder)
    {
        case "name_desc":
            students = students.OrderByDescending(s => s.LastName);
            break;
        case "Date":
            students = students.OrderBy(s => s.EnrollmentDate);
            break;
        case "date_desc":
            students = students.OrderByDescending(s => s.EnrollmentDate);
            break;
        default:
            students = students.OrderBy(s => s.LastName);
            break;
    }
    return View(await students.AsNoTracking().ToListAsync());
}

String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";//手动高亮
这是一个三元运算符的语句。第一个指定如果sortOrder参数为null或为空,Name的排序应设置为“name_desc”; 否则,应将其设置为空字符串。这两个语句使视图可以按如下所示设置列标题超链接:

img_1e23781a23c4d139ac83c99599185015.png
Paste_Image.png

使用LINQ to Entities指定要排序的列。IQueryable在switch语句之前创建一个变量,在switch语句中进行排序,然后执行完毕后ToListAsync。创建和修改IQueryable变量时,不会向数据库发送任何查询。在IQueryable调用方法将对象转换为集合之前,不会执行查询ToListAsync。

将列标题排序添加到Index视图中

替换Views / Students / Index.cshtml中的代码,使用以下代码添加列标题超链接。

@model IEnumerable<ContosoUniversity.Models.Student>

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
                <th>
                    <a asp-action="Index" asp-route-sortOrder="@ViewData["NameSortParm"]">@Html.DisplayNameFor(model => model.LastName)</a>
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.FirstMidName)
                </th>
                <th>
                    <a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]">@Html.DisplayNameFor(model => model.EnrollmentDate)</a>
                </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.LastName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.FirstMidName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.EnrollmentDate)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.ID">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

此代码使用属性中的ViewData信息来使用适当的查询字符串值设置超链接。
运行页面,然后单击"LastName"和"EnrollmentDate"列标题,以验证排序是否有效。

img_3e3f20b615dfac997a84631e36e1b154.png
Paste_Image.png

给Student的Index视图添加搜索功能

要向学生Index页面添加过滤,您需要向视图中添加一个文本框和一个提交按钮,并对Index方法进行相应的更改。文本框将允许您输入要在名字和姓氏字段中搜索的字符串。

向Index方法添加过滤功能

在StudentsController.cs中,将Index方法替换为以下代码

public async Task<IActionResult> Index(string sortOrder, string searchString)
{
    ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
    ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
    ViewData["CurrentFilter"] = searchString;//手动高亮

    var students = from s in _context.Students
                   select s;
    if (!String.IsNullOrEmpty(searchString))
    {
        students = students.Where(s => s.LastName.Contains(searchString)
                               || s.FirstMidName.Contains(searchString));//手动高亮
    }//手动高亮
    switch (sortOrder)
    {
        case "name_desc":
            students = students.OrderByDescending(s => s.LastName);
            break;
        case "Date":
            students = students.OrderBy(s => s.EnrollmentDate);
            break;
        case "date_desc":
            students = students.OrderByDescending(s => s.EnrollmentDate);
            break;
        default:
            students = students.OrderBy(s => s.LastName);
            break;
    }
    return View(await students.AsNoTracking().ToListAsync());
}

您已向方法添加了searchString参数Index。searchString是从将添加到"Index”视图的文本框中接收的。您还在LINQ语句中添加了一个where子句,该代码表示会搜索Student表中Last Name或者FirstMidName,如果有值则会返回到视图页面上。

注意:
这里你调用对象使用Where上的IQueryable方法,在运行的时候在服务器上处理。在某些情况下,您可能将该Where方法调用为内存中集合的扩展方法。(例如,假设您更改使用_context.Students以便代替EF, DbSet引用返回集合的类型为IEnumerable。)结果通常是相同的,但在某些情况下可能不同。

例如,该Contains方法的.NET Framework实现默认情况下执行,是会区分大小写的,但在SQL Server中,这是由SQL Server实例的排序规则设置决定的,默认为不区分大小写。你可以调用该ToUpper方法让它显式不区分大小写: Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper()).。这将确保结果保持不变,如果你以后更改代码使用一个存储库,它返回一个IEnumerable集合而不是一个IQueryable对象(当你调用集合类型为IEnumerable的Contains方法,你得到的.NET框架实现;当你在一个IQueryable对象上调用它,你得到数据库提供实现。)然而,这个解决方案存在性能损失。ToUpper代码将在TSQL SELECT语句的WHERE子句中放置一个函数。这将阻止优化程序使用索引。考虑到SQL大多数是安装为不区分大小写,最好避免ToUpper代码,直到迁移到区分大小写的数据存储。

在学生Index视图中添加一个搜索框

在Views / Student / Index.cshtml中,在table标签之前添加突出显示的代码,以创建标题,文本框和搜索按钮。

<p>
    <a asp-action="Create">Create New</a>
</p>

<form asp-action="Index" method="get">
    <div class="form-actions no-color">
        <p>
            Find by name: <input type="text" name="SearchString" value="@ViewData["currentFilter"]" />
            <input type="submit" value="Search" class="btn btn-default" /> |
            <a asp-action="Index">Back to Full List</a>
        </p>
    </div>
</form>

<table class="table">

此代码使用<form> tagHelper添加搜索文本框和按钮。
默认情况下,<form>tagHelper使用POST提交表单数据,这意味着参数在HTTP消息正文中传递,而不是作为查询字符串在URL中传递。当您指定使用HTTP GET请求时,表单数据作为查询字符串传递到URL中,这使用户可以为URL添加书签。W3C准则建议您在使用GET请求的时候,不会导致数据的修改。

换句话说,就是使用GET请求应该是查询功能,其他的添加、删除、修改,不能使用GET请求,建议使用POST请求

运行页面,输入任意字符串,然后单击搜索以验证搜索是否正常。

img_e7ceec81a1be038f6976d3014a37243f.png
Paste_Image.png

请注意,该URL包含搜索字符串(SearchString)。

http://localhost:5813/Students?SearchString=an

在这个阶段,如果您点击列标题排序链接,您将丢失在搜索框中输入的过滤器值。你会在下一节中解决这个问题。

给Student的Index页面添加分页功能

要向“学生Index”页面添加分页,您将创建一个PaginatedList类,它使用Skip和Take语句来过滤服务器上的数据,而不是总是检索表的所有行。然后,您将对方法进行其他更改,Index方法的Index视图中添加分页按钮。下图显示了分页按钮。

img_81ec808b5940bbe58098f2aec303c318.png
Paste_Image.png

在项目文件夹中创建PaginatedList.cs,然后用下面的代码替换模板代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

public class PaginatedList<T> : List<T>
{
    public int PageIndex { get; private set; }
    public int TotalPages { get; private set; }

    public PaginatedList(List<T> items, int count, int pageIndex, int pageSize)
    {
        PageIndex = pageIndex;
        TotalPages = (int)Math.Ceiling(count / (double)pageSize);

        this.AddRange(items);
    }

    public bool HasPreviousPage
    {
        get
        {
            return (PageIndex > 1);
        }
    }

    public bool HasNextPage
    {
        get
        {
            return (PageIndex < TotalPages);
        }
    }

    public static async Task<PaginatedList<T>> CreateAsync(IQueryable<T> source, int pageIndex, int pageSize)
    {
        var count = await source.CountAsync();
        var items = await source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
        return new PaginatedList<T>(items, count, pageIndex, pageSize);
    }
}

此代码中的CreateAsync方法采用页面大小和页码,并将适当的Skip和Take语句应用于IQueryable。当IQueryable进行ToListAsync调用时,它将返回一个只包含请求的页面的列表。属性HasPreviousPage,HasNextPage可用于启用或禁用上一页和下一页分页按钮。
使用CreateAsync方法,而不是构造函数来创建PaginatedList<T>对象,因为构造函数不能运行异步代码。

向Index视图中添加分页功能

StudentsController.cs中,将Index方法替换为以下代码。

public async Task<IActionResult> Index(
    string sortOrder,
    string currentFilter,
    string searchString,
    int? page)
{
    ViewData["CurrentSort"] = sortOrder;
    ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
    ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";

    if (searchString != null)
    {
        page = 1;
    }
    else
    {
        searchString = currentFilter;
    }

    ViewData["CurrentFilter"] = searchString;

    var students = from s in _context.Students
                   select s;
    if (!String.IsNullOrEmpty(searchString))
    {
        students = students.Where(s => s.LastName.Contains(searchString)
                               || s.FirstMidName.Contains(searchString));
    }
    switch (sortOrder)
    {
        case "name_desc":
            students = students.OrderByDescending(s => s.LastName);
            break;
        case "Date":
            students = students.OrderBy(s => s.EnrollmentDate);
            break;
        case "date_desc":
            students = students.OrderByDescending(s => s.EnrollmentDate);
            break;
        default:
            students = students.OrderBy(s => s.LastName);
            break;
    }

    int pageSize = 3;
    return View(await PaginatedList<Student>.CreateAsync(students.AsNoTracking(), page ?? 1, pageSize));
}

下面的代码将页码参数,当前排序顺序参数和当前过滤器参数添加到方法中。

public async Task<IActionResult> Index(
    string sortOrder,
    string currentFilter,
    string searchString,
    int? page)

第一次加载页面时,或者如果用户没有单击分页或排序链接,所有参数将为null。如果单击分页链接,页面变量将包含要显示的页码。
名为CurrentSort 的ViewData元素为视图提供了当前的排序顺序,因为这必须包含在分页链接中,以便在分页时保持排序顺序相同。

名为CurrentFilter 的 ViewData元素提供带有当前过滤器字符串的视图。此值必须包含在分页链接中,以便在分页期间过滤器设置,并且必须在重新显示页面时将其还原到文本框。

如果在分页期间更改搜索字符串,则page必须重置为1,因为新的searchString可能导致显示不同的数据。当在文本框中输入值并按下提交按钮时,searchString将更改。在这种情况下,searchString参数不为null。

if (searchString != null)
{
    page = 1;
}
else
{
    searchString = currentFilter;
}

在Index方法结束时,该PaginatedList.CreateAsync方法将学生查询转换为支持分页的List类型中的学生。那个学生集合然后被传递到视图。

return View(await PaginatedList<Student>.CreateAsync(students.AsNoTracking(), page ?? 1, pageSize));

该PaginatedList.CreateAsync方法获取页码。两个问号表示null合并运算符。空联合运算符定义可空类型的默认值; 表达式(page ?? 1)意味着返回值,page如果它有一个值,或返回1如果page为null。

向学生索引视图中添加分页链接

在Views / Students / Index.cshtml中,使用以下代码替换现有代码。

@model PaginatedList<ContosoUniversity.Models.Student>

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

<p>
    <a asp-action="Create">Create New</a>
</p>

<form asp-action="Index" method="get">
    <div class="form-actions no-color">
        <p>
            Find by name: <input type="text" name="SearchString" value="@ViewData["currentFilter"]" />
            <input type="submit" value="Search" class="btn btn-default" /> |
            <a asp-action="Index">Back to Full List</a>
        </p>
    </div>
</form>

<table class="table">
    <thead>
        <tr>
            <th>
                <a asp-action="Index" asp-route-sortOrder="@ViewData["NameSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Last Name</a>
            </th>
            <th>
                First Name
            </th>
            <th>
                <a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Enrollment Date</a>
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.LastName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.FirstMidName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.EnrollmentDate)
                </td>
                <td>
                    <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
                    <a asp-action="Details" asp-route-id="@item.ID">Details</a> |
                    <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>

@{
    var prevDisabled = !Model.HasPreviousPage ? "disabled" : "";
    var nextDisabled = !Model.HasNextPage ? "disabled" : "";
}

<a asp-action="Index"
   asp-route-sortOrder="@ViewData["CurrentSort"]"
   asp-route-page="@(Model.PageIndex - 1)"
   asp-route-currentFilter="@ViewData["CurrentFilter"]"
   class="btn btn-default @prevDisabled btn">
    Previous
</a>
<a asp-action="Index"
   asp-route-sortOrder="@ViewData["CurrentSort"]"
   asp-route-page="@(Model.PageIndex + 1)"
   asp-route-currentFilter="@ViewData["CurrentFilter"]"
   class="btn btn-default @nextDisabled btn">
    Next
</a>

顶部的model类型为PaginatedList<T>而不是List<T>。

列标题链接使用查询字符串将当前搜索字符串传递到控制器,以便用户可以在过滤器结果中排序:

<a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]" asp-route-currentFilter ="@ViewData["CurrentFilter"]">Enrollment Date</a>

分页按钮由tagHelper显示:

<a asp-action="Index"
   asp-route-sortOrder="@ViewData["CurrentSort"]"
   asp-route-page="@(Model.PageIndex - 1)"
   asp-route-currentFilter="@ViewData["CurrentFilter"]"
   class="btn btn-default @prevDisabled btn">
   Previous
</a>

运行页面

img_81ec808b5940bbe58098f2aec303c318.png
Paste_Image.png

按不同排序顺序单​​击分页链接,以确保分页工作正常。然后输入搜索字符串并再次尝试分页,以验证分页在排序和过滤时也能正常工作。

创建一个显示学生统计信息的关于页面

对于Contoso大学网站的“ 关于”页面,您将显示已注册的学生人数以及注册日期。这需要对组进行分组和简单计算。要完成此操作,您需要执行以下操作:

  • 根据业务创建一个ViewModel。
  • 修改Home控制器中的about方法。
  • 修改“About”视图页面。

创建视图模型(ViewModel)

Models文件夹中创建一个SchoolViewModels文件夹。
在新文件夹中,添加类文件EnrollmentDateGroup.cs,并将模板代码替换为以下代码:

using System;
using System.ComponentModel.DataAnnotations;

namespace ContosoUniversity.Models.SchoolViewModels
{
    public class EnrollmentDateGroup
    {
        [DataType(DataType.Date)]
        public DateTime? EnrollmentDate { get; set; }

        public int StudentCount { get; set; }
    }
}

修改Home控制器

在HomeController控制器中引入新的 命名空间

using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Data;
using ContosoUniversity.Models.SchoolViewModels;

然后对HomeController中,添加上下文的实例,进行依赖注入。

public class HomeController : Controller
{
    private readonly SchoolContext _context;

    public HomeController(SchoolContext context)
    {
        _context = context;
    }

将About方法的代码替换为以下代码:

public async Task<ActionResult> About()
{
    IQueryable<EnrollmentDateGroup> data = 
        from student in _context.Students
        group student by student.EnrollmentDate into dateGroup
        select new EnrollmentDateGroup()
        {
            EnrollmentDate = dateGroup.Key,
            StudentCount = dateGroup.Count()
        };
    return View(await data.AsNoTracking().ToListAsync());
}

使用LINQ语句按照注册日期将学生实体分组,计算每个组中的实体数,并将结果存储在EnrollmentDateGroup视图模型对象的集合中。

注意
在1.0版本的Entity Framework Core中,将整个结果集返回给客户端,并在客户端上进行分组。在某些情况下,这可能会导致性能问题。确保使用生产数据量测试性能,并且如果需要,可以使用原始SQL在服务器上进行分组。有关如何使用原始SQL的信息,请参阅

修改关于视图

使用以下代码替换Views / Home / About.cshtml文件中的代码:

@model IEnumerable<ContosoUniversity.Models.SchoolViewModels.EnrollmentDateGroup>

@{
    ViewData["Title"] = "Student Body Statistics";
}

<h2>Student Body Statistics</h2>

<table>
    <tr>
        <th>
            Enrollment Date
        </th>
        <th>
            Students
        </th>
    </tr>

    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.EnrollmentDate)
            </td>
            <td>
                @item.StudentCount
            </td>
        </tr>
    }
</table>

运行应用程序,然后单击关于链接。每个注册日期的学生数量显示在表中。

img_6f25e7c894f7f0ce0f369e6543adbbb5.png
Paste_Image.png

概要

在本教程中,您已经了解了如何执行排序,过滤,分页和分组。在下一个教程中,您将学习如何使用迁移来处理数据模型更改。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
手写SpringMVC实战,一切从Spring底层源码分析开始
Spring框架对于Java后端程序员来说再熟悉不过了,以前只知道它用的反射实现的,但了解之后才知道有很多巧妙的设计在里面。
1179 0
【CSS3 入门教程系列】CSS3 Media Queries 实现响应式设计
  在 CSS2 中,你可以为不同的媒介设备(如屏幕、打印机)指定专用的样式表,而现在借助 CSS3 的 Media Queries 特性,可以更为有效的实现这个功能。你可以为媒介类型添加某些条件,检测设备并采用不同的样式表。
733 0
Java NIO系列教程(九) ServerSocketChannel
Java NIO中的 ServerSocketChannel 是一个可以监听新进来的TCP连接的通道, 就像标准IO中的ServerSocket一样。ServerSocketChannel类在 java.nio.channels包中。
1017 0
java的nio之:java的nio系列教程之SocketChannel
Java NIO中的SocketChannel是一个连接到TCP网络套接字的通道。可以通过以下2种方式创建SocketChannel: 打开一个SocketChannel并连接到互联网上的某台服务器。
877 0
java的nio之:java的nio系列教程之serverSocketChannel
Java NIO中的 ServerSocketChannel 是一个可以监听新进来的TCP连接的通道, 就像标准IO中的ServerSocket一样。ServerSocketChannel类在 java.nio.channels包中。
790 0
Json.Net系列教程 1.Json.Net介绍及实例
原文 Json.Net系列教程 1.Json.Net介绍及实例 本系列教程假设读者已经对Json有一定的了解,关于Json在这里不多说.本系列教程希望能对读者开发涉及到Json的.Net项目有一定的帮 助.本系列教程是根据官方文档资料和自己项目应用汇总而成.如果觉得本系列对你有用,望多多关注.本人还只是个未毕业的学生,水平有限,尽请指正. 一.Json.Net有什么用?   Json.Net是一个读写Json效率比较高的.Net框架.Json.Net 使得在.Net环境下使用Json更加简单。
1085 0
《阿里巴巴Java Spring Boot 2.0开发实战课程》05课:三层MVC网站与架构分层误区、Java面试题
本期分享主题:三层架构MVC网站与分层架构误区、Java面试题,国内系统架构设计的文章和书籍。经常会搞错分层的概念,本课程进行了讲解。还有关于model概念的解析,以及Java Spring Boot2.0面试题。 另外java是免费的!
3151 0
将ASP.NET MVC 2.0 部署在IIS6和IIS7上的教程
我的程序开发环境: 系统:Win7 IIS:IIS7 开发工具:VS2008 SP1 MVC版本:ASP.NET MVC 2.0 RC   在部署MVC应用之前,一定要确保你的程序BIN文件夹下面是否包含 System.Web.Mvc.dll(非常重要),如图:   如果没有, 请在你的MVC项目中,打开引用列表,如图:    鼠标右键点击System.Web.Mvc,选择“属性”,转到下面窗口:   将“复制本地”设为True (默认为False),然后生成一下项目,System.Web.Mvc.dll就会出现在BIN文件夹下了。
976 0
+关注
wer_ltm
梁桐铭,微软MVP,2018微软人工智能大赛教练,腾讯课堂,网易云课堂讲师,学生超过2000人,积微物联技术经理,6年软件开发经验,20人+团队管理经验。负责过多个大型项目的开发和管理,开发的项目数十个,擅长应用系统项目规划设计、处理各种综合性故障与疑难杂症;
25
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载