.NET Core nginx和rPi上的带有EF的Postgres(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/pi/net-core-nginx-and-postgres-with-ef-on-an-rpi-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 36 分钟阅读 - 17866 个词 阅读量 0.NET Core nginx和rPi上的带有EF的Postgres(译文)
原文地址:https://www.codeproject.com/Articles/1273615/NET-Core-nginx-and-Postgres-with-EF-on-an-rPi
原文作者:Marc Clifton
译文由本站 robot-v1.0 翻译
前言
Implementing an SSL capable server in .NET Core WITHOUT ASP.NET, using nginx, and testing Postgres with EF, all running on an rPi
使用nginx在不使用ASP.NET的.NET Core中实现支持SSL的服务器,并使用EF测试Postgres,所有这些都在rPi上运行
This article starts off with showing how to get started with rPi. We will look at PuTTY and WinSCP, followed by how to install PostgresSQL and DotNet Core. Then, we will see how to connect to Postgres with C# and .NET Core on the rPi. Next, we will take a look at a bare bones server, nginx and finally see how to run the server as a service.
本文首先展示了如何开始使用rPi.我们将研究PuTTY和WinSCP,然后介绍如何安装PostgresSQL和DotNet Core.然后,我们将看到如何在rPi上使用C#和.NET Core连接到Postgres.接下来,我们将看一看裸服务器nginx,最后看一下如何将服务器作为服务运行.
内容(Contents)
-
在rPi上使用C#和.NET Core连接到Postgres(Connecting to Postgres with C# and .NET Core on the rPi)
介绍(Introduction)
今年,我决定专注于物联网,主要是Raspberry PI(rPi)和Beaglebone单板计算机(SBC).我将其称为"个人物联网年".我的兴趣最初是带我去测试这些设备之一是否可以用作简单的Web服务器(是的,当然可以),但是具有足够的功能来支持SQL数据库和"真实的" Web应用程序.作为测试用例,我打算使用几年前为客户开发的网站,但是出于本文的目的,我只想审查各种技术.最终(不是本文的最后一天),我应该能够确定使用低成本的SBC作为满足低带宽需求的体面Web服务器的可行性.一路上,我可能还会玩一些硬件功能.(This year, I’ve decided to focus on IoT, mainly the Raspberry PI (rPi) and Beaglebone Single Board Computers (SBCs). I’ll call it my “personal year of IoT.” My interest is initially taking me down the path of testing out whether one of these devices can be used as a simple web server (yes, of course it can) but has enough horsepower to support a SQL database and a “real” web application. As a test case, I’m planning on using a website that I developed for a client a few years back, but for the purposes of this article, I just want to vet a variety of technologies. At the end of the day (not this article-day), I should be able to determine the viability of using a very low cost SBC as a decent web server for low-bandwidth needs. Along the way I may play with some of the hardware features as well.) 对于我的主要任务,我计划使用PostgresQL(我对MySQL有个人历史感)和用于Web服务器的DotNet Core.面临三个最初的挑战:(For my primary mission, I’m planning on using PostgresSQL (I have a personal historic distaste for MySQL) and DotNet Core for the web server. Three initial challenges present themselves:)
- 将SQL Server数据库导入Postgres(无法使用SQL Server的Docker映像需要2GB RAM,而rPi仅具有1GB RAM,更大的问题是它仅支持x64处理器,不支持ARM处理器.)存在一个实体框架Postgres的核心提供商(Importing a SQL Server database into Postgres (a Docker image of SQL Server is not viable is requires 2GB of RAM and the rPi only has 1GB RAM and the bigger issue is that it supports only x64 processors, not ARM processors.) There’s an Entity Framework Core provider for Postgres) 这里(here)
- 强制.NET Core使用我的服务器代码,因为我为客户端编写的网站不使用ASP.NET.(Coercing .NET Core into using my server code, as the website that I wrote for my client does not use ASP.NET.)
- 弄清SSL证书在带有.NET Core的Linux领域中如何工作.(Figuring out how SSL certificates work in the world of Linux with .NET Core.)
- 第3步涉及配置反向代理服务器,我将使用nginx进行演示.(Step 3 involves configuring a reverse proxy server, which I demonstrate using nginx.) 因此,将存在一些与SBC无关的挑战,而某些挑战肯定是相关的!(So there will be some challenges not related to SBCs, and some definitely related!)
rPi入门(Getting Started with the rPi)
第一步是组装(The first step is to assemble the) CanaKit(KanaKit) rPi并启动它.之后,我希望能够从USB驱动器启动操作系统,而不是使用micro SD卡.(rPi and get it fired up. After that, I want to be able to boot the OS from a USB drive rather than use the micro SD card.)
拆包,组装和加载操作系统(Unpacking, Assembling, and Loading an OS)
打开大盒子,我们在rPi本身,电源,HDMI电缆,SD卡,外壳和散热器中找到:(Opening the big box, we find inside the rPi itself, power supply, HDMI cable, SD card, case, and heat sinks:)
打开这些盒子的包装,我们到了真正的硬件!(Unpacking those boxes, we get to the actual hardware!)
在外壳中组装rPi花费了10到15分钟的时间(我拒绝观看视频!),结果证明您必须将rPI滑入适当的位置,以便SD卡插槽正确地定位在外壳中.外壳的检修孔.最后,它组装好了(包括散热器):(Assembling the rPi in the case took a good 10 or 15 minutes of struggling with the case (I refused to watch the video!) Turns out you have to sort of slide the rPI into position so that the SD card slot is properly positioned in the access hole for the case. Finally, it was assembled (including heat sinks):)
SD卡已随附(The SD card comes installed with) 新手(NOOBS) ,“全新的开箱即用软件”,可让您选择要安装的操作系统:(, “New Out Of the Box Software” which lets you choose the OS you wish to install:)
当我尝试安装推荐的Raspbian OS(第一个复选框)时,安装过程挂起(我确实等待了几分钟.)由于不安,我切断了电源并重新启动了rPi,后者很高兴地重新启动回NOOBS.选择第二个选项Raspbian Full,安装没有任何问题.大!(When I tried installing the recommended Raspbian OS (the first checkbox), the installation process hung (I did wait several minutes.) With trepidation, I pulled the power and restarted the rPi, which happily booted back into NOOBS. Selecting the second option, Raspbian Full, installed without any problems. Great!)
检查硬件和功能(Checking out the Hardware and Capabilities)
此版本的rPi的优点之一是内置的WiFi,它很容易配置.我从来没有能够在BeagleBone Black上使用WiFi,而且WiFi是我的一项要求,因为我希望能够在不局限于我有电缆连接的办公室的情况下进行此项目(我的办公室杂乱无章,与BeagleBone项目一起用于另一个客户.)(One of the nice things about this version of the rPi is the built in WiFi, which was very easy to configure. I’ve never been able to get WiFi working on the BeagleBone Black, and WiFi was a requirement as I want to be able to work on this project without being confined to my office where I have cable connectivity (my office is cluttered enough as it is with BeagleBone projects for another client.))
什么版本的rPi?(What Version rPi?)
KanaKit(至少据我所知)实际上没有告诉我我拥有的rPi版本,因此经过一番挖掘后,我发现(The KanaKit (at least as far as I could tell) did not actually tell me what version rPi I had, so after some digging, I found) 这个网站(this site) 列出了不同的版本.打开命令行窗口并输入:(that lists the different versions. Opening a command line window and typing:)
cat /proc/cpuinfo
我确定报告的"版本"是" a020d3",并在该站点(上面的链接)上进行了查找,并确认我具有rPi 3B +:(I determined that the “version” reported is “a020d3” and looking that up on the site (link above) I verified that I have an rPi 3B+:)
它支持从USB启动吗?(Does it Support Boot from USB?)
经过大量的Google搜索之后,我发现3A +和3B + rPi可以从USB引导,而无需进行任何配置更改.尽管配置更改看起来很简单,但我还是决定根据这些说明来验证rPi是否具有USB引导功能.事实证明,如果您输入:(After much Googling, I discovered that the 3A+ and 3B+ rPi’s can boot from USB without any configuration changes. While the configuration changes looked simple, I decided to verify, based on those instructions, that the rPi was USB boot capable. Turns out that if you type in:)
vcgencmd otp_dump | grep 17:
您会得到以下代码:(and you get back this code:) 0x3020000a
,这意味着已将OTP(一次性可编程)位编程为从USB引导.该位指示尝试从SD卡启动,如果不起作用,请扫描USB设备以获取启动代码.显然,鉴于这是"一次可编程的",您仍然可以更改为从SD卡启动(, it means that the OTP (One Time Programmable) bit has been programmed to boot from USB. This bit says to try and boot from the SD card and if that doesn’t work, scan the USB devices for bootcode. Apparently, given that this is “one time programmable”, you can still change to boot from the SD card with) 有点不安(a little finagling) .(.)
将操作系统映像到USB驱动器上(Imaging an OS onto a USB Drive)
下一步是将操作系统映像到USB驱动器上.我已经有一个2TB旋转硬盘(不是SSD!)驱动器,并且考虑到rPi不支持USB 3,至少在游戏的这个阶段,使用机械驱动器与SSD的性能差异似乎无关紧要- -此外,我没有任何未使用的SSD驱动器,我想随项目一起移动.(The next step was to image the OS onto a USB drive. I already had a 2TB spinny (not SSD!) drive lying around, and given that the rPi doesn’t support USB 3, the performance hit of using a mechanical drive vs. SSD seemed irrelevant, at least at this stage of the game – and besides, I didn’t have any unused SSD drives and I wanted to move along with the project.)
- 来自(From the) rPi下载网站(rPi download site) ,我选择了"带有桌面和推荐软件的Raspbian Stretch"并下载了它.(, I selected “Raspbian Stretch with desktop and recommended software” and downloaded it.)
- 来自(From the) 7Zip网站(7Zip site) ,我下载并安装了7Zip,并从第1步解压缩了文件,因此现在有了" 2018-11-13-raspbian-stretch-full.img"文件.(, I downloaded and installed 7Zip and unzipped the file from step 1 so I now had the “2018-11-13-raspbian-stretch-full.img” file.)
- 然后我下载并安装(I then downloaded and installed) 刻蚀者(Etcher) ,这是一个简单的三步过程,可以使用(, which is a simple three step process for imaging the drive with the)**.img(.img)**文件.(file.)
蚀刻器用户界面:(Etcher UI:)
在对驱动器进行映像并取出SD卡之后,rPI从USB驱动器启动!(After imaging the drive and removing the SD card, the rPI booted from the USB drive!)
橘子,香薰蜡烛(在橘子后面)和(Mandarin oranges, scented candles (behind the oranges) and) 特色巧克力(specialty chocolate) (橘子后面的袋子)仅在需要其他咒语才能使东西工作时才需要.((the bag behind the oranges) are only required if other incantations are required to get things working.)
正常关机(Graceful Shutdown)
尽可能使用以下方法正常关闭rPi:(As much as possible, always gracefully shutdown your rPi with:)
sudo shutdown -h now
重启rPi(Rebooting the rPi)
在命令行或终端窗口上,键入:(On the command line or terminal window, type:)
sudo reboot
后续步骤-PuTTY和WinSCP(Next Steps - PuTTY and WinSCP)
最终,我不需要将显示器,键盘和鼠标连接到rPi(因此,它也不需要桌面UI).相反,将使用PuTTY(远程登录客户端)和WinSCP进行rPi的文件传输.(Ultimately, I don’t want to have to hook up a monitor, keyboard, and mouse to the rPi (and therefore, it also doesn’t need a desktop UI). Instead, work with the rPi will be done using PuTTY (telnet client) and WinSCP for file transfers.)
- 从下载并安装PuTTY(Download and install PuTTY from) 这里(here) .(.)
- 从以下位置下载并安装WinSCP(Download and install WinSCP from) 这里(here) .(.)
启用SSH(Enable SSH)
Debian OS内置有SSH服务器,但是我们需要启用SSH.启用SSH的一种方法是输入:(The Debian OS has an SSH server built into it, however we need to enable SSH. One way to enable SSH is to enter:)
sudo raspi-config
出现一个简单的UI:(which brings up a simple UI:)
- 导航到项目5"(Navigate to item 5 “)界面选项(Interface Options)”.(".)
- 选择 “(Select “)P2 SSH-使用SSH启用/禁用对Pi的远程命令行访问(P2 SSH - Enable/Disable remote command line access to your Pi using SSH)”.(”.)
- 选择 “(Select “)是(Yes)” 提示时 “(” when prompted “)您要启用SSH服务器吗?(Would you like the SSH server to be enabled?)"(")
- 选择 “(Select “)好(OK)”.(”.)
- 选择 “(Select “)完(Finish)“退出配置应用.(” to exit the config app.) 阅读有关raspi-config应用程序的更多信息(Read more about the raspi-config app) 这里(here) .(.) 现在,一旦我们知道IP地址即可通过telnet直接登录到rPi,该IP地址由以下方式确定:(Now we can telnet directly into the rPi once we know the IP address, which is determined by using:)
ifconfig
在控制台窗口中.由于我使用的是WiFi,因此我在(in the console window. Since I’m using WiFi, I find the IP address in the) wlan0
部分为(section as) inet 192.168.0.15
确定IP地址的其他选项包括(Other options to determine the IP address include using) hostname -I
它为您提供网络IP,本地IP和IPv6地址.(which gives you the network IP, the local IP, and the IPv6 addresses.)
油灰(PuTTY)
启动PuTTY,然后输入您的rPi的IP地址:(Fire up PuTTY and enter the IP address of your rPi:)
我发现保存IP地址很有用.(I find it useful to save the IP address.)
首次连接时(或每当rPi的IP地址更改时),您将看到如下所示的对话框:(The first time you connect (or whenever the rPi’s IP address changes), you’ll see a dialog like this:)
点击 “(Click on “)是(Yes)“并继续登录:(” and proceed to login:)
用户名是” pi”(除非您对其进行了更改),而密码是您首次引导OS时设置的密码.(The username is “pi” (unless you changed it) and the password is whatever you used when setting up the OS the first time it booted.)
如果要自动登录,则可以使用(当然要更改rPi的IP地址!):(If you want to automatically log in, you can either use (change the IP address for your rPi of course!) :) putty pi@192.168.0.15 -pw [your password]
在命令行上或创建桌面快捷方式.作为读者的练习,最好的方法是使用密钥对.(on the command line or create a desktop shortcut. As an exercise for the reader (mwahaha), a better approach would be to use key pairs.)
WinSCP(WinSCP)
WinSCP的设置(SCP表示安全复制协议)的设置基本相同,不同的是,您可以在此处输入用户名和密码,并选择保存两者:(Setup for WinSCP (SCP stands for Secure Copy Protocol) is essentially the same except that here you can enter in the username and password with the option to save both:)
将会话另存为站点时,您还可以选择保存密码:(When you save the session as a site, you have the option to save your password as well:)
登录后,您会在左侧看到Windows目录结构,在右侧看到rPi的OS目录结构.这使得在两个文件之间复制和粘贴文件甚至使用简单的文本编辑器编辑文件变得非常容易.(Once you’ve logged in, you’ll see on the left the Windows directory structure and on the right, the rPi’s OS directory structure. This makes it really easy to copy and paste files between the two and even edit files with a simple text editor.)
WinSCP首次连接时,还将显示安全警报:(WinSCP, on the first time connecting, will also display a security alert:)
选择 “(Select “)是(Yes)”.(”.)
第一步:安装PostgresQL(First Big Step: Installing PostgresSQL)
第一步是安装PostgresQL.幸运的是,有一个(The first big step is to install PostgresSQL. Happily, there is a) 很棒的文章(great article) 告诉我该怎么做,否则我将永远无法解决任何问题.在PuTTY终端(或从rPi本身的终端窗口)中,键入:(that told me how to do this, as otherwise I’d never be able to figure anything out. In the PuTTY terminal (or from a terminal window on your rPi itself), type in:)
sudo apt install postgresql libpq-dev postgresql-client postgresql-client-common -y
暗示(Hint):如果您使用的是PuTTY,请右键单击鼠标以复制文本(: If you’re using PuTTY, right-click the mouse to copy text)*从剪贴板(from the clipboard)*进入终端窗口.如果您想复制文字(into the terminal window. If you want to copy text)从终端窗口(from the terminal window)到剪贴板,用鼠标选择文本并单击鼠标左键.(to the clipboard, select the text with your mouse and left-click.) 此时,请按照其余步骤进行操作,但不包括”(At this point, just follow the rest of the steps up to, but no including, “)现在使用外壳连接到Postgres并创建一个测试数据库.(Now connect to Postgres using the shell and create a test database.)“我执行的步骤是:(” The steps I performed are:)
sudo su postgres
createuser pi -P --interactive
并按照文章或我所做操作的屏幕快照中的提示进行响应(显然,输入您自己的密码):(and respond the prompts as indicated in the article or the screenshot of what I did (obviously, enter your own password):)
暗示(Hint):以超级用户(” su”)身份登录后,您可以输入(: Once logged in as a superuser (“su”), you can type) exit
以该用户身份退出并返回到” pi"用户.但是,如果您要按照本节中的步骤进行操作,请不要执行此操作.(to, well, exit as that user and return to the “pi” user. Don’t do this yet though if you’re following the steps in this section.)
远程连接到Postgres(Connecting to Postgres Remotely)
我们都想远程工作,对吗?我的意思是,在当今时代,借助所有这些技术,在办公室开车似乎是荒谬的.抱歉,没有主题.继续进行本教程,让我们启用Postgres,以便我们可以远程连接到它.根据我上面链接的文章:(We all want to work remotely, right? I mean, in this day and age, with all this tech, driving in the office seems absurd. Sorry, off topic. Continuing further down the tutorial, let’s enable Postgres so we can connect to it remotely. As per the article I linked to above:)
- 编辑PostgreSQL配置文件(Edit the PostgreSQL config file)**/etc/postgresql/9.6/main/postgresql.conf(/etc/postgresql/9.6/main/postgresql.conf)**取消注释(to uncomment the)
listen_addresses
行并更改其值(line and change its value from)localhost
至(to)*
.(.)使用(Using)nano
,一个简单的终端编辑器,按照步骤1中的指示进行编辑.我们使用nano作为超级用户,因此我们有权保存文件.(, a simple terminal editor, edit the line as indicated in step 1. We’re using nano as the superuser so we have the permissions to save the file.) 暗示(Hint):当前路径在(: The current path is on the left of the)$
,您输入的内容位于(, what you type in is on the right of the)$
.(.)
别忘了删除(Don’t forget to remove the) #
在生产线的开始!(at the start of the line!)
- 编辑(Edit the)**/etc/postgresql/9.6/main/pg_hba(/etc/postgresql/9.6/main/pg_hba)**配置文件并更改(config file and change)
127.0.0.1/32
至(to)0.0.0.0/0
用于IPv4和(for IPv4 and)::1/128
至(to)::/0
用于IPv6.(for IPv6.)
确保编辑未注释掉的行!(Make sure you edit the lines that are NOT commented out!)
关于第三步,重新启动postgres服务,我无法使这一步起作用-它一直在询问postgres用户的密码,但是没有一个.重新启动rPi后,我再次尝试了该命令,并说该服务尚未启动!所以我不知道发生了什么.(Regarding the third step, restarting the postgres service, I was unable to get this step to work – it kept asking for the postgres user’s password, and there isn’t one. After rebooting the rPi, I tried the command again and it said the service hadn’t started! So I don’t know what’s going on.)
在Windows Box上安装pgadmin(Installing pgadmin on Your Windows Box)
从以下位置下载pgadmin 3(非常重要的一点是您下载不再受支持的pgadmin 3,因为它是桌面应用程序,而不是本地主机Web应用程序,是的)(Download pgadmin 3 (very important that you download the no longer supported pgadmin 3, as it is a desktop app, not a localhost web app, yuck) from) 这里(here) (或来自的pgadmin 4((or pgadmin 4 from) 这里(here) )并安装在Windows机器上.当然,您可以使用pgadmin4,但是我个人更喜欢使用不需要在浏览器中运行的应用程序.无论如何,UI都是相似的.使用pgadmin3,在您的rPi上建立到Postgres的连接(相应地更改IP地址和密码):()and install on your Windows box. Certainly you can use pgadmin4, but I personally prefer to have an application that doesn’t require being run in my browser. Regardless, the UIs are similar. Using pgadmin3, create a connection to Postgres on your rPi (change the IP address and password accordingly):)
如果您正确地修改了上面的文件(我不是第一次),那么您应该可以连接并浏览数据库:(If you modified the files above correctly (I didn’t the first time), you should be able to connect and explore the database:)
不幸的是,我发现pgadmin 3有问题(尝试添加表等时会报告查询错误,但似乎并不能阻止该操作完成),但是pgadmin 4(浏览器版本)的工作原理很不错更好.这是pgadmin 4的屏幕截图:(Unfortunately, I’m finding pgadmin 3 to be buggy (it’s reporting query errors when I try to add tables, etc., but it doesn’t seem to prevent the operation from completing) but pgadmin 4 (the browser version) works a lot better. Here’s a screenshot from pgadmin 4:)
请注意,当我第一次运行pgadmin 4时,它无法启动” pgadmin 4服务器".当我第二次尝试时,它起作用了.去搞清楚.关键是,我们可以连接到运行在rPi上的Postgres服务器!(Note that when I first ran pgadmin 4, it couldn’t start the “pgadmin 4 server.” When I tried it a second time, it worked. Go figure. The point being, we can connect to the Postgres server running on the rPi!)
我们的rPi表现如何?(How’s our rPi Doing?)
让我们用(Let’s use) free -h
查看内存分配的外观:(to see how the memory allocation looks:)
共享内存的32M用于显示驱动程序.鉴于有521M的免费空间,我们在安装Postgres之后做的还不错.(The 32M of shared memory is for the display driver. Given that there’s 521M free, we’re doing pretty well after installing Postgres.)
和(And) df -h
看看我们的磁盘可用空间如何:(to see how our disk free space looks:)
暗示(Hint):"(: The “) -h
“告诉这两个命令以1位数的精度(过去的小数点)将显示的长度缩短为字节,K(千字节),M(兆字节),G(千兆字节)或T(兆字节)可读的显示.(” tells both commands to shorten the amount displayed to the byte, K (kilobyte), M (megabyte), G (gigabyte), or T (terabyte) with 1 digit of precision (past the decimal point) which makes for a much more readable display.)
安装DotNet Core(Installing DotNet Core)
再说一遍,“我什么都不知道!“并依靠他人来讲述如何做事. “戴夫工程师"有(Again, “I know nothing!” and rely on others to tell how to do things. “Dave the Engineer” has) 很棒的MSDN博客文章(a great MSDN blog post) 在rPi上设置.NET Core运行时.但这是针对.NET Core 2.0的,我想安装最新的稳定版本,即2.2(我很想安装3.0,但我将等待.)更多谷歌搜索发现(on setting up the .NET Core runtime on the rPi. But this is for .NET Core 2.0, and I’d like to install the latest stable version, which is 2.2 (I’m tempted to install 3.0, but I’ll wait.) More Googling finds) [斯科特汉瑟曼(Scott Hanselman)的帖子(*Scott Hanselman's post*)](https://www.hanselman.com/blog/BuildingRunningAndTestingNETCoreAndASPNETCore21InDockerOnARaspberryPiARM32.aspx) 关于安装.NET Core 2.1.跳过所有Docker内容,然后转到帖子的底部,找到"第二"部分.我特别不想使用Docker,因为它增加了复杂性,而且正如Scott所写的那样,我想在金属上使用.NET Core.有趣的是,Scott的文章包括安装SDK,据我了解,该SDK不被支持.德扬
斯托雅诺维奇(Dejan Stojanovic)(on installing .NET Core 2.1. Skip all the Docker stuff and go down to the bottom of the post where you find the section “Second.” I particularly don’t want to use Docker as it’s an added complexity and as Scott writes, I want to use .NET Core “on the metal.” Interestingly, Scott’s article includes installing the SDK, which from all I’ve read is unsupported. Dejan Stojanovic) 有一篇文章(has an article) 用于安装2.2!如果您认为太空中的太空垃圾是个问题,那么在Internet上查找有关最新技术的帖子已成为一种真正的麻烦!(for installing 2.2! If you think space junk in orbit is a problem, it’s becoming a real nuisance to find posts on the most current technologies on the Internet!)
跳过本文的中间部分,我们应该运行以下代码:(Skipping down the middle of the article, we’re supposed to run this:)
wget https://download.visualstudio.microsoft.com/download/pr/
36bff52b-2cdd-4011-8e92-d00f7537704f/9885ba267b1ef29a1401adc387d9a016/
dotnet-sdk-2.2.101-linux-arm.tar.gz
真是的您甚至如何找出所有这些疯狂的数字?令人惊讶的是:(Good grief. How do you even figure out all these crazy numbers? Amazingly, that worked:)
在他的帖子之后,我们现在运行:(Following his post, we now run:)
sudo mkdir -p /bin/dotnet && sudo tar zxf dotnet-sdk-2.2.101-linux-arm.tar.gz -C /bin/dotnet
export DOTNET_ROOT=/bin/dotnet
export PATH=$PATH:/bin/dotnet
然后编辑(and edit the)**bash.rc(bash.rc)**文件:(file:)
sudo nano ~/.bashrc
并在末尾添加以下行:(and add this line at the end:)
export PATH=$PATH:/bin/dotnet
哇,行得通! (当所有这些东西都在Linux中工作时,我总是感到惊讶.)(Wow, it worked! (I’m always surprised when all this stuff works in Linux.))
测试.NET Core应用程序(Testing a .NET Core Application)
请按照此处的说明进行操作:(Following the instructions here:)
-
在PC上的命令行窗口(不是rPi)中,为测试应用创建目录,然后(In a command line window on your PC (not the rPi), create a directory for the test app and)
cd
进入该目录.(into that directory.) -
输入:(Type in:)
dotnet new console
-
输入:(Type in:)
dotnet publish -r linux-arm
然后:(Then:) -
深入研究文件夹结构以查找发布文件夹-使用WinSCP,复制(Drill into the folder structure to find the publish folder - using WinSCP, copy)*一切(everything)*在此文件夹中,将其放到rPi上的文件夹中.(in this folder into a folder on your rPi.)
-
在"腻子"窗口中,(In the PuTTY window,)
cd
进入在rPi上创建的文件夹,然后键入:(into the folder created on the rPi and type in:)chmod 755 ./consoleApp
使该文件成为可执行文件.(to make that file an executable.) -
类型:(Type:)
./consoleApp
如果一切顺利,您应该看到Hello World发出了:(If all went well, you should see Hello World emitted:)
有很多的欣喜!!!(And there was much rejoicing!!!)
在rPi上使用C#和.NET Core连接到Postgres(Connecting to Postgres with C# and .NET Core on the rPi)
现在,让我们看看是否可以使用在rPi上运行的应用程序连接到Postgres数据库.我们应该能够在Visual Studio中测试代码,并连接到rPi上的Postgres -呵呵,有一个辅助应用程序,使用rPi作为数据库服务器!(Now let’s see if we can connect to the Postgres database with an app running on the rPi. We should be able to test the code in Visual Studio, connecting to Postgres on the rPi – hah, there’s a secondary application, using the rPi as a database server!)
创建一个测试数据库(Create A Database for Testing)
在开始使用C#方面之前,我们首先创建一个数据库和一个简单的表进行测试.在pgadmin SQL窗口中,执行以下命令:(Before we get started with the C# side of things, let’s first create a database and a simple table for testing. In the pgadmin SQL window, execute this:)
CREATE TABLE public."TestTable"
(
"ID" serial primary key NOT NULL,
"FirstName" text COLLATE pg_catalog."default",
"LastName" text COLLATE pg_catalog."default"
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE public."TestTable" OWNER to pi;
暗示(Hint):在pdgadmin 3中,选择(: In pdgadmin 3, select)工具类(Tools)->(->)查询工具(Query Tool)在pgadmin3中,单击SQL图标.(, in pdgadmin 3, click on the SQL icon.)
暗示(Hint):(: The) serial
(要么((or) bigserial
)关键字是Postgres指定自动递增字段的方式.() keyword is Postgres' way of specifying an auto-increment field.)
添加Nuget软件包(Add Nuget Packages)
使用 “(Using the “) consoleApp
上面创建的"“项目,右键单击"依赖项”:(” project created above, right-click on the Dependencies:)
并添加两个依赖项:(and add two dependencies:)
Microsoft.EntityFrameworkCore
Npgsql.EntityFrameworkCore.PostgreSQL
您的项目现在应该在NuGet子文件夹中引用这些:(Your project should now reference these in the NuGet sub-folder:)
其他命名空间(Additional Namespaces)
添加以下名称空间:(Add the following namespaces:)
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics;
using Microsoft.EntityFrameworkCore;
诊断将用于计时数据库操作.(Diagnostics will be used to time the database operations.)
TestTable模型和DbContext(The TestTable Model and DbContext)
public class TestTable
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Context : DbContext
{
public DbSet<TestTable> TestTable { get; set; }
public Context(DbContextOptions options) : base(options) { }
}
主要(Main)
Main修改为执行(Main is modified to execute) TestPostgres
接下来我们会看到.(which we’ll see next.)
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
TestPostgres();
Console.ReadLine();
}
TestPostgres方法(TestPostgres Method)
这是个(This is an) async void
方法,通常要避免!如果找不到数据,则此方法将自动插入几行,并对操作计时.在下面的代码中,替换(method, normally to be avoided! This method will automatically insert a couple rows if no data is found and time the operations. In the code below, replace) [your password]
使用创建Postgres时使用的密码(with the password you used when creating the Postgres) pi
用户.(user.)
static async void TestPostgres()
{
var contextBuilder = new DbContextOptionsBuilder();
// Database name is case-sensitive
contextBuilder.UseNpgsql
("Host=192.168.0.15;Database=Test;Username=pi;Password=[your password]");
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
using (var context = new Context(contextBuilder.Options))
{
Console.WriteLine(stopwatch.ElapsedMilliseconds + "ms");
stopwatch.Restart();
var items = await context.TestTable.ToListAsync();
Console.WriteLine("First query: " + stopwatch.ElapsedMilliseconds + "ms");
stopwatch.Restart();
Console.WriteLine("Number of items: " + items.Count);
if (items.Count == 0)
{
TestTable t1 = new TestTable() { FirstName = "Marc", LastName = "Clifton" };
TestTable t2 = new TestTable() { FirstName = "Kelli", LastName = "Wagers" };
context.Add(t1);
context.Add(t2);
context.SaveChanges();
Console.WriteLine("Insert: " + stopwatch.ElapsedMilliseconds + "ms");
Console.WriteLine("t1 ID = " + t1.ID);
Console.WriteLine("t2 ID = " + t2.ID);
stopwatch.Restart();
}
else
{
items.ForEach(t => Console.WriteLine
("ID: " + t.ID + " FirstName: " + t.FirstName + " LastName " + t.LastName));
}
// Query again to see how long a second query takes.
var items2 = await context.TestTable.ToListAsync();
Console.WriteLine("Second query: " + stopwatch.ElapsedMilliseconds + "ms");
stopwatch.Restart();
}
using (var context = new Context(contextBuilder.Options))
{
// Query again to see how long a second query takes.
var items2 = await context.TestTable.ToListAsync();
Console.WriteLine("Third query: " + stopwatch.ElapsedMilliseconds + "ms");
}
}
在Visual Studio中运行测试(Run the Test in Visual Studio)
运行该程序,您应该看到类似于以下内容:(Run the program, and you should see something similar to this:)
请注意,第一个查询建立了与数据库的连接,耗时将近1.5秒.我已经看到这高达4秒.(Notice the first query, which establishes a connection to the database, takes almost 1.5 seconds. I’ve seen this as high as 4 seconds.)
在rPi上运行测试(Run the Test on the rPi)
不要忘记运行(Don’t forget to run the) publish
再次命令:(command again:)
dotnet publish -r linux-arm
像以前一样使用WinSCP,复制(Using WinSCP as before, copy)一切(everything)转到rPi.(over to the rPi.)
暗示(Hint):通常,我们不需要复制所有内容,只需复制最新更改,但是由于我们添加了几个NuGet软件包,因此最好复制整个工具包和caboodle,因为可能会有dll,因此在发行日期和日期上都加了时间戳.如果按降序对文件夹内容进行排序,则不会显示.(: Normally we don’t need to copy everything, only the most recent changes, but since we added a couple NuGet packages, it’s best to copy the whole kit and caboodle as there will probably be dll’s and so’s that timestamped by their release date and won’t show up if you sort the folder contents by descending date.)
暗示(Hint):有趣的是,一次(: Interestingly, once) consoleApp
已经(has been) chmod
要成为可执行文件,我们不必再次这样做.(’d to be an executable, we don’t have to do this again.)
从Visual Studio删除在运行中创建的测试数据后,应该看到类似以下内容:(After deleting the test data created in the run from Visual Studio, you should see something similar to this:)
暗示(Hint): 按下(: Press the)输入(Enter)退出程序的关键,因为它位于(key to exit the program, as it’s sitting on the) Console.ReadLine()
呼叫.(call.)
请注意,rPi花费高达8秒钟来创建与Postgres的连接.幸运的是,一旦建立了连接,查询将在100毫秒内运行,但是插入操作花费了一秒钟.(Notice the rPi takes a whopping 8 seconds to create the connection to Postgres. Fortunately, once the connection has been established, the queries run in under 100ms, but insert took over a second.)
再次运行测试程序,我们取回数据:(Running the test program again, we get our data back instead:)
性能改进?(Performance Improvement?)
如我所述,我在强制Turbo模式(这使您的rPi保修无效!)方面做了一些尝试.(I played around a little with forcing turbo mode (which voids your rPi warranty!) as described in) 这个文章(this writeup) 但未发现性能改善.我没有尝试超频选项,因为这些选项可能会使rPi无法启动,并且我不想在恢复超频方面大惊小怪.(but found no performance improvement. I didn’t try the overclocking options as those may make the rPi unbootable and I didn’t want to fuss with recovering the)**/boot/config.txt(/boot/config.txt)**文件,可以在其中设置配置选项.(file, which is where you set the configuration options.)
裸骨头服务器(Bare Bones Server)
已经有(There already is) GitHub上的出色服务器(an excellent server on GitHub here) 它已经支持HTTPS,那么为什么要重新发明轮子呢?因为我的好奇心将我带到了编程的各个角落,所以我想看看(并学习)如何使用.NET Core编写不基于ASP.NET Core堆栈的服务器.使用ASP.NET Core堆栈编写了一个简单的服务后,我发现它易于使用,依赖项注入(DI)很酷,从HTTP标头,JSON POST正文中自动提取参数等都非常吸引人.绝对推荐!但是,我仍然想尝试一种裸机实现,除了我喜欢做的之外.因此,如果您像我一样好奇,请继续阅读.(and it already supports HTTPS, so why reinvent the wheel? Because my curiosity takes me to strange corners of programming, and I want to see (and learn) how one can use .NET Core to write a server that is not based on the ASP.NET Core stack. Having written a simple service using the ASP.NET Core stack, I found it easy to use, the dependency injection (DI) is cool, the automatic extraction of parameters from the HTTP headers, JSON POST body, etc., are all really snazzy. Definitely recommended! But still, I want try out a bare metal implementation for no other reason than it’s what I like to do. So if you’re curious like me, read on.)
HTTP服务器(HTTP Server)
HTTP服务器很简单.首先,让我们修改(An HTTP server is trivial. First, let’s modify) Main
开始(to start up an) HttpListener
:(:)
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
// TestPostgres();
StartServer();
Console.WriteLine("Press ENTER to exit.");
Console.ReadLine();
}
我们将启动服务器并以(We’ll start the server and respond with the) GET
路径以及将动词和路径写入控制台(请记住您的rPi的IP可能不同):(path as well as write the verb and path to the console (remember your rPi’s IP may be different):)
static void StartServer()
{
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://192.168.0.15:5000/");
listener.Start();
Task.Run(() => WaitForConnection(listener));
}
static void WaitForConnection(object objListener)
{
HttpListener listener = (HttpListener)objListener;
while (true)
{
HttpListenerContext context = listener.GetContext();
string verb = context.Request.HttpMethod;
string path = context.Request.RawUrl.LeftOf("?").RightOf("/");
Console.WriteLine($"Verb: {verb} Path: {path}");
byte[] buffer = Encoding.UTF8.GetBytes(path);
context.Response.StatusCode = (int)HttpStatusCode.OK;
context.Response.ContentLength64 = buffer.Length;
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
context.Response.Close();
}
}
在文件顶部添加:(Add at the top of the file:)
using System.Net;
using System.Text;
为了完整起见,我在各处使用了两种扩展方法:(And for completeness, the two extension methods that I use everywhere:)
public static class ExtensionMethods
{
public static string LeftOf(this String src, string s)
{
string ret = src;
int idx = src.IndexOf(s);
if (idx != -1)
{
ret = src.Substring(0, idx);
}
return ret;
}
public static string RightOf(this String src, string s)
{
string ret = String.Empty;
int idx = src.IndexOf(s);
if (idx != -1)
{
ret = src.Substring(idx + s.Length);
}
return ret;
}
}
发布,WinSCP和测试:(Publish, WinSCP, and test:)
大!从那里开始,HTTP的不安全世界就是我们的游乐场!(Great! From there, the unsecure world of HTTP is our playground!)
幕后花絮-htop(Under the Covers - htop)
使用很有趣(It’s interesting to use) htop
是Debian随附的交互式进程查看器,用于查看运行Web服务器应用程序的.NET Core启动了多少个进程(有10个./consoleApp进程):(, an interactive process viewer, that comes with Debian to see how many processes are started by .NET Core running the web server application (there are 10 ./consoleApp processes):)
Nginx的(nginx)
但是,实现HTTPS服务器需要反向代理服务器,例如nginx或Apache,它将获取传入IP并将其路由到指定的localhost端口,并将响应返回给发出请求的客户端.在深入研究HTTPS和SSL证书之前,让我们获得一个与我们的C#代码一起使用的基本反向代理.(Implementing an HTTPS server however requires a reverse proxy server such as nginx or Apache which will take the incoming IP and route it to a specified localhost port and return responses back to the client making the request. Before diving into HTTPS and SSL certificates, let’s get a basic reverse proxy working with our C# code.)
安装和测试nginx(Install and Test nginx)
要在rPi上安装nginx,请在终端窗口中输入它(这是我了解的(To install nginx on the rPi, enter this in a terminal window (this I learned) 从rPi网站(from the rPi site) ):():)
sudo apt-get install nginx
使用以下命令启动服务器:(Start the server with:)
sudo /etc/init.d/nginx start
现在导航到您的rPi的IP地址,您应该会看到nginx欢迎屏幕:(Now navigate to you rPi’s IP address and you should see the nginx welcome screen:)
该网站如何提供服务?(How is this Site Served?)
由于我对nginx一无所知,因此我将探讨一些基础知识.显然,nginx在某个地方创建了默认的网站和网页.配置文件在(Since I know nothing about nginx, I’m going to explore some of the basics. Obviously, nginx created a default website and webpage somewhere. The configuration file is in)/etc/nginx/sites-available(/etc/nginx/sites-available),我们在其中看到一个名为(, where we see a file called)默认(default):(:)
如果我们使用WinSCP检查此文件(或者如果您在终端中,请使用(If we inspect this file using WinSCP (or if you’re in the terminal, use)**纳米/etc/nginx/sites-available/default(nano /etc/nginx/sites-available/default)**要么(or)cat/etc/nginx/sites-available/default(cat /etc/nginx/sites-available/default)),我们会看到一些重要的配置行(以下内容从实际文件中截断了):(), we see some important configuration lines (the following is truncated from the actual file):)
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
太好了,因此它可以从(Great, so it’s serving pages from)/var/www/html(/var/www/html),我们在其中看到索引文件:(, where we see the index file:)
现在,我们知道了默认网站在哪里提供静态内容.(So now, we know where the default website is serving up static content.)
配置反向代理以运行.NET Core ConsoleApp(Configuring a Reverse Proxy to Run the .NET Core ConsoleApp)
接下来,我想将所有非静态内容路由到我的服务器.阅读(Next, I want to route anything that isn’t static content to my server. Reading the) Nginx入门指南(Beginner’s Guide on nginx) ,我将更改(, I’ll change the) try_files
命令(command to) proxy_pass
并指定(and specify the URL that the) consoleApp
程序正在监听.这必须以超级用户身份完成,因此我们使用以下命令行:(program is listening on. This has to be done as a superuser, so we use this command line:)**须藤nano/etc/nginx/sites-available/default(sudo nano /etc/nginx/sites-available/default)**编辑文件,注释掉(to edit the file, commenting out the) try_files
命令并添加(command and adding) proxy_pass http://127.0.0.1:5000/;
保存文件后,使用以下命令重新启动nginx:(and after saving the file, restarting nginx with:)
sudo /etc/init.d/nginx reload
暗示(Hint):如果重新加载nginx时出错,请返回编辑器并撤消所做的编辑,保存文件,然后查看重新加载现在是否可以正常进行.然后尝试再次更改文件.我不知道该怎么做,但是第一次在上面进行文件更改时,我遇到了一个错误(没有麻烦按照说明来查看错误是什么),所以我恢复了更改并重新应用他们,突然没有错误!(: If you get an error reloading nginx, go back into the editor and undo your edits, save the file, and see if reload now works. Then try changing the file again. I don’t know what I did, but the first time I made the file change above, I got an error (didn’t bother to follow the instructions to see what the error was), so I reverted my changes and re-applied them, and suddenly no error!)
暗示(Hint):使用(: using) http://localhost:5000/
不起作用-您从nginx收到"未找到"错误,必须使用(does not work - you get a “Not Found” error from nginx, you must use) <a href="http://127.0.0.1:5000/">http://127.0.0.1:5000/</a>
.(.)
最后,更改(Lastly, change the IP address that the) consoleApp
服务器正在侦听,至127.0.0.1:(server is listening to, to 127.0.0.1:)
listener.Prefixes.Add("http://127.0.0.1:5000/");
发布,WinSCP更改的文件结束,启动(Publish, WinSCP the changed files over, start the) consoleApp
,当您尝试使用屏幕截图中所示的URL时,您应该获得:(, and when you try a URL as depicted in the screenshot, you should get:)
并在终端窗口中:(and in the terminal window:)
暗示(Hint):在正确执行此操作之前,我遇到了一些错误,并且(: I got a few errors before getting this right, and a) 非常有用的Digital Ocean页面(very helpful Digital Ocean page) 导致我执行以下命令:(led me to this command:)
sudo tail -30 /var/log/nginx/error.log
它显示nginx报告的最后30行错误.在找出问题所在时非常有用!(which displays the last 30 lines of errors reported by nginx. Very useful in figuring out what’s going wrong!) 暗示(Hint):自动启动nginx(从(: auto-start nginx (from) 这里(here) ):():) 在启动时自动启动NGINX:(Auto-start NGINX at boot:)
cd /etc/init.d
sudo update-rc.d nginx defaults
删除自动启动:(Remove auto-start:)
sudo update-rc.d -f nginx remove
HTTPS(HTTPS)
反向代理的伟大之处在于它可以为您处理HTTPS-您的本地服务器可以是HTTP.另外,nginx支持服务器名称标识(SNI),这意味着我可以从同一物理设备和IP地址运行多个域,每个域具有不同的SSL证书.现在,我们将只创建一个自签名证书进行测试.首先,让我们证明HTTPS无法正常工作:(The great thing about a reverse proxy is that it handles HTTPS for you – your local server can be HTTP. Also, nginx supports Server Name Identification (SNI) which means that I can run several domains, each with different SSL certificates, from the same physical device and IP address. For now, we’ll just create a self-signed certificate for testing. First, let’s prove that HTTPS isn’t working:)
是的,不行.接下来,让我们创建一个以下内容的自签名证书(是的,我再次找比我了解更多的人)(Yup, not working. Next, let’s create a self-signing certificate following (yes, once again, I revert to people that know a lot more than me)) Karlo van Wyk的指示在这里(Karlo van Wyk’s instructions here) .基本上,请原谅我essentially窃他的说明,创建一个文件夹,然后在该文件夹中创建一个名为(. Basically, forgive me for essentially plagiarizing his instructions, create a folder and in that folder, create a file called)本地主机(localhost.conf).您可以使用nano编辑器,由于某种原因,说明说要启动(. You can use the nano editor, and for some reason, the instructions say to launch) nano
作为超级用户通过(as the superuser via) sudo nano
,我不确定为什么.接下来,复制他提供的配置文件(我很难过再次将其发布到此处,但是出于完整性考虑(, I’m not sure why. Next, copy the configuration file he provides (I feel really bad posting it here again, but for completeness of)*这个(this)*文章,似乎有必要):(article, it seems necessary):)
[req]
default_bits = 2048
default_keyfile = localhost.key
distinguished_name = req_distinguished_name
req_extensions = req_ext
x509_extensions = v3_ca
[req_distinguished_name]
countryName = Country Name (2 letter code)
countryName_default = US
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = New York
localityName = Locality Name (eg, city)
localityName_default = Rochester
organizationName = Organization Name (eg, company)
organizationName_default = localhost
organizationalUnitName = organizationalunit
organizationalUnitName_default = Development
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = localhost
commonName_max = 64
[req_ext]
subjectAltName = @alt_names
[v3_ca]
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = 127.0.0.1
随时编辑您的位置信息.(Feel free to edit your locality information.) 接下来,创建证书密钥对(公共和私有):(Next, create the certificate key pairs (public and private):)
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048
-keyout localhost.key -out localhost.crt -config localhost.conf
然后将它们复制到(Then copy them to the)**/etc/ssl(/etc/ssl)**文件夹作为超级用户(因此您具有写权限):(folders as the superuser (so you have write permissions):)
sudo cp localhost.crt /etc/ssl/certs/localhost.crt
sudo cp localhost.key /etc/ssl/private/localhost.key
最后,使用(Lastly, using) sudo nano
,编辑(, edit the)**默认(default)**像我们上面所做的文件:(file like we did above:)
sudo nano /etc/nginx/sites-available/default
取消注释SSL配置行并添加几行额外的行,因此看起来像这样:(uncommenting the SSL configuration lines and adding a couple extra lines, so it looks like this:)
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_certificate /etc/ssl/certs/localhost.crt;
ssl_certificate_key /etc/ssl/private/localhost.key;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
最后,像之前一样重新加载nginx配置:(Finally, reload the nginx configuration as we did earlier:)
sudo /etc/init.d/nginx reload
然后使用HTTPS浏览到rPi的IP,您应该获得以下信息:(Then browse to the rPi’s IP using HTTPS, and you should get this:)
显然,现在正在建立连接,Chrome浏览器警告您该证书无效,这很明显,因为我们正在创建测试证书,而不是具有证书授权机构(例如LetsEncrypt)的证书.因此,请点击”(Clearly, the connection is now being made and Chrome is alerting you that the certificate in not valid, which is obvious because we’re creating a test certificate rather than one with a certificate authority such as LetsEncrypt. So, click on “)高级(Advanced)“和”(” and “)继续….(proceed….)前往网站:(” to get to the site:)
然后你去了!(And there you go!)
运行服务器即服务(Running the Server as a Service)
理想情况下,当rPi引导时,Web服务器应自动启动-尽管我确实必须通读了两者,但实现这一点很简单(Ideally, the web server should start up automatically when the rPi boots – implementing this is straight forward though I did have to read through both) 这个连结(this link) 关于托管ASP.NET Core和(on hosting ASP.NET Core and) 这个连结(this link) 设置简单的控制台应用程序即服务.这里的"把戏"是不要执行(on setting up a simple console app as a service. The “trick” here is not to perform a) Console.ReadLine
因为这样会使启动过程超时,并且显然不退出应用程序!按照第二个链接的指导,添加以下名称空间:(as this times out the startup process, and obviously not to exit the application! Following the guidance from the second link, add these namespaces:)
using System.IO;
using System.Reflection;
然后编辑(and edit)Program.cs(Program.cs):(:)
static readonly CancellationTokenSource tokenSource = new CancellationTokenSource();
static void Main(string[] args)
{
StartService();
}
和实现(从第二个链接的示例中摘录):(and the implementation (trimmed down from the example in the second link):)
static void StartService()
{
AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
StartServer();
while (!tokenSource.Token.IsCancellationRequested)
{
Thread.Sleep(1000);
}
}
private static void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
tokenSource.Cancel();
}
暗示(Hint)注意:可以通过等待直到令牌被取消的任务来改善while循环.(: The while loop can probably be improved with a task that waits until the token is cancelled.)
接下来,创建一个(Next, create a)**.服务(.service)文件在(file in the)/lib/systemd/system(/lib/systemd/system)**看起来像这样的文件夹(使用(folder that looks like this (use) sudo nano
创建和编辑文件):(to create and edit the file):)
[Unit]
Description=Web Server
After=nginx.service
[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/webserver
ExecStart=/home/pi/webserver/consoleApp
Restart=always
[Install]
WantedBy=multi-user.target
如您所见,我将(As you can see, I place)consoleApp(consoleApp)(及其文件)放入一个名为((and its files) into a folder called)**网络服务器(webserver)**我也叫服务档案(and I also called the service file)webserver.service(webserver.service).(.) 创建服务文件后,创建一个符号链接以便于参考:(Once service file is created, create a symlink for easy reference:)
sudo systemctl enable webserver
您可以使用以下命令立即手动启动服务器:(You can manually start the server right away with:)
sudo systemctl start webserver
并使用以下命令检查其状态:(and check on its status with:)
systemctl status webserver.service
暗示(Hint):查看服务状态时,会记录并显示任何控制台输出!(: Any console output is logged and displayed when you view the service status!)
您应该看到类似以下内容:(You should see something similar to this:)
我们还可以看到该服务正在运行(We can also see the service running using) htop:
我发现错误完全可以说明问题所在.(I found that errors are fairly indicative of the problem.)
修订版(Revisions)
- 1/11/2019:添加了将Web服务器设置为服务(1/11/2019: Added setting up the web server as a service)
结论(Conclusion)
本文完成了很多事情:(This article accomplishes quite a few things:)
- 确定rPi版本和功能(Determining the rPi version and capabilities)
- 将操作系统映像到USB驱动器上(Imaging an OS onto a USB drive)
- 设置SSH,以便我们可以使用PuTTy和WinSCP与rPi进行通信(Setting up SSH so we can use PuTTy and WinSCP to communicate to the rPi)
- 安装Postgres并创建测试数据库(Installing Postgres and creating a test database)
- 从Windows框直接在rPi上安装.NET Core 2.2并测试Postgres连接(Installing .NET Core 2.2 and testing out Postgres connectivity, both from a Windows box and directly on the rPi)
- 创建一个” echo” HTTP服务器(Creating an “echo” HTTP server)
- 为HTTP安装和配置Nginx(Installing and configuring nginx for HTTP)
- 将Nginx配置为.NET Core” echo"服务器的反向代理(Configuring nginx as a reverse proxy to our .NET Core “echo” server)
- 使用测试证书配置Nginx(Configuring nginx with a test certificate) 而这里最大的成就是,我们无需使用ASP.NET Core就能完成所有这些工作.坦白说,很难找到与ASP.NET Core不相关的有关nginx,设置HTTPS等方面的文章,所以希望读者能理解我在这里所采用的裸机方法.我的下一篇文章将更深入地探讨创建一个真实的网站(现有网站的端口),解决性能问题(连接Postgres的8秒钟令人恐惧的连接延迟)以及谁知道其他问题.(And the big accomplishment here is that we did all this without using ASP.NET Core. Frankly, it’s damn hard to find any articles that are not related to ASP.NET Core with regards to nginx, setting up HTTPS, etc., so hopefully the reader will appreciate the bare-metal approach that I’ve taken here. My next article will dive more into creating a real website (a port from an existing website), working with performance issues (that horrid 8 second connect delay to Postgres) and who knows what else.)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C# Raspberry .NET-Core .NET Dev 新闻 翻译