Asp.Net Core 是開源,跨平臺,模塊化,快速而簡單的Web框架. "Asp.net Core官網的一個合集,方便一次性Clone" 目錄 "快速入門" "安裝" "一個最小的應用" "項目模板" "路由" "靜態文件" "頁面渲染" "請求" "錯誤和重定向" "關於響應" "會話" "日 ...
Asp.Net Core 是開源,跨平臺,模塊化,快速而簡單的Web框架.
Asp.net Core官網的一個合集,方便一次性Clone
目錄
持續更新,也可以通過我的網站訪問,歡迎探討交流
快速入門
安裝
查看dotnet sdk 版本
$ dotnet --version`
2.1.4
創建項目目錄
$ mkdir study
$ cd study
使用 dotnet new
命令創建項目
$ dotnet new console -n Demo
$ cd Demo
在 VS Code中打開Demo文件夾
一個最小的應用
打開 Program.cs
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseStartup<Startup>()
.Build();
host.Run();
}
}
class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Hello, World!");
});
}
}
}
安裝相關的Nuget包
$ dotnet add package Microsoft.AspNetCore.Hosting --version 2.0.1
$ dotnet add package Microsoft.AspNetCore.Server.Kestrel --version 2.0.1
下載依賴項
$ dotnet restore
運行
$ dotnet run
輸出結果:
Hosting environment: Production
Content root path: C:\netcore\study\Demo\bin\Debug\netcoreapp2.0\
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
項目模板
根據指定的模板,創建新的項目、配置文件或解決方案。
$ dotnet new -h
使用情況: new [選項]
選項:
-h, --help 顯示有關此命令的幫助。
-l, --list 列出包含指定名稱的模板。如果未指定名稱,請列出所有模板。
-n, --name 正在創建輸出的名稱。如果未指定任何名稱,將使用當前目錄的名 稱。
-o, --output 要放置生成的輸出的位置。
-i, --install 安裝源或模板包。
-u, --uninstall 卸載一個源或模板包。
--type 基於可用的類型篩選模板。預定義的值為 "project"、"item" 或 "other"。
--force 強制生成內容,即使該內容會更改現有文件。
-lang, --language 指定要創建的模板的語言。
模板 短名稱 語言 標記
-------------------------------------------------------------------------------- ------------------------
Console Application console [C#], F#, VB Common/Console
Class library classlib [C#], F#, VB Common/Library
Unit Test Project mstest [C#], F#, VB Test/MSTest
xUnit Test Project xunit [C#], F#, VB Test/xUnit
ASP.NET Core Empty web [C#], F# Web/Empty
ASP.NET Core Web App (Model-View-Controller) mvc [C#], F# Web/MVC
ASP.NET Core Web App razor [C#] Web/MVC/Razor Pages
ASP.NET Core with Angular angular [C#] Web/MVC/SPA
ASP.NET Core with React.js react [C#] Web/MVC/SPA
ASP.NET Core with React.js and Redux reactredux [C#] Web/MVC/SPA
ASP.NET Core Web API webapi [C#], F# Web/WebAPI
global.json file globaljson Config
NuGet Config nugetconfig Config
Web Config webconfig Config
Solution File sln Solution
Razor Page page Web/ASP.NET
MVC ViewImports viewimports Web/ASP.NET
MVC ViewStart viewstart Web/ASP.NET
Examples:
dotnet new mvc --auth Individual
dotnet new page --namespace
dotnet new --help
使用dotnet new
選擇 console 模板 創建項目
$ dotnet new console -n Demo
$ cd Demo
創建後的項目文檔結構是
.
├── Demo
│ ├── Demo.csproj
│ └── Program.cs
路由
啟用,配置路由
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
namespace Demo {
class Startup {
public void ConfigureServices (IServiceCollection services) {
//啟用路由
services.AddRouting ();
}
public void Configure (IApplicationBuilder app) {
//配置路由
app.UseRouter (routes => {
//根路由 (/)
routes.MapGet("", context =>
{
return context.Response.WriteAsync("Hello, World!");
});
//在根路由 (/) 上,配置 /hello Get請求的路由
routes.MapGet ("hello", context => {
return context.Response.WriteAsync ("Got a Get request at /hello");
});
});
}
}
}
安裝相關的Nuget包
$ dotnet add package Microsoft.AspNetCore.Routing --version 2.0.1
下載依賴項
$ dotnet restore
運行
$ dotnet run
訪問 http://localhost:5000/hello ,輸出結果:
Got a Get request at /hello
對 /user 路由的 POST 請求進行響應:
routes.MapPost("hello", context => {
return context.Response.WriteAsync ("Got a Post request at /hello");
})
對 /user 路由的 PUT 請求進行響應:
routes.MapPut("hello", context => {
return context.Response.WriteAsync ("Got a Put request at /hello");
})
對 /user 路由的 DELETE 請求進行響應:
routes.MapDelete("hello", context => {
return context.Response.WriteAsync ("Got a Dlete request at /hello");
})
靜態文件
啟用,配置靜態資源
創建 wwwroot文件夾
$ mkdir wwwroot
$ cd wwwroot
複製 index.html 到 wwwroot目錄
$ mkdir images
$ cd images
複製 favicon.png 到 images文件夾下
項目結構圖如下:
.
├── Demo
│ ├── wwwroot
│ │ ├── images
│ │ │ ├── favicon.png
│ │ ├── index.html
│ ├── Demo.csproj
│ └── Program.cs
更改 Program.cs,設置ContentRoot路徑為當前項目根目錄,啟用靜態資源
using System;
using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
namespace Demo {
class Program {
static void Main (string[] args) {
Console.WriteLine (AppContext.BaseDirectory);
var host = new WebHostBuilder ()
.UseKestrel ()
//設置 ContentRoot, ContentRoot是任何資源的根路徑,比如頁面和靜態資源
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build ();
host.Run ();
}
}
class Startup {
public void Configure (IApplicationBuilder app) {
//使用靜態資源,預設的目錄是 /wwwroot
app.UseStaticFiles ();
}
}
}
運行
http://localhost:5000/index.html
http://localhost:5000/images/favicon.png
配置其他文件夾
新建文件夾myfiles
$ mkdir myfiles
$ cd myfiles
創建一個新的 index.html到myfiles文件夾,配置並使用myfiles文件夾
app.UseStaticFiles (new StaticFileOptions {
FileProvider = new PhysicalFileProvider (
Path.Combine (Directory.GetCurrentDirectory (), "myfiles")),
RequestPath = "/myfiles"
});
運行
http://localhost:5000/myfiles/index.html
頁面渲染
Razor模板引擎
Asp.net Core自帶的模板引擎是 Razor模板引擎,傳統的Razor頁面以cshtml結尾, 閱讀Razor語法
遺憾的是Razor模板引擎在Asp.net Core中封裝在了MVC模塊之中,需要做一些擴展才可以單獨拿出來使用
創建模板頁面
創建 views文件夾
$ mkdir views
$ cd views
創建 index.cshtml 頁面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<ul>
@for (int i = 0; i < 5; i++)
{
<li>第@(i + 1)行</li>
}
</ul>
</body>
</html>
使用模板
using System;
using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(AppContext.BaseDirectory);
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();
host.Run();
}
}
class Startup
{
public void ConfigureServices(IServiceCollection services)
{
//啟用Mvc
services.AddMvc();
//擴展類
services.AddSingleton<RazorViewRenderer>();
}
public void Configure(IApplicationBuilder app)
{
app.UseRouter(routes =>
{
//根路徑 /
routes.MapGet("", context =>
{
return context.Render("/views/index.cshtml");
}
});
}
}
}
安裝相關的Nuget包
$ dotnet add package Microsoft.AspNetCore.Mvc --version 2.0.2
下載依賴項
$ dotnet restore
運行
$ dotnet run
結果
第1行
第2行
第3行
第4行
第5行
渲染數據
新增實體類 UserInfo
public class UserInfo
{
public string Name { get; set; }
public int Age { get; set; }
}
新增user.cshtml頁面
@using Demo;
@model UserInfo
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<ul>
<li>姓名:@Model.Name</li>
<li>年齡:@Model.Age</li>
</ul>
</body>
</html>
更改Program.cs
app.UseRouter(routes =>
{
//根路徑 /
routes.MapGet("", context =>
{
return context.Render("/views/index.cshtml");
}
routes.MapGet("/user", context =>
{
return context.Render("/views/user.cshtml", new UserInfo() { Name = "張三", Age = 18 });
});
});
運行
$ dotnet run
結果
姓名:張三
年齡:18
請求數據
QueryString
var queryCollection = context.Request.Query;
foreach (var item in queryCollection)
{
Console.WriteLine(item.Key + ":" + item.Value);
}
Form
if (context.Request.ContentType.ToLower().Contains("application/x-www-form-urlencoded")
{
var formCollection = context.Request.Form;
foreach (var item in formCollection)
{
Console.WriteLine(item.Key + ":" + item.Value);
}
}
Files
var fileCollections = context.Request.Form.Files;
var rootPath = context.RequestServices.GetService<IHostingEnvironment>().ContentRootPath;
foreach (var item in fileCollections)
{
var path = Path.Combine(rootPath,item.FileNa
using (var stream = new FileStream(path, FileMode.Create))
{
await item.CopyToAsync(stream);
}
Console.WriteLine(item.FileName + ":" + item.Length);
}
Header
var headerCollection = context.Request.Headers;
foreach (var item in headerCollection)
{
Console.WriteLine(item.Key + ":" + item.Value);
}
Body
StreamReader reader = new StreamReader(context.Request.Body);
string text = reader.ReadToEnd();
Cookies
var cookieCollection=context.Request.Cookies;
foreach (var item in cookieCollection)
{
Console.WriteLine(item.Key + ":" + item.Value);
}
錯誤和重定向
重定向
context.Response.Redirect("path")
狀態代碼頁
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.IO;
using System.Text.Encodings.Web;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(AppContext.BaseDirectory);
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();
host.Run();
}
}
class Startup
{
public void ConfigureServices(IServiceCollection services)
{
//啟用路由
services.AddRouting();
services.AddMvc();
services.AddSingleton<RazorViewRenderer>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//啟用狀態碼頁
app.UseStatusCodePages();
app.UseRouter(routes =>
{
//根路徑 /
routes.MapGet("", context =>
{
return context.Render("/views/index.cshtml");
}
});
}
}
}
自定義狀態碼頁
新增 404.cshtml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<h1> Oops! Page Not Found ! </h1>
</body>
</html>
配置和使用自定義的狀態碼頁
app.UseStatusCodePagesWithRedirects("/status/{0}");
app.UseRouter(routes =>
{
//""
routes.MapGet("", context =>
{
return context.Response.WriteAsync("root path");
});
routes.MapGet("status/{code}", (request, response, routeData) =>
{
var statusCodePagesFeature = request.HttpContext.Features.Get<IStatusCodePagesFeature>();
var code = routeData.Values["code"];
if (statusCodePagesFeature != null && code!=null && code.ToString() == "404")
{
//跳轉到自定義的404頁面
return request.HttpContext.Render("/views/404.cshtml");
}
else
{
return response.WriteAsync(HtmlEncoder.Default.Encode("狀態碼:"+ routeData.Values["code"]));
}
});
});
異常錯誤頁
開發異常頁面,Asp.net Core自帶
app.UseDeveloperExceptionPage();
新增測試路由,拋出空指針異常
env.EnvironmentName = EnvironmentName.Development;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/error");
}
app.UseRouter(routes =>
{
//""
routes.MapGet("", context =>
{
return context.Response.WriteAsync("root path");
}
//test
routes.MapGet("test", context =>
{
throw new Exception("空指針異常!!!");
});
});
訪問http://localhost:57393/test,得到下麵的頁面
自定義異常頁面
env.EnvironmentName = EnvironmentName.Production;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
//自定義異常錯誤頁面
app.UseExceptionHandler("/error");
}
app.UseRouter(routes =>
{
//""
routes.MapGet("", context =>
{
return context.Response.WriteAsync("root path");
}
//test
routes.MapGet("test", context =>
{
throw new Exception("空指針異常!!!");
});
//自定義異常錯誤頁面
routes.MapGet("error", context =>
{
context.Response.StatusCode = 500;
context.Response.ContentType = "text/html";
var error = context.Features.Get<IExceptionHandlerFeature>();
if (error != null)
{
return context.Response.WriteAsync("<h1>" + HtmlEncoder.Default.Encode("發生了錯誤: " + error.Error.Messa + "</h1>");
}
else
{
return context.Response.WriteAsync("<h1>" + HtmlEncoder.Default.Encode("Oops! 發生了錯誤,請聯繫管理員")"</h1>");
}
});
});
關於響應
會話
Session
新增登陸頁面login.cshtml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<form action="/login" method="post">
<div>
<label>用戶名:</label>
<input type="text" name="UserName" />
</div>
<div>
<label>密碼:</label>
<input type="password" name="PassWord" />
</div>
<div>
<input type="submit" value="登陸" />
</div>
</form>
</body>
</html>
添加並啟用Session,輸入用戶名和密碼,點擊登陸,保持Session數據,登陸成功跳轉到/home路由頁面,訪問Session數據,顯示當前登陸的用戶名
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.IO;
using System.Threading.Tasks;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(AppContext.BaseDirectory);
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();
host.Run();
}
}
class Startup
{
public void ConfigureServices(IServiceCollection services)
{
//啟用路由
services.AddRouting();
services.AddMvc();
services.AddSingleton<RazorViewRenderer>();
//增加Session
services.AddSession();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseDeveloperExceptionPage();
// 啟用Session
app.UseSession();
app.UseRouter(routes =>
{
routes.MapGet("", (request, response, routeData) =>
{
return request.HttpContext.Render("/views/login.cshtml");
});
routes.MapGet("home", context =>
{
string userName = context.Session.GetString("userName");
if (!string.IsNullOrEmpty(userName))
{
return context.Response.WriteAsync("User:" + userName);
}
else
{
context.Response.Redirect("/");
return Task.CompletedTask;
}
});
routes.MapPost("login", context =>
{
var userName = context.Request.Form["UserName"].ToString();
var password = context.Request.Form["PassWord"].ToString();
if (userName.Equals("admin") && password.Equals("123456"))
{
context.Session.SetString("userName", password);
context.Response.Redirect("/home");
return Task.CompletedTask;
}
else
{
throw new Exception("用戶名或密碼錯誤");
}
});
});
}
}
}
日誌
安裝Nuget包
$ dotnet add package Microsoft.Extensions.Logging --version 2.0.0
$ dotnet add package Microsoft.Extensions.Logging.Console --version 2.0.0
下載依賴項
$ dotnet restore
添加日誌模塊
//啟用日誌
services.AddLogging(builder=> {
//使用控制台日誌提供程式
builder.AddConsole();
});
創建ILogger實例
var logger = context.RequestServices.GetService<ILogger<Startup>> ();
//記錄日誌
logger.LogInformation("before hello world");
日誌分類
日誌的類別,可以是任意字元串,預設是完全限定的類名,例如: Demo.Startup
日誌級別
logger.LogTrace();
logger.LogDebug();
logger.LogInformation();
logger.LogWarning();
logger.LogError();
logger.LogCritical();
日誌過濾
給日誌分類為 Demo.Startup的日誌類別限定最小的日誌級別是LogLevel.Information
services.AddLogging(builder=> {
builder.AddFilter("Demo.Startup", LogLevel.Information);
builder.AddConsole();
});
訪問更多關於日誌類別,級別,模板,過濾,作用域的說明日誌類別
配置
- 添加配置
```c#
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
var configBuilder = new ConfigurationBuilder();
configBuilder.AddInMemoryCollection(new Dictionary
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseConfiguration(config)
.UseStartup<Startup>()
.Build();
host.Run();
}
}
}
-- 讀取配置
c#
app.UseRouter(routes =>
{
routes.MapGet("", context =>
{
var config = context.RequestServices.GetService
## 國際化
-- 添加依賴的Nuget包
$ dotnet add package Microsoft.Extensions.Localization --version 2.0.1
下載依賴項
$ dotnet restore
```
資源文件命名規則
命名規則 {分類名稱}.{語言區功能變數名稱稱}.resx
- 分類名稱:預設的分類名稱就是類型的FullName,在AssemblyName後的相對路徑,比如Demo.Startup,程式集的名稱Demo,就剩下了Startup
- 語言區功能變數名稱稱: 語言區功能變數名稱稱有zh-CN,en-US,更多
特殊條件下你也可以將資源文件和類定義文件放在同一個目錄,這樣資源文件的分類名稱就是{類名稱}.{語言區功能變數名稱稱}.resx
添加資源文件
- 新建 myresources文件夾
- 新建 Startup.en-US.resx 新增項 name是sayhi,value是 HelloWorld
新建 Startup.zh-CN.resx 新增項 name是sayhi,value是 世界你好
添加本地化
services.AddLocalization(options => options.ResourcesPath = "myresources"; });
啟用本地化
var cultureList = new List<CultureInfo>() { new CultureInfo("en-US"), new CultureInfo("zh-CN") }; var options = new RequestLocalizationOptions() { SupportedCultures = cultureList, SupportedUICultures = cultureList, DefaultRequestCulture = new RequestCulture("zh-CN") }; //新建基於Query String的多語言提供程式 var provider = new QueryStringRequestCultureProvider(); provider.QueryStringKey = "culture"; provider.UIQueryStringKey = "uiculture"; //刪除所有多語言提供程式 options.RequestCultureProviders.Clear(); options.RequestCultureProviders.Add(provider);
資源文件讀取
var stringLocalizer = context.RequestServices.GetService<IStringLocalizer<Startup>>(); string sayhi = stringLocalizer["sayhi"];
訪問 http://localhost:57393/?culture=en-US 切換為英文版本,預設的語言是中文
多語言提供程式
- 通過Query String,[預設自帶]
- 通過Cookie,[預設自帶]
- 通過Accept-Language header,[預設自帶]
通過RouteData
模板格式化
string username="張三"; string localizedString = _localizer["Hello {0}!", username];