第六章 使用Visual Studio

第六章 使用Visual Studio

本章中将介绍一些Visual Studio用于开发ASP.NET Core MVC的关键特性, 下面是章节概括

问题 解决方案
添加程序包 使用NuGet添加.NET包, Bower添加前端包
即时查看视图和类改变的影响 迭代开发模式
在浏览器中显示详细信息 开发者异常页面
得到程序执行的详细信息 调试器
使用VS重新加载浏览器 浏览器链接
减少JS和CSS文件的HTTP请求数量和带宽占用 文件打包

准备示例项目

仍然和上一章一样, 但创建的项目叫WorkingWithVisualStudio

// StartUp.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

namespace WorkingWithVisualStudio {
    public class Startup {
        public void ConfigureServices(IServiceCollection services) {
            services.AddMvc();
        }
        public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
            app.UseMvcWithDefaultRoute();
        }
    }
}

不同的是把默认在debug环境中开启的developer exception page关闭了.

创建模型

// Models\Product.cs

namespace WorkingWithVisualStudio.Models
{

    public class Product
    {
        public string Name { get; set; }
        public decimal Price { get; set; }
    }
}

再创建一个用于存储的类(内存中)

// Models\SimpleRespository.cs

using System.Collections.Generic;

namespace WorkingWithVisualStudio.Models
{
    public class SimpleRepository
    {
        private static SimpleRepository sharedRepository = new SimpleRepository();

        private Dictionary<string, Product> products = new Dictionary<string, Product>();

        public static SimpleRepository SharedRepository => sharedRepository;

        public SimpleRepository()
        {
            var initialItems = new[] {
                new Product { Name = "Kayak", Price = 275M },
                new Product { Name = "Lifejacket", Price = 48.95M },
                new Product { Name = "Soccer ball", Price = 19.50M },
                new Product { Name = "Corner flag", Price = 34.95M }
            };

            foreach (var p in initialItems)
            {
                AddProduct(p);
            }
        }
        public IEnumerable<Product> Products => products.Values;
        public void AddProduct(Product p) => products.Add(p.Name, p);
    }
}

此类将数据存储在内存中, 每次应用停止数据就会丢失, 用于演示很便利, 但显然不会在真实环境中使用. 第八章中将介绍使用关系型数据库进行持久化存储的技术.

注意: 上面的代码使用了单例模式用于共享数据, 这不是最佳方案, 我会在第十八章中描述一个共享组件的更好方式.

创建控制器和视图

// Controllers\HomeController.cs

using Microsoft.AspNetCore.Mvc;
using WorkingWithVisualStudio.Models;

namespace WorkingWithVisualStudio.Controllers {
    public class HomeController : Controller {
        public IActionResult Index()
            => View(SimpleRepository.SharedRepository.Products);
    }
}

Index是一个简单的行为, 获取数据并传递给默认视图, 创建视图

<!-- \Views\Home\Index.cshtml -->

@model IEnumerable<WorkingWithVisualStudio.Models.Product>

@{ Layout = null; }

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Working with Visual Studio</title>
</head>
<body>
    <table>
        <thead>
            <tr><td>Name</td><td>Price</td></tr>
        </thead>
        <tbody>
            @foreach (var p in Model)
            {
                <tr>
                    <td>@p.Name</td>
                    <td>@p.Price</td>
                </tr>
            }
        </tbody>
    </table>
</body>
</html>

效果图如下

这里写图片描述

管理软件包

在ASP.NET Core MVC项目中有两种不同的软件包管理方式, 我将介绍每种类型的软件包, 以及管理他们的工具.

NuGet

VS提供了管理.NET包的可视化工具. 在工具 > NuGet包管理器 > 管理解决方案的程序包打开此工具. (界面很容易理解)

!理解包Microsoft.AspNetCore.All

如果你用过早期版本的ASP.NET Core, 你可能知道在创建新项目时要添加很多NuGet包. ASP.NET Core 2采用了不同的方式, 只需要依赖一个包Microsoft.AspNetCore.All.
Microsoft.AspNetCore.All是一个元包(meta-package), 包含ASP.NET Core和MVC框架需要的所有独立的NuGet包, 也就是说你不需要一个一个地添加包了. 在发布应用的时候, 没有用到的程序包会自动被移除, 以保证应用的清洁.

理解NuGet包列表和位置

NuGet会在<ProjectName>.csproj文件中跟踪项目使用的软件包, 在此项目中存储在WorkingWithVisualStudio.csproj中. 在解决方案资源管理器中右键项目, 可以打开此文件. .csproj是一个XML文件, 其中一部分是程序包的信息

<ItemGroup>
  <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
</ItemGroup>

一个程序包需要使用名字和版本号来限定. 添加新的程序包有三种方式: 使用NuGet图形界面, 使用NuGet命令行, 以及直接修改.csproj文件. VS会检测到csproj文件的修改, 并自动下载程序包
NuGet安装程序包时会自动安装依赖项, 在解决方案资源管理器 > 依赖项 > NuGet中可以看到程序包及其依赖项

