ASP.NET Core快速入門之實戰(zhàn)篇
NO1 留言板(mysql的使用)
演示:http://haojima.net
這個功能很簡單。就是對數(shù)據(jù)庫的寫入和展示。如果在Windows下,相信大家分分鐘都可以搞定。而初次接觸.net core + mysql可能需要注意些細(xì)節(jié)。
首先打開vs2017新建一個asp.net core項目(選Web應(yīng)用程序),然后nuget 導(dǎo)入Microsoft.EntityFrameworkCore.Tools 1.1.1和MySql.Data.EntityFrameworkCore 8.0.8-dmr。
然后新建一個DbContext類。
public class DataContext : DbContext
{
//【注意】連接字符串一定要加 sslmode=none
string str = @"Data Source=;Database=;User ID=;Password=;pooling=true;CharSet=utf8;port=3306;sslmode=none";
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
optionsBuilder.UseMySQL(str);
//下面就可以添加要加入數(shù)據(jù)庫的實體了
//public DbSet<Message> Messages { get; set; }
}
到此為止,我們已經(jīng)可以利用EF Core直接連接mysql進行增刪改查操作了。注意:需要導(dǎo)入命名空間using Microsoft.EntityFrameworkCore; using MySQL.Data.EntityFrameworkCore.Extensions;
當(dāng)然。你會說,連接字符串不能硬編碼到代碼里面。我們也可以放配置文件。appsettings.json
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
},
"ConnectionStrings": { "SqlServerConnection": "Data Source=;Database=;User ID=;Password=;pooling=true;CharSet=utf8;port=3306;sslmode=none" }
}
然后把上面的硬編碼注釋掉。在Startup.cs文件的ConfigureServices方法添加
var connection = Configuration.GetConnectionString("SqlServerConnection");
services.AddDbContext<DataContext>(options => options.UseMySQL(connection));
【注意】項目名稱和路徑最好不要有中文,不然會出現(xiàn)些亂七八糟的問題。
【完整代碼】:https://github.com/zhaopeiym/BlogDemoCode/tree/master/MessageBoard
NO2 聊天室(WebSocket的使用)
演示:http://socket.haojima.net
WebSocket是Html5新增的一個很酷的技術(shù)。下面我們簡單講解下這個很酷的技術(shù)
var Socket = new WebSocket(url);//創(chuàng)建 WebSocket 對象
創(chuàng)建了一個WebSocket對象后會觸發(fā)打開連接事件:
Socket.onopen = function(){ }
除了onopen事件,還有其他三個事件:
Socket.onmessage //客戶端接收服務(wù)端數(shù)據(jù)時觸發(fā) Socket.onerror //通信發(fā)生錯誤時觸發(fā) Socket.onclose //連接關(guān)閉時觸發(fā)
另外還有兩個方法:
Socket.send() //使用連接發(fā)送數(shù)據(jù) Socket.close() //關(guān)閉連接
最后還有四個連接狀態(tài)屬性:
Socket.readyState 0 - 表示連接尚未建立。 1 - 表示連接已建立,可以進行通信。 2 - 表示連接正在進行關(guān)閉。 3 - 表示連接已經(jīng)關(guān)閉或者連接不能打開。
整個WebSocket常用功能知識點就四個事件、兩個方法、四種狀態(tài)。簡單吧,下面我們看看asp.net core后臺的配合:
后臺添加一個SocketHandler類,并添加一個靜態(tài)方法Map:
/// <summary>
/// 請求
/// </summary>
/// <param name="app"></param>
public static void Map(IApplicationBuilder app)
{
app.UseWebSockets(); //【注意】需要 nuget 導(dǎo)入 Microsoft.AspNetCore.WebSockets.Server
app.Use(Acceptor);
}
然后新增對應(yīng)的Acceptor方法:
/// <summary>
/// 接收請求
/// </summary>
/// <param name="httpContext"></param>
/// <param name="n"></param>
/// <returns></returns>
static async Task Acceptor(HttpContext httpContext, Func<Task> n)
{
需要在Startup.cs類里面的Configure方法里面加入
app.Map("/ws", SocketHandler.Map); //傳入我們剛才新建的靜態(tài)方法Map
現(xiàn)在為止,基本的類和配置已經(jīng)完成。
我們主要操作,是在Acceptor方法里面接收和發(fā)送消息。
//建立連接 var socket = await httpContext.WebSockets.AcceptWebSocketAsync(); //等待接收數(shù)據(jù) await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); //發(fā)送消息 await socket.SendAsync(arraySegment, WebSocketMessageType.Text, true, CancellationToken.None);
后臺關(guān)鍵代碼也就這三句,建立連接、等待接收、發(fā)送消息。
不過這里有一點需要理解。建立連接后,可以接收任意多次客戶端消息。所以ReceiveAsync等待接收這里需要死循環(huán)接收消息,直到連接斷開。(不用擔(dān)心真的死循環(huán),沒有消息發(fā)送的時候,代碼會阻塞在那里等待消息)
【完整實現(xiàn)】:https://github.com/zhaopeiym/ChatRoom
NO3 找工作(AngleSharp的使用)
演示:http://job.haojima.net
對于爬蟲抓包,我相信大家初次接觸都非常的熱衷于此。我也不例外。
那么在asp.net core下面是否也有這樣的插件呢?答案是肯定的。
http://www.cnblogs.com/linezero/p/5599611.html HtmlAgilityPack HTML解析(感謝博主對.net core的貢獻)。不過xpath用起來超級惡心。
之前在.net下面有一款Jumony http://www.cnblogs.com/Ivony/p/3447536.html(博客園大牛寫的)。支持CSS選擇和linq查詢。簡直不要太爽??墒遣恢С?net core。(本人試了下遷移.net core,發(fā)現(xiàn)很多類在.net core沒有實現(xiàn))
最后還是到了一款支持.net core的解析組件。并可以媲美Jumony,同樣支持css選擇和linq查詢。那就是AngleSharp。
新建項目,nuget 安裝 AngleSharp。然后以下簡單使用:
using (HttpClient http = new HttpClient())
{
var htmlString = await http.GetStringAsync(url);
HtmlParser htmlParser = new HtmlParser();
var jobInfos = htmlParser.Parse(htmlString)
.QuerySelectorAll(".newlist_list_content table")
.Where(t => t.QuerySelectorAll(".zwmc a").FirstOrDefault() != null)
.Select(t => new JobInfo()
{
PositionName = t.QuerySelectorAll(".zwmc a").FirstOrDefault().TextContent,
CorporateName = t.QuerySelectorAll(".gsmc a").FirstOrDefault().TextContent,
Salary = t.QuerySelectorAll(".zwyx").FirstOrDefault().TextContent,
WorkingPlace = t.QuerySelectorAll(".gzdd").FirstOrDefault().TextContent,
.ToList();
return jobInfos;
}
看到?jīng)]有,就像jq一樣解析html。如果你說不爽我都不信。
【完整實現(xiàn)】:https://github.com/zhaopeiym/JobWanted
部署多個站點
以上,這些項目都比較簡單。關(guān)鍵技術(shù)點和難點都進行的分析。我相信大家都可以動起手練習(xí)起來了。
不過有個問題,前面我們只說了部署一個應(yīng)用程序。如果是多個該怎么部署呢?
首先我們把多個程序發(fā)布包放到服務(wù)器上。
然后修改nginx的配置文件/etc/nginx/conf.d/default.conf
server {
listen 80;
server_name www.haojima.net; #對應(yīng)的域名
root /home/projects/messagBoard; #程序路徑
location / {
proxy_pass http://localhost:5000; #內(nèi)網(wǎng)端口
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header Upgrade $http_upgrade;
}
}
有幾個程序就添加幾個server,不過需要修改你解析到的域名、程序路徑和內(nèi)網(wǎng)對應(yīng)的端口(看配置里的注釋) 。
然后修改supervisor的配置文件/etc/supervisor/conf.d/supervisord.conf
[program:MessageBoard] command=dotnet MessageBoard.dll ; 運行程序的命令 directory= /home/projects/messagBoard/ ; 命令執(zhí)行的目錄 autorestart=true ; 程序意外退出是否自動重啟 stderr_logfile=/var/log/WebApplication1.err.log ; 錯誤日志文件 stdout_logfile=/var/log/WebApplication1.out.log ; 輸出日志文件 environment=ASPNETCORE_ENVIRONMENT=Production ; 進程環(huán)境變量 user=root ; 進程執(zhí)行的用戶身份 stopsignal=INT
有幾個程序就往下復(fù)制幾份program。需要修改program名稱,只要名稱不重復(fù)就可以。然后修改 運行程序的命令 對應(yīng)的dll和命令執(zhí)行的目錄(看配置文件的注釋)。
如此就可以部署多個程序了。
開始我還以為是在域名解析的時候,解析IP + 端口。原來是多個域名解析到同一個IP,然后nginx在內(nèi)部做域名和內(nèi)網(wǎng)端口分發(fā)。
一些其它的細(xì)節(jié)
部署阿里云
我們在linux的防火墻開放了端口,發(fā)現(xiàn)在外面還是訪問不了(可以telnet IP 端口 來測試)。有可能是阿里云攔截了。https://help.aliyun.com/document_detail/25471.html 在安全組添加某端口哪些IP可以訪問。
mysql的客戶端
對于mysql,我們安裝好之后總不能每次命令操作吧。在Windows下面有個客戶端Navicat可以方便管理mysql。Navicat
獲取ip
用了nginx后發(fā)現(xiàn)取不到瀏覽器IP了。那是因為我們程序都是瀏覽器訪問nginx,然后nginx轉(zhuǎn)發(fā)內(nèi)網(wǎng)程序端口。所以取到的IP都是內(nèi)網(wǎng)本機IP。如果需要取瀏覽器IP需要在nginx配置
server {
listen 80;
server_name www.haojima.net;
root /home/projects/messagBoard;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-real-ip $remote_addr; # 新添加
}
}
然后代碼里面取IP:
var ip = HttpContext.Request.Headers["X-real-ip"].FirstOrDefault();
WebSocket在nginx的配置
上面我們寫的WebSocket直接運行發(fā)現(xiàn)沒有任何問題,可是部署在nginx去跑不起來了。那是因為需要nginx支持WebSocket,需要配置。http://nginx.org/en/docs/http/websocket.html
server {
listen 80;
server_name job.haojima.net;
root /home/projects/jobWanted;
location / {
proxy_pass http://localhost:5002;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header Upgrade $http_upgrade; # 新增
#proxy_set_header Connection "upgrade"; # 新增
proxy_set_header Connection $http_connection; #ws和post同時使用 https://github.com/aspnet/KestrelHttpServer/issues/1263
}
}
WebSocket心跳
經(jīng)過上面的配置,我們的WebSocket在nginx上跑起來了。萬分歡喜的我們,發(fā)現(xiàn)一分鐘不發(fā)消息就自動掉線了。郁悶至極到頭大。細(xì)心的同學(xué)通過上面的鏈接資料其實已經(jīng)有說明:
By default, the connection will be closed if the proxied server does not transmit any data within 60 seconds. This timeout can be increased with the proxy_read_timeout directive. Alternatively, the proxied server can be configured to periodically send WebSocket ping frames to reset the timeout and check if the connection is still alive.
nginx給出了兩種解決方案。第一種,修改proxy_read_timeout (默認(rèn)60秒)。第二種,瀏覽器客戶端定時發(fā)送心跳包(時間要短于proxy_read_timeout)。
我使用的是第二種方式。
第一種雖然簡單粗暴,但是時間再長也是一個值,還是會有超時的可能。再者,誰能保證瀏覽器端不會new 很多個WebSocket出來搗蛋。
第二種方式,瀏覽器定時發(fā)送一條消息,內(nèi)容和后臺約定下。如發(fā)送“心跳”,然后后臺接收消息是,判斷如果是“心跳”則不做任何處理。
中文編碼
在做“找工作”爬前程無憂的數(shù)據(jù)時,發(fā)現(xiàn)他們使用的GBK編碼。而在.net core中默認(rèn)不支持這種格式,導(dǎo)致取到的數(shù)據(jù)都是亂碼。我們需要nuget安裝System.Text.Encoding.CodePages。然后在Startup.cs的Configure里面注冊:
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);//注冊編碼提供程序
使用:
var htmlBytes = await http.GetByteArrayAsync(url);
var htmlString = Encoding.GetEncoding("GBK").GetString(htmlBytes);
asp.net core 端口分配
asp.net core 默認(rèn)端口都是5000。那么我們運行第二個程序的時候就會提示5000端口被占用。這個時候,我們就需要為每個程序分配不同的端口了。
在根目錄新建一個json文件hosting.json
{
"server.urls": "http://*:5002"
}
在Program.cs文件修改
public static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("hosting.json", optional: true)
.Build();
var host = new WebHostBuilder()
.UseKestrel()
.UseConfiguration(config)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.UseApplicationInsights()
.Build();
host.Run();
}
爬拉勾數(shù)據(jù)
在爬拉勾網(wǎng)的時候沒有搞定,不知道是不是因為https的原因。
using (HttpClient http = new HttpClient())
{
var url = "https://www.lagou.com/zhaopin/Java/?labelWords=label";
var htmlString = await http.GetStringAsync(url);
}
在.net core中報錯:An unhandled exception occurred while processing the request.
在.net 4.5 中抓到的數(shù)據(jù)是“頁面加載中...”。和瀏覽器訪問的結(jié)果不一樣。
170819搞定
https://github.com/zhaopeiym/JobWanted/blob/master/JobWanted/Controllers/JobsController.cs#L211
//拉勾網(wǎng) 后臺檢測了user-agent、X-Requested-With、Referer還會檢測list_是否有參數(shù)
http.DefaultRequestHeaders.Add("Referer", "https://www.lagou.com/jobs/list_.net");
http.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0");
http.DefaultRequestHeaders.Add("X-Requested-With", "XMLHttpRequest");
演示
http://haojima.net
http://socket.haojima.net
http://job.haojima.net
源碼
https://github.com/zhaopeiym/JobWanted
https://github.com/zhaopeiym/ChatRoom
https://github.com/zhaopeiym/BlogDemoCode
以上就是ASP.NET Core快速入門之實戰(zhàn)篇的詳細(xì)內(nèi)容,更多關(guān)于ASP.NET Core實戰(zhàn)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Asp.net TreeView來構(gòu)建用戶選擇輸入的方法 推薦
選擇優(yōu)于輸入,這是一般人的共識,面對繁多的數(shù)據(jù),提供良好的選擇界面,一方面增強用戶的界面體驗,一方面也提高了數(shù)據(jù)的準(zhǔn)確性,更節(jié)省了用戶的寶貴時間。2009-12-12
Visual Studio 2017中找回消失的“在瀏覽器中查看”命令
這篇文章主要為大家詳細(xì)介紹了如何在Visual Studio 2017中找回消失的“在瀏覽器中查看”命令,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-03-03
ASP.NET Core Api網(wǎng)關(guān)Ocelot的使用初探
這篇文章主要介紹了ASP.NET Core Api網(wǎng)關(guān)Ocelot的使用初探,幫助大家更好的理解和學(xué)習(xí)使用.NET技術(shù),感興趣的朋友可以了解下2021-03-03
asp.net core 屬性路由和約定路由的實現(xiàn)
ASP.NET Core中的WebAPI路由用于映射客戶端請求的URL到服務(wù)器端的控制器和操作方法,路由分為基于屬性的路由和約定路由兩種方式,本文就來介紹一下,感興趣的可以了解一下2025-01-01

