C# · #csharp#aspnetcore#dotnet-core

.NET Core 1.0 初探:跨平台的新时代

2016.09.14 C# 3 min 1.2k
// 目录 · contents

2016 年 6 月,微软正式发布了 .NET Core 1.0,这是 .NET 平台历史上最大的一次架构重构。作为一个长期在 Windows 上写 C# 的开发者,第一次在 macOS 上 dotnet run 成功时确实有点难以置信。这篇文章记录我的上手体验和核心认知。

1. .NET Core 是什么

.NET Core 不是 .NET Framework 的升级版,而是从零重写的跨平台运行时

.NET Framework .NET Core 1.0
平台 Windows only Windows / Linux / macOS
部署方式 全局安装 可随应用自包含
包管理 GAC + NuGet 纯 NuGet
Web 框架 ASP.NET (System.Web) ASP.NET Core(完全重写)
体积 大(几百MB运行时) 轻量(可裁剪)
开源 是(MIT)

最大的变化是 System.Web 消失了。ASP.NET Core 不再依赖 IIS 的 HttpModule/HttpHandler 架构,而是从零构建了一套全新的请求管道。这意味着大量 ASP.NET MVC 4/5 的代码不能直接迁移,需要重写。

2. 第一个 ASP.NET Core 1.0 应用

项目结构相比 MVC 5 简化了很多:

1
2
3
4
5
6
7
8
9
MyApp/
├── Controllers/
│ └── HomeController.cs
├── Views/
│ └── Home/Index.cshtml
├── wwwroot/ # 静态文件根目录(新增)
├── appsettings.json # 配置文件(替代 web.config)
├── Program.cs # 应用入口
└── Startup.cs # 应用配置(新)

Program.cs(应用入口,类似控制台程序):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel() // 内置跨平台 HTTP 服务器
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration() // Windows 下 IIS 反向代理支持
.UseStartup<Startup>()
.Build();

host.Run();
}
}

Startup.cs(服务注册 + 中间件配置):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class Startup
{
public IConfigurationRoot Configuration { get; }

public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();

Configuration = builder.Build();
}

// 服务注册(DI 容器)
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("Default")));
services.AddScoped<IUserService, UserService>();
}

// 中间件管道配置
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}

app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}

3. 内置依赖注入

这是 ASP.NET Core 最重要的改变之一:DI 是框架的一等公民,无需引入第三方容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 服务注册(三种生命周期)
services.AddTransient<IEmailService, SmtpEmailService>(); // 每次请求新实例
services.AddScoped<IOrderService, OrderService>(); // 每次 HTTP 请求共享一个实例
services.AddSingleton<ICacheService, RedisCacheService>(); // 全局单例

// 在 Controller 中通过构造函数注入
public class OrdersController : Controller
{
private readonly IOrderService _orderService;
private readonly ILogger<OrdersController> _logger;

public OrdersController(IOrderService orderService,
ILogger<OrdersController> logger)
{
_orderService = orderService;
_logger = logger;
}
}

与 MVC 5 需要手动集成 Autofac 相比,内置 DI 大大降低了项目的启动成本。

4. 配置系统

web.config 退场,新的配置系统支持多源合并:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// appsettings.json
{
"ConnectionStrings": {
"Default": "Server=localhost;Database=myapp;..."
},
"App": {
"MaxRetries": 3,
"Timeout": 30
}
}

// 在代码中读取
string connStr = Configuration.GetConnectionString("Default");
int maxRetries = Configuration.GetValue<int>("App:MaxRetries");

// 强类型配置(更推荐)
services.Configure<AppSettings>(Configuration.GetSection("App"));

// 在服务中注入
public class MyService
{
private readonly AppSettings _settings;
public MyService(IOptions<AppSettings> options)
{
_settings = options.Value;
}
}

5. 在 Linux 上运行

1
2
3
4
5
6
7
8
9
10
11
# 安装 .NET Core SDK(Ubuntu)
curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg
sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg
sudo apt-get install dotnet-dev-1.0.4

# 创建并运行项目
dotnet new mvc -o MyApp
cd MyApp
dotnet restore
dotnet run
# 监听 http://localhost:5000

第一次在 Linux 上跑起来 C# Web 应用,感觉还是挺震撼的。

个人感受

.NET Core 1.0 还很早期,有一些明显的不足:API 覆盖率不完整(很多 .NET Framework 的类库还没移植),工具链也不够成熟,项目格式是 project.json 而不是 .csproj(这个在后来的版本改回来了)。

但方向是对的。内置 DI、中间件管道、可自托管的 Kestrel——这套架构比老的 ASP.NET 干净多了。我当时的判断是:如果是全新项目,值得考虑 Core;老项目迁移代价太大,先观望。

现在回头看,这个判断基本正确:.NET Core 2.0 之后才真正成熟,那时候迁移才比较顺畅。

作者 · authorzt
发布 · date2016-09-14
篇幅 · length1.2k 字 · 3 min
许可 · licenseCC BY-SA 4.0
$ echo "comments" · 评论