Bower

前端库包含发送到客户端的内容, 例如JS, CSS和图片. NuGet也可以管理这些包, 但ASP.NET Core MVC现在使用Bower工具. Bower是一个开源工具, 且得到了广泛应用.

注意: Bower最近被抨击了, 你可能会看到推荐使用替代工具的警告. 但Bower仍然在积极维护, 且支持集成到VS. 在某种程度上可以期望微软支持另一种前端包管理工具, 但在实现之前可以继续使用Bower. (在npm中安装bower时将提示: We don’t recommend using Bower for new projects. Please consider Yarn and Webpack or Parcel. You can read how to migrate legacy project here , bower作者都推荐使用其他工具了, 且我的VS2017版本中也找不到Bower的集成…..很绝望啊….使用方法详见github仓库的readme)

Bower包列表

Bower包在bower.json中指定.

!由于我的VS中没有集成Bower(在安装程序中也没有发现bower组件), 所以需要在项目下先添加一个配置文件.bowerrc(选择新建一个文本文件)

{
  "registry": "https://registry.bower.io",
  "directory": "wwwroot/lib"
}

这个文件指定了安装位置, 否则使用命令行会把程序包安装在bower_components

然后新建bower配置文件bower.json, 填写默认内容

{
  "name": "asp.net",
  "private": true,
  "dependencies": {
  }
}

在解决方案资源管理器中, bower.json会自动折叠.bowerrc, 且bower的一些智能感知功能还是可以用的, 然后在”依赖项”中可以打开GUI工具. 感觉微软的态度可能是在逐步脱离bower.

Bower的使用方法和NuGet类似, 可以使用UI工具, 直接修改配置文件, 或者使用PM命令行. 包会在执行编译之前下载.

{
  "name": "asp.net",
  "private": true,
  "dependencies": {
    "bootstrap": "4.1.2"
  }
}

(具体使用方法请自行搜索)

迭代开发

Web应用开发通常是一个迭代过程, 在对视图和类进行细微修改后就需要重新运行来查看效果. MVC和VS支持查看实时修改.

修改Razor页面

在开发过程中, 当从浏览器接收到HTTP请求时, Razor视图的更改就会起效. 先开始调试应用, 再修改视图(包括DOM元素和Razor代码块), 刷新页面会直接显示变化.

(个人推测这个机制是由于在返回时先检测改动, 加载文件再进行编译, 相比之下以前的C#开发在调试时不可以进行代码修改)

修改C#类

对于C#类(控制器和视图), 处理更改的方式取决于如何启动应用程序. 在”调试”菜单中有两个选项

  • 开始运行(不调试): 类会在HTTP请求到来时自动编译, 开发可以更灵活, 但不运行调试器, 就不能精确控制代码
  • 开始调试: 每次更改后都需要重新编译才能生效, 附加调试器, 可以检查代码状态并分析问题.

自动编译C#类

在一般的开发活动中, 快速的迭代循环让你能够即时看到更改. 在这种开发模式中, VS会在接收到HTTP请求并检测到更改时自动重新编译.
“开始执行(不调试)”, 之后更改代码, 刷新网页就会看到更改(但这个过程相比改前端还是挺慢的)
当一切都计划好时, 自动编译特性很有用. 缺点则是错误和异常只会显示在浏览器(没开调试器)中, 很难弄清楚到底发生了什么.

使用开发者异常页面

启用developer exception page来缓解上面的问题, 在StartUp.cs中配置(默认是打开的)

public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
    app.UseDeveloperExceptionPage();
    app.UseMvcWithDefaultRoute();
}

浏览器显示的错误信息可以解决简单的问题, 特别是因为迭代开发方式意味着错误很可能是因为最近的更改. 但对于更复杂的问题, VS调试器是必须的.

使用调试器

(… 这个没什么要说的了吧…应该都会用)

浏览器链接

浏览器链接特性可以将一个或多个浏览器置于VS的控制下, 从而简化开发过程. 浏览器链接只有在”开始执行(无调试器)”模式下才有效, 可以不用手动切换到浏览器刷新页面就看到修改.
(我没看到啊…..我这用户权限设置太高了??不….需要进行一些设置)

启用功能

老规矩, StartUp.cs

// StartUp.cs
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseMvcWithDefaultRoute();
            app.UseBrowserLink();
            app.UseDeveloperExceptionPage();
        }

然后应该就可以了(反正我这不行), 如果成功链接, 在调试按钮旁边的刷新按钮就可以刷新浏览器

这里写图片描述

使用多个浏览器

在调试按钮的IIS配置中设置

这里写图片描述

为部署准备JS和CSS

写web前端的时候通常有很多JS和CSS文件. 这些文件需要被处理, 以便在生产环境中优化, 减少HTTP请求数量及带宽占用, 这个过程称为”bundling”或”minification”(不管叫什么, 称作”打包”了), 是一个压缩过程. 本节将介绍如何启用静态内容的交付, 以及如何为部署准备这些内容

