ASP.NET Core 快速入門(實戰篇)

来源:http://www.cnblogs.com/zhaopei/archive/2017/08/14/netcore2.html
-Advertisement-
Play Games

上篇講了 "《asp.net core在linux上的環境部署》" 。今天我們將做幾個小玩意實戰一下。用到的技術和工具有mysql、websocket、AngleSharp(爬蟲html解析)、nginx多站點部署。 NO1 留言板(mysql的使用) 演示:http://haojima.net 這 ...


上篇講了《asp.net core在linux上的環境部署》。今天我們將做幾個小玩意實戰一下。用到的技術和工具有mysql、websocket、AngleSharp(爬蟲html解析)、nginx多站點部署。

NO1 留言板(mysql的使用)

演示:http://haojima.net
這個功能很簡單。就是對資料庫的寫入和展示。如果在Windows下,相信大家分分鐘都可以搞定。而初次接觸.net core + mysql可能需要註意些細節。
首先打開vs2017新建一個asp.net core項目(選Web應用程式),然後nuget 導入Microsoft.EntityFrameworkCore.Tools 1.1.1MySql.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);

    //下麵就可以添加要加入資料庫的實體了
    //public DbSet<Message> Messages { get; set; }
}

到此為止,我們已經可以利用EF Core直接連接mysql進行增刪改查操作了。註意:需要導入命名空間using Microsoft.EntityFrameworkCore; using MySQL.Data.EntityFrameworkCore.Extensions;

當然。你會說,連接字元串不能硬編碼到代碼裡面。我們也可以放配置文件。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));

【註意】項目名稱和路徑最好不要有中文,不然會出現些亂七八糟的問題。

【完整代碼】:https://github.com/zhaopeiym/BlogDemoCode/tree/master/MessageBoard

NO2 聊天室(WebSocket的使用)

演示:http://socket.haojima.net
WebSocket是Html5新增的一個很酷的技術。下麵我們簡單講解下這個很酷的技術

var Socket = new WebSocket(url);//創建 WebSocket 對象

創建了一個WebSocket對象後會觸發打開連接事件:

Socket.onopen = function(){  }

除了onopen事件,還有其他三個事件:

Socket.onmessage  //客戶端接收服務端數據時觸發
Socket.onerror    //通信發生錯誤時觸發
Socket.onclose    //連接關閉時觸發

另外還有兩個方法:

Socket.send()   //使用連接發送數據
Socket.close()  //關閉連接

最後還有四個連接狀態屬性:

Socket.readyState
0 - 表示連接尚未建立。
1 - 表示連接已建立,可以進行通信。
2 - 表示連接正在進行關閉。
3 - 表示連接已經關閉或者連接不能打開。

整個WebSocket常用功能知識點就四個事件、兩個方法、四種狀態。簡單吧,下麵我們看看asp.net core後臺的配合:

後臺添加一個SocketHandler類,並添加一個靜態方法Map:

/// <summary>
/// 請求
/// </summary>
/// <param name="app"></param>
public static void Map(IApplicationBuilder app)
{
    app.UseWebSockets(); //【註意】需要 nuget   導入 Microsoft.AspNetCore.WebSockets.Server
    app.Use(Acceptor);
}

然後新增對應的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);   //傳入我們剛纔新建的靜態方法Map

現在為止,基本的類和配置已經完成。
我們主要操作,是在Acceptor方法裡面接收和發送消息。

//建立連接
var socket = await httpContext.WebSockets.AcceptWebSocketAsync();
//等待接收數據
await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
//發送消息
await socket.SendAsync(arraySegment, WebSocketMessageType.Text, true, CancellationToken.None);

後臺關鍵代碼也就這三句,建立連接、等待接收、發送消息。
不過這裡有一點需要理解。建立連接後,可以接收任意多次客戶端消息。所以ReceiveAsync等待接收這裡需要死迴圈接收消息,直到連接斷開。(不用擔心真的死迴圈,沒有消息發送的時候,代碼會阻塞在那裡等待消息)

【完整實現】: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,發現很多類在.net core沒有實現)
最後還是到了一款支持.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;
}

看到沒有,就像jq一樣解析html。如果你說不爽我都不信。

【完整實現】:https://github.com/zhaopeiym/JobWanted

部署多個站點

以上,這些項目都比較簡單。關鍵技術點和難點都進行的分析。我相信大家都可以動起手練習起來了。
不過有個問題,前面我們只說了部署一個應用程式。如果是多個該怎麼部署呢?
首先我們把多個程式發佈包放到伺服器上。
然後修改nginx的配置文件/etc/nginx/conf.d/default.conf

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;
        
        proxy_set_header Upgrade $http_upgrade;   
    }
}

有幾個程式就添加幾個server,不過需要修改你解析到的功能變數名稱、程式路徑和內網對應的埠(看配置里的註釋) 。
然後修改supervisor的配置文件/etc/supervisor/conf.d/supervisord.conf

[program:MessageBoard]
command=dotnet MessageBoard.dll        ; 運行程式的命令
directory= /home/projects/messagBoard/ ; 命令執行的目錄
autorestart=true                    ; 程式意外退出是否自動重啟
stderr_logfile=/var/log/WebApplication1.err.log ; 錯誤日誌文件
stdout_logfile=/var/log/WebApplication1.out.log ; 輸出日誌文件
environment=ASPNETCORE_ENVIRONMENT=Production ; 進程環境變數
user=root ; 進程執行的用戶身份
stopsignal=INT

