ASP.NET Core Quick Start Practical Articles

Time:2022-9-18

NO1 message board (mysql use)

Demo: http://haojima.net
This function is simple. It is to write and display to the database. If under Windows, I believe everyone can get it in minutes. And the first contact with .net core + mysql may need to pay attention to some details.

First open vs2017 to create a new asp.net core project (select Web application), and then nuget import Microsoft.EntityFrameworkCore.Tools 1.1.1 and MySql.Data.EntityFrameworkCore 8.0.8-dmr.
Then create a new DbContext class.

public class DataContext : DbContext
{
    //[Note] The connection string must add 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);

    // Now you can add the entity to be added to the database
    //public DbSet<Message> Messages { get; set; }
}

So far, we can use EF Core to directly connect to mysql for addition, deletion, modification and query operations. Note: Need to import namespace using Microsoft.EntityFrameworkCore; using MySQL.Data.EntityFrameworkCore.Extensions;

certainly. You will say that connection strings cannot be hardcoded into the code. We can also put configuration files. appsettings.json


{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "ConnectionStrings": { "SqlServerConnection": "Data Source=;Database=;User ID=;Password=;pooling=true;CharSet=utf8;port=3306;sslmode=none" }
}

Then comment out the hardcoded above. Add in the ConfigureServices method of the Startup.cs file


var connection = Configuration.GetConnectionString("SqlServerConnection");
services.AddDbContext<DataContext>(options => options.UseMySQL(connection));

[Note] It is best not to have Chinese in the project name and path, otherwise there will be some messy problems.

[Complete code]: https://github.com/zhaopeiym/BlogDemoCode/tree/master/MessageBoard

NO2 chat room (use of WebSocket)

Demo: http://socket.haojima.net

WebSocket is a cool new technology added to Html5. Here we briefly explain this cool technology

var Socket = new WebSocket(url);//Create a WebSocket object

After a WebSocket object is created, the open connection event is fired:


Socket.onopen = function(){  }

Besides the onopen event, there are three other events:

Socket.onmessage //Triggered when the client receives data from the server
Socket.onerror //Triggered when a communication error occurs
Socket.onclose //Triggered when the connection is closed

There are two other methods:

Socket.send() //Use the connection to send data
Socket.close() //Close the connection

Finally there are four connection state properties:

Socket.readyState
0 - Indicates that the connection has not been established.
1 - Indicates that the connection is established and can communicate.
2 - Indicates that the connection is being closed.
3 - Indicates that the connection is closed or the connection cannot be opened.

The knowledge points of the common functions of the entire WebSocket are four events, two methods, and four states. Simple, let's take a look at the cooperation of the asp.net core background:

Add a SocketHandler class in the background and add a static method Map:

/// <summary>
/// ask
/// </summary>
/// <param name="app"></param>
public static void Map(IApplicationBuilder app)
{
    app.UseWebSockets(); //[Note] nuget is required to import Microsoft.AspNetCore.WebSockets.Server
    app.Use(Acceptor);
}

Then add the corresponding Acceptor method:

/// <summary>
/// Receive request
/// </summary>
/// <param name="httpContext"></param>
/// <param name="n"></param>
/// <returns></returns>
static async Task Acceptor(HttpContext httpContext, Func<Task> n)
{

It needs to be added to the Configure method in the Startup.cs class

app.Map(&quot;/ws&quot;, SocketHandler.Map); //Pass in the static method Map we just created

So far, the basic classes and configuration have been completed.

Our main operation is to receive and send messages in the Acceptor method.

//establish connection
var socket = await httpContext.WebSockets.AcceptWebSocketAsync();
//waiting to receive data
await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
//Send a message
await socket.SendAsync(arraySegment, WebSocketMessageType.Text, true, CancellationToken.None);

The key code in the background is these three sentences, establishing a connection, waiting to receive, and sending a message.
But there is one thing to understand here. After the connection is established, any number of client messages can be received. So ReceiveAsync waits to receive the message, which needs to be received in an infinite loop until the connection is disconnected. (Don't worry about a really infinite loop, when no message is sent, the code will block there waiting for a message)

[Complete implementation]: https://github.com/zhaopeiym/ChatRoom

NO3 looking for a job (using AngleSharp)

Demo: http://job.haojima.net
For crawler capture, I believe that everyone is very keen on it for the first time. I am no exception.
So is there such a plugin under asp.net core? The answer is yes.
http://www.cnblogs.com/linezero/p/5599611.html HtmlAgilityPack HTML parsing (thanks to bloggers for their contributions to .net core). But xpath is super disgusting to use.
There was a Jumony http://www.cnblogs.com/Ivony/p/3447536.html under .net (written by the blogger). Supports CSS selection and linq queries. Just don't be too cool. But does not support .net core. (I tried to migrate .net core and found that many classes are not implemented in .net core)
Finally, there is a parsing component that supports .net core. And comparable to Jumony, it also supports css selection and linq query. That is AngleSharp.
Create a new project, nuget installs AngleSharp. Then simply use the following:


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;
}

See no, parse html like jq. I don't believe it if you say it's unhappy.

[Complete implementation]: https://github.com/zhaopeiym/JobWanted

Deploy multiple sites

Above, these items are relatively simple. Analysis of key technical points and difficulties. I believe that everyone can start practicing.
But there is a problem. Earlier we only talked about deploying an application. How to deploy if there are multiple?
First we put multiple program distribution packages on the server.
Then modify the nginx configuration file /etc/nginx/conf.d/default.conf

server {
    listen 80;
    server_name www.haojima.net; #Corresponding domain name
    root /home/projects/messagBoard; #Program path
    location / {
        proxy_pass http://localhost:5000; #Intranet port
        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;   
    }
}

There are several programs to add several servers, but you need to modify the domain name, program path and the port corresponding to the intranet that you resolve to (see the notes in the configuration).
Then modify the supervisor's configuration file /etc/supervisor/conf.d/supervisord.conf

[program:MessageBoard]
command=dotnet MessageBoard.dll ; command to run the program
directory= /home/projects/messagBoard/ ; the directory where the command is executed
autorestart=true ; Whether the program will automatically restart if the program exits unexpectedly
stderr_logfile=/var/log/WebApplication1.err.log ; error log file
stdout_logfile=/var/log/WebApplication1.out.log ; output log file
environment=ASPNETCORE_ENVIRONMENT=Production ; Process environment variables
user=root ; the user identity of the process execution
stopsignal=INT

There are several programs to copy down a few programs. The program name needs to be modified, as long as the name is not repeated. Then modify the dll corresponding to the command to run the program and the directory where the command is executed (see the notes on the configuration file).
This allows multiple programs to be deployed.

At first I thought it was when the domain name was resolved, the IP + port was resolved. It turns out that multiple domain names resolve to the same IP, and then nginx distributes domain names and intranet ports internally.

some other details

Deploy Alibaba Cloud

We opened the port in the firewall of linux, and found that it was still not accessible outside (Can telnet IP port to test). It is possible that Alibaba Cloud blocked it. https://help.aliyun.com/document_detail/25471.html Add a port to the security group and which IPs can be accessed.

mysql client

For mysql, after we install it, we can't always command it every time. There is a client Navicat under Windows that can easily manage mysql.Navicat

get ip

After using nginx, I found that the browser IP could not be obtained. That's because our programs are all browsers accessing nginx, and then nginx forwards the intranet program port. Therefore, the IP obtained is the local IP of the intranet. If you need to get the browser IP, you need to configure it in 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; # new addition
    }
}

