ASP.NET Core 是一个新的开源和跨平台的框架,用于构建如 Web 应用、物联网(IoT)应用和移动后端应用等连接到互联网的基于云的现代应用程序。ASP.NET Core 应用可运行于 .NET Core 和完整的 .NET Framework 之上。 构建它的目的是为那些部署在云端或者内部运行(on-premises)的应用提供一个优化的开发框架。它由最小开销的模块化的组件构成,因此在构建你的解决方案的同时可以保持灵活性。你可以在 Windows、Mac 和 Linux 上跨平台的开发和运行你的 ASP.NET Core 应用。 ASP.NET Core 开源在 GitHub 上。
C#新特性
这里记录下在C#6.0和C#7.0下常用的一些新特性
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static System.Math;//静态导入 static 类
namespace Ruanmou.Core.ConsoleProject
{
/// <summary>
/// C#6 新语法
/// </summary>
public class SharpSix
{
#region 自动属性初始化(Auto-property initializers)
public string Name { get; set; } = "summit";
public int Age { get; set; } = 22;
public DateTime BirthDay { get; set; } = DateTime.Now.AddYears(-20);
public IList<int> AgeList
{
get;
set;
} = new List<int> { 10, 20, 30, 40, 50 };
#endregion
public void Show(People peopleTest)
{
#region 字符串嵌入值(String interpolation)
Console.WriteLine($"年龄:{this.Age} 生日:{this.BirthDay.ToString("yyyy-MM-dd")}");
Console.WriteLine($"年龄:{{{this.Age}}} 生日:{{{this.BirthDay.ToString("yyyy -MM-dd")}}}");
Console.WriteLine($"{(this.Age <= 22 ? "小鲜肉" : "老鲜肉")}");
#endregion
#region 导入静态类(Using Static)
Console.WriteLine($"之前的使用方式: {Math.Pow(4, 2)}");
Console.WriteLine($"导入后可直接使用方法: {Pow(4, 2)}");
#endregion
#region 空值运算符(Null-conditional operators)
int? iValue = 10;
Console.WriteLine(iValue?.ToString());//不需要判断是否为空
string name = null;
Console.WriteLine(name?.ToString());
#endregion
#region 对象初始化器(Index Initializers)
IDictionary<int, string> dictOld = new Dictionary<int, string>()
{
{ 1,"first"},
{ 2,"second"}
};
IDictionary<int, string> dictNew = new Dictionary<int, string>()
{
[4] = "first",
[5] = "second"
};
#endregion
#region nameof表达式 (nameof expressions)
Console.WriteLine(nameof(peopleTest)); //获取peopleTest这个字符串
#endregion
}
#region 在属性/方法里使用Lambda表达式(Expression bodies on property-like function members)
public string NameFormat => string.Format("姓名: {0}", "summit");
public void Print() => Console.WriteLine(Name);
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace Ruanmou.Core.ConsoleProject
{
/// <summary>
/// c#7新语法
/// </summary>
public class SharpSeven
{
public void Show()
{
#region out参数
{
this.DoNoting(out int x, out int y);
Console.WriteLine(x + y);
this.DoNoting(out var l, out var m);
}
//Console.WriteLine(x + y);
#endregion
#region 模式
this.PrintStars(null);
this.PrintStars(3);
this.Switch(null);
this.Switch("ElevenEleven");
this.Switch("Eleven");
#endregion
#region 元组
{
var result = this.LookupName(1);
Console.WriteLine(result.Item1);
Console.WriteLine(result.Item2);
Console.WriteLine(result.Item3);
}
#endregion
#region 局部函数
{
Add(3);
int Add(int k)//闭合范围内的参数和局部变量在局部函数的内部是可用的,就如同它们在 lambda 表达式中一样。
{
return 3 + k;
}
}
#endregion
#region 数字分隔号
long big = 100_000;
#endregion
}
/// <summary>
/// System.ValueTuple 需要安装这个nuget包
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
private (string, string, string) LookupName(long id) // tuple return type
{
return ("first", "middle", "last");
}
/// <summary>
/// 具有模式的 IS 表达式
/// </summary>
/// <param name="o"></param>
public void PrintStars(object o)
{
if (o is null) return; // 常量模式 "null"
if (!(o is int i)) return; // 类型模式 定义了一个变量 "int i"
Console.WriteLine(new string(‘*‘, i));
}
/// <summary>
/// 可以设定任何类型的 Switch 语句(不只是原始类型)
/// 模式可以用在 case 语句中
/// Case 语句可以有特殊的条件
/// </summary>
/// <param name="text"></param>
private void Switch(string text)
{
int k = 100;
switch (text)
{
case "ElevenEleven" when k > 10:
Console.WriteLine("ElevenEleven");
break;
case "Eleven" when text.Length < 10:
Console.WriteLine("ElevenEleven");
break;
case string s when s.Length > 7://模式
Console.WriteLine(s);
break;
default:
Console.WriteLine("default");
break;
case null:
Console.WriteLine("null");
break;
}
}
private void DoNoting(out int x, out int y)
{
x = 1;
y = 2;
}
}
}
应用程序剖析
一个 ASP.NET Core 应用其实就是一个在其 Main 方法中创建一个 web 服务器的简单控制台应用程序:
using System;
using Microsoft.AspNetCore.Hosting;
namespace aspnetcoreapp
{
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseStartup<Startup>()
.Build();
host.Run();
}
}
}
Main 调用遵循 builder 模式的 WebHostBuilder ,用于创建一个 web 应用程序宿主。这个 builder 有些用于定义 web 服务器 (如 UseKestrel)和 startup 类型( UseStartup)的方法。在上面的示例中,web 服务器 Kestrel 被启用,但是你也可以指定其它 web 服务器。
WebHostBuilder 提供了一些可选方法,其中包括寄宿在 IIS 和 IIS Express 中的 UseIISIntegration 和用于指定根内容目录的 UseContentRoot。Build 和 Run 方法构建了用于宿主应用程序的 IWebHost 然后启动它来监听传入的 HTTP 请求。
Startup
WebHostBuilder 的 UseStartup 方法为你的应用指定了 Startup 类。
Startup 类是用来定义请求处理管道和配置应用需要的服务。 Startup 类必须是公开的(public)并且包含如下方法:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
}
public void Configure(IApplicationBuilder app)
{
}
}
ConfigureServices 定义你的应用所使用的服务(例如 ASP.NET MVC Core framework、Entity Framework Core、Identity 等等)
Configure 定义你的请求管道中的 中间件(middleware)
服务(Services)
服务是应用中用于通用调用的组件。服务通过依赖注入获取并使用。 ASP.NET Core 内置了一个简单的控制反转(IoC) 容器,它默认支持构造器注入,并且可以方便的替换成你自己选用的 IoC 容器。由于它的松耦合特性,依赖注入(DI) 使服务在整个应用中都可以使用。例如,Logging 在你整个应用中都可用。查看 Dependency Injection 获取更多信息。
中间件(Middleware)
在 ASP.NET Core 中,你可以使用 Middleware 构建你的请求处理管道。 ASP.NET Core 中间件为一个 HttpContext 执行异步逻辑,然后按顺序调用下一个中间件或者直接终止请求。一般来说你要使用一个中间件,只需要在 Configure 方法里调用 IApplicationBuilder 上一个对应的 UseXYZ 扩展方法。
ASP.NET Core 带来了丰富的内置中间件:
- 静态文件(Static files)
- 路由(Routing)
- 身份验证(Authentication)
你也可以创建你自己的自定义中间件。
你也可以在 ASP.NET Core 中使用任何基于 OWIN 的中间件。
服务器(Servers)
ASP.NET Core 托管模式并不直接监听请求;而是依赖于一个 HTTP server 实现来转发请求到应用程序。这个被转发的请求会以一组 feature 接口的形式被包装,然后被应用程序组合到一个 HttpContext中去。 ASP.NET Core 包含了一个托管的跨平台 web 服务器,被称为 Kestrel,它往往会被运行在一个如 IIS 或者 nginx 的生产 web 服务器之后。
内容根目录(Content root)
内容根目录是应用程序所用到的所有内容的根路径,例如它的 views 和 web 内容。内容根目录默认与宿主应用的可执行程序的应用根目录相同;一个替代的地址可以通过 WebHostBuilder 来设置。
Web根目录(Web root)
你的应用的Web根目录(Web root)是你项目中所有公共的、静态的资源,如 css、js 和 图片文件的目录。静态文件中间件将默认只发布 Web 根目录(Web root)和其子目录中的文件。 Web 根目录(Web root)默认为 /wwwroot,但是你也可以通过 WebHostBuilder 来指定另外一个地址。
配置(Configuration)
ASP.NET Core 使用了一个新的配置模型用于处理简单的键值对。新的配置模型并非基于System.Configuration 或者 web.config ;而是从一个有序的配置提供者集合拉取数据。内置的配置提供者支持多种不同的文件格式如(XML,JSON, INI)和用于支持基于环境的配置环境变量。
默认的MVC项目是通过 Asp.net Core 预制的"空"模板创建的,项目中已经有一个 appsettings.json 的文件了。 我们可以对文件补充键值对,在StartUp类,Configure方法中就可以直接读取配置。
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory factory)
{
#region 配置文件的读取
//xml path
Console.WriteLine($"option1 = {this.Configuration["Option1"]}");
Console.WriteLine($"option2 = {this.Configuration["option2"]}");
Console.WriteLine(
$"suboption1 = {this.Configuration["subsection:suboption1"]}");
Console.WriteLine("Wizards:");
Console.Write($"{this.Configuration["wizards:0:Name"]}, ");
Console.WriteLine($"age {this.Configuration["wizards:0:Age"]}");
Console.Write($"{this.Configuration["wizards:1:Name"]}, ");
Console.WriteLine($"age {this.Configuration["wizards:1:Age"]}");
#endregion
}
依赖注入
在.NET Core中DI的核心分为两个组件:IServiceCollection和 IServiceProvider。
IServiceCollection 负责注册;IServiceProvider 负责提供实例。通过默认的 ServiceCollection(在Microsoft.Extensions.DependencyInjection命名空间下)有三个方法:
var serviceCollection = new ServiceCollection()
.AddTransient<ILoginService, EFLoginService>()
.AddSingleton<ILoginService, EFLoginService>()
.AddScoped<ILoginService, EFLoginService>();
对应的实例生命周其包括三种:
Transient: 每一次GetService都会创建一个新的实例
Scoped: 在同一个Scope内只初始化一个实例 ,可以理解为( 每一个request级别只创建一个实例,同一个http request会在一个 scope内)
Singleton :整个应用程序生命周期以内只创建一个实例
ASP.NET Core可以在Startup.cs的 ConfigureService中配置DI,大家看到 IServiceCollection这个参数应该就比较熟悉了。
Controller中使用时,一般可以通过构造函数或者属性来实现注入,但是官方推荐是通过构造函数。这也是所谓的显式依赖。
private ILoginService<ApplicationUser> _loginService;
public AccountController(
ILoginService<ApplicationUser> loginService)
{
_loginService = loginService;
}
参考:
ASP.NET Core 介绍
解读ASP.NET 5 & MVC6系列(7):依赖注入
全面理解 ASP.NET Core 依赖注入