有幾個程式就往下複製幾份program。需要修改program名稱,只要名稱不重覆就可以。然後修改 運行程式的命令 對應的dll和命令執行的目錄(看配置文件的註釋)。
如此就可以部署多個程式了。

開始我還以為是在功能變數名稱解析的時候,解析IP + 埠。原來是多個功能變數名稱解析到同一個IP,然後nginx在內部做功能變數名稱和內網埠分發。

一些其它的細節

部署阿裡雲

我們在linux的防火牆開放了埠,發現在外面還是訪問不了(可以telnet IP 埠 來測試)。有可能是阿裡雲攔截了。https://help.aliyun.com/document_detail/25471.html 在安全組添加某埠哪些IP可以訪問。

mysql的客戶端

對於mysql,我們安裝好之後總不能每次命令操作吧。在Windows下麵有個客戶端Navicat可以方便管理mysql。Navicat

獲取ip

用了nginx後發現取不到瀏覽器IP了。那是因為我們程式都是瀏覽器訪問nginx,然後nginx轉發內網程式埠。所以取到的IP都是內網本機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直接運行發現沒有任何問題,可是部署在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";      # 新增 
    }
}

WebSocket心跳

經過上面的配置,我們的WebSocket在nginx上跑起來了。萬分歡喜的我們,發現一分鐘不發消息就自動掉線了。鬱悶至極到頭大。細心的同學通過上面的鏈接資料其實已經有說明:

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.

靠,英文實在太爛了。

預設情況下,如果代理的伺服器在60秒內沒有傳輸任何數據,則連接將被關閉。可以使用proxy_read_timeout指令增加此超時 。或者,代理伺服器可以配置為定期發送WebSocket ping幀以重置超時並檢查連接是否仍然存在。

nginx給出了兩種解決方案。第一種,修改proxy_read_timeout (預設60秒)。第二種,瀏覽器客戶端定時發送心跳包(時間要短於proxy_read_timeout)。
我使用的是第二種方式。
第一種雖然簡單粗暴,但是時間再長也是一個值,還是會有超時的可能。再者,誰能保證瀏覽器端不會new 很多個WebSocket出來搗蛋。
第二種方式,瀏覽器定時發送一條消息,內容和後臺約定下。如發送“心跳”,然後後臺接收消息是,判斷如果是“心跳”則不做任何處理。

中文編碼

在做“找工作”爬前程無憂的數據時,發現他們使用的GBK編碼。而在.net core中預設不支持這種格式,導致取到的數據都是亂碼。我們需要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 預設埠都是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();
}

爬拉勾數據

在爬拉勾網的時候沒有搞定,不知道是不是因為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 中抓到的數據是“頁面載入中...”。和瀏覽器訪問的結果不一樣。
原因未知。如果有大佬解惑,感激不盡!

 

參考
http://www.runoob.com/html/html5-websocket.html
http://www.cnblogs.com/liguobao/p/6130121.html
http://www.cnblogs.com/linezero/p/5806814.html
演示
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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 下載鏈接:http://pan.baidu.com/s/1o8C34xk ...
  • 2017 年 1 月 22 日,上海 ——微軟加速器上海首期啟航儀式在上海市儀電華鑫慧享城舉行,14 支創業團隊經過層層篩選從激烈競爭中脫穎而出,成為微軟加速器上海的首期加速項目。微軟加速器上海是微軟在中國開設的第二家、在全球開設的第八家加速器,旨在以頂尖、專業的創業服務,面向全球為創新創業團隊提供... ...
  • 又是一年年會時,正值各家公司紅人紛紛登場之際,Azure 自然也不會缺席。我們今年的主題是:Azure 杯年會 Cosplay,秀出你最愛的角色! ...
  • Azure 1 月新發佈:Microsoft Power BI Embedded 公共預覽和電腦視覺 API 標準版的更新以及 Azure IoT 網關 SDK 和中心設備管理新功能正式發佈以及關於計量名稱變更的通知 ...
  • 網關,物聯網網關 Azure 物聯網平臺可以按需運作,整合現有設備和服務,讓開發者利用自己熟悉的編程語言進行擴展,無縫整合企業部署的後端平臺。而隨著 Azure 物聯網網關 SDK(Software Development Kit)的進一步優化,用戶甚至可以將 Azure 數據中心外的物聯網和高級分... ...
  • CentOS 調教方法: ①刪除虛擬機但保留磁碟,隨後將系統盤作為數據盤掛載到臨時虛擬機上 ②修改配置文件 /etc/sysconfig/network-scripts/ifcfg-eth0 ③將虛擬網卡硬體地址改成正確的值,或刪除該行 ④保存並退出,分離該磁碟,並基於該磁碟新建虛擬機 SUSE... ...
  • Azure 12 月新發佈:導入/導出服務,虛擬機和雲服務的 Av2,虛擬網路對等互連現已正式發佈以及流分析的更新 ...
  • 共用訪問簽名是一種字元串,包含可附加到 URI 的安全令牌,可以讓我們委派對象的訪問許可權,並指定訪問的許可權和日期/時間範圍等限制。例如我們可以授予對 Blob、容器、隊列、文件和表的訪問許可權。很多服務在做驗證時都會用到 SAS,例如 Azure Service Bus、Azure IoT Hub 等... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...