启用静态内容交付

StartUp.cs

app.UseStaticFiles();

向项目中添加静态内容

为了演示打包过程, 需要先添加一些静态内容, 并包含进实例应用中. 创建wwwroot/css文件夹和wwwroot/js文件夹, 然后创建文件

/* wwwroot\css\first.css */

h3 {
    font-size: 18pt;
    font-family: sans-serif;
}

table, td {
    border: 2px solid black;
    border-collapse: collapse;
    padding: 5px;
    font-family: sans-serif;
}
/* wwwroot\css\second.css */

p {
    font-family: sans-serif;
    font-size: 10pt;
    color: darkgreen;
    background-color: antiquewhite;
    border: 1px solid black;
    padding: 2px;
}
// wwwroot\js\third.js

document.addEventListener("DOMContentLoaded", function () {
    var element = document.createElement("p");
    element.textContent = "This is the element from the third.js file";
    document.querySelector("body").appendChild(element);
});
// wwwroot\js\fourth.js

document.addEventListener("DOMContentLoaded", function () {
    var element = document.createElement("p");
    element.textContent = "This is the element from the fourth.js file";
    document.querySelector("body").appendChild(element);
});

更新视图

将刚创建好的静态内容引入视图

<!-- Views\Home\Index.cshtml -->

@model IEnumerable<WorkingWithVisualStudio.Models.Product>

@{ Layout = null; }

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Working with Visual Studio</title>
    <link rel="stylesheet" href="css/first.css" />
    <link rel="stylesheet" href="css/second.css" />
    <script src="js/third.js"></script>
    <script src="js/fourth.js"></script>
</head>
<body>
    <h3>Products</h3>
    <p>Request Time: @DateTime.Now.ToString("HH:mm:ss")</p>
    <table>
        <thead>
            <tr><td>Name</td><td>Price</td></tr>
        </thead>
        <tbody>
            @foreach (var p in Model)
            {
                <tr>
                    <td>@p.Name</td>
                    <td>@($"{p.Price:C2}")</td>
                </tr>
            }
        </tbody>
    </table>
</body>
</html>

显示效果应该如下(如果样式不对, 可能是没有启用静态文件交付)

这里写图片描述

在MVC应用中对静态文件进行打包

现在有四个静态文件, 浏览器也必须发送所有的四个请求. 而且每个文件中也包含大量的空白, 这些空白可以让开发者更容易阅读, 但对于客户端是没用的, 而且会占用大量的带宽.
合并同样类型的文件称为”捆绑”(bundling), 让文件更小称为”紧缩”(minification). 这些任务都可以使用VS扩展”Bundler & Minifier”完成

安装VS扩展

工具 > 扩展和更新 > 联机 > 搜索, 插件将在VS关闭后完成安装.

打包文件

安装完毕后, 重启VS并打开项目. 在解决方案资源管理器中选区多个同类型的文件, 执行操作

这里写图片描述

插件会创建一个捆绑后的文件bundle.css, 以及一个紧缩后的文件bundle.min.css. 对js文件重复此过程.

注意: 为了保证加载顺序, 需要按顺序在解决方案资源管理器中选取文件, 再进行执行.

之后在视图文件中修改引入的文件

<!-- Views\Home\Index.cshtml -->

@model IEnumerable<WorkingWithVisualStudio.Models.Product>
@{ Layout = null; }

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Working with Visual Studio</title>
    <link rel="stylesheet" href="css/bundle.min.css" />
    <script src="js/bundle.min.js"></script>
</head>
<body>
    <h3>Products</h3>
    <p>Request Time: @DateTime.Now.ToString("HH:mm:ss")</p>
    <table>
        <thead>
            <tr><td>Name</td><td>Price</td></tr>
        </thead>
        <tbody>
            @foreach (var p in Model) {
                <tr>
                    <td>@p.Name</td>
                    <td>@($"{p.Price:C2}")</td>
                </tr>
            }
        </tbody>
    </table>
</body>
</html>

应用程序看起来没有任何变化, 但静态文件已经被打包了.
打包完成后, 扩展将生成一个配置文件bundleconfig.json

[
  {
    "outputFileName": "wwwroot/css/bundle.css",
    "inputFiles": [
      "wwwroot/css/first.css",
      "wwwroot/css/second.css"
    ]
  },
  {
    "outputFileName": "wwwroot/js/bundle.js",
    "inputFiles": [
      "wwwroot/js/third.js",
      "wwwroot/js/fourth.js"
    ]
  }
]

可以在此修改配置(特别是文件顺序). 扩展程序会自动监视输入文件的改动, 在保存改动后自动重新进行打包操作.

总结

本章介绍了VS为web应用开发提供的特性, 包括自动编译类, 浏览器连接和静态文件打包.
下一章将介绍MVC项目的单元测试

猜你喜欢

转载自blog.csdn.net/crf_moonlight/article/details/81065676