Then take the IP in the code:


var ip = HttpContext.Request.Headers["X-real-ip"].FirstOrDefault();

WebSocket configuration in nginx

The WebSocket we wrote above is found to run directly without any problems, but it cannot run when deployed in nginx. That's because nginx is required to support WebSocket, which requires configuration. 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 &quot;upgrade&quot;; # new 
        proxy_set_header Connection $http_connection; #ws and post use both https://github.com/aspnet/KestrelHttpServer/issues/1263
    }
}

WebSocket heartbeat

After the above configuration, our WebSocket is running on nginx. We are very happy, and found that if we don't send a message for one minute, we will be automatically disconnected. Depressed to the extreme. Careful students have already explained through the above link information:

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 gives two solutions. First, modify proxy_read_timeout (default 60 seconds). Second, the browser client periodically sends heartbeat packets (time shorter than proxy_read_timeout)。

I am using the second way.

The first one is simple and rude, but no matter how long the time is, it is still a value, and there is still a possibility of timeout. Furthermore, who can guarantee that the browser will not create a lot of new WebSockets to make trouble.

In the second method, the browser regularly sends a message, and the content is agreed with the background. For example, if a &quot;heartbeat&quot; is sent, and then the background receives a message, it is judged that if it is a &quot;heartbeat&quot;, nothing will be done.

Chinese code

While doing a &quot;job search&quot; to crawl the data of Worry-Free, I found out that they were using GBK encoding. In .net core, this format is not supported by default, resulting in garbled data. We need nuget to install System.Text.Encoding.CodePages. Then register it in Configure in Startup.cs:

Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);//Register encoding provider

use:


var htmlBytes = await http.GetByteArrayAsync(url);
var htmlString = Encoding.GetEncoding("GBK").GetString(htmlBytes);

asp.net core port assignment

The default port of asp.net core is 5000. Then when we run the second program, it will prompt that port 5000 is occupied. At this time, we need to assign a different port to each program.
Create a new json file hosting.json in the root directory


{
  "server.urls": "http://*:5002"
}

Modify in Program.cs file


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();
}

Crawling hook data

I didn't get it when I was crawling and pulling the hook. I don't know if it was because of https.


using (HttpClient http = new HttpClient())
{
    var url = "https://www.lagou.com/zhaopin/Java/?labelWords=label";
    var htmlString = await http.GetStringAsync(url);
}

Error in .net core: An unhandled exception occurred while processing the request.
The data captured in .net 4.5 is &quot;Page Loading…&quot;. It is not the same as the result of browser access.

170819 get it

https://github.com/zhaopeiym/JobWanted/blob/master/JobWanted/Controllers/JobsController.cs#L211

//The user-agent, X-Requested-With, and Referer are detected in the background of the pull hook network, and the list_ has parameters
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");

demo
http://haojima.net
http://socket.haojima.net
http://job.haojima.net

source code
https://github.com/zhaopeiym/JobWanted
https://github.com/zhaopeiym/ChatRoom
https://github.com/zhaopeiym/BlogDemoCode

The above is the detailed content of the actual combat of ASP.NET Core Quick Start. For more information about the actual combat of ASP.NET Core, please pay attention to other related articles on developpaer!