ASP.NET Core快速入门之实战篇

asp.net core快速入门之实战篇

 

no1 留言板(mysql的使用)

演示:http://haojima.net
这个功能很简单。就是对数据库的写入和展示。如果在windows下,相信大家分分钟都可以搞定。而初次接触.net core + mysql可能需要注意些细节。

首先打开vs2017新建一个asp.net core项目(选web应用程序),然后nuget 导入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);

  //下面就可以添加要加入数据库的实体了
  //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";      # 新增 
      proxy_set_header connection $http_connection;  #ws和post同时使用  https://github.com/aspnet/kestrelhttpserver/issues/1263
  }
}

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.

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 中抓到的数据是“页面加载中...”。和浏览器访问的结果不一样。

170819搞定

https://github.com/zhaopeiym/jobwanted/blob/master/jobwanted/controllers/jobscontroller.cs#l211

//拉勾网 后台检测了user-agent、x-requested-with、referer还会检测list_是否有参数
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快速入门之实战篇的详细内容,更多关于asp.net core实战的资料请关注硕编程其它相关文章!

下一节:.net core 集成 kafka的步骤

asp.net编程技术

相关文章