安装net 6.0环境几种方式:

一、直接用源安装

On Ubuntu 20.04

wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb

On Ubuntu 18.04

wget https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb

开发SDK

apt update
apt install -y apt-transport-https
apt install -y dotnet-sdk-6.0

应用程序运行时

apt update
apt install -y apt-transport-https
apt install -y aspnetcore-runtime-6.0

ASP.NET Core Runtime

apt update
apt install -y apt-transport-https
apt install -y dotnet-runtime-6.0

二、官方脚本

wget https://dot.net/v1/dotnet-install.sh
chmod +x dotnet-install.sh
./dotnet-install.sh -c 6.0

增加变量:
$ vim ~/.bashrc
export PATH=$PATH:$HOME/.dotnet
export DOTNET_ROOT=$HOME/.dotnet
source ~/.bashrc

三、用 Snap 安装

apt install snapd
systemctl enable --now snapd.socket
systemctl enable --now snapd apparmor
snap install dotnet-sdk --classic --channel=6.0
snap alias dotnet-sdk.dotnet dotnet
snap install dotnet-runtime-60 --classic
snap alias dotnet-runtime-60.dotnet dotnet
vim ~/.bashrc
export DOTNET_ROOT=/snap/dotnet-sdk/current
source ~/.bashrc

开启 Tab 自动完成功能:

$ vim ~/.zshrc

# zsh parameter completion for the dotnet CLI
_dotnet_zsh_complete()
{
  local completions=("$(dotnet complete "$words")")
  reply=( "${(ps:\n:)completions}" )
}
compctl -K _dotnet_zsh_complete dotnet

$source ~/.zshrc

$ vim ~/.bashrc

# bash parameter completion for the dotnet CLI
_dotnet_bash_complete()
{
  local word=${COMP_WORDS[COMP_CWORD]}

  local completions
  completions="$(dotnet complete --position "${COMP_POINT}" "${COMP_LINE}" 2>/dev/null)"
  if [ $? -ne 0 ]; then
    completions=""
  fi
  COMPREPLY=( $(compgen -W "$completions" -- "$word") )
}
complete -f -F _dotnet_bash_complete dotnet

$ source ~/.bashrc

测试:

dotnet new console --output testapp1
dotnet run --project testapp1

打包时,选择 linux

安装SVN:

apt install subversion
svn checkout https://server/myproject
cd myproject
chmod 777 ./myproject

后台运行

nohup ./myproject> /dev/null 2>&1 &

web 项目后台运行:

nohup dotnet Demo.Net.Core.dll --urls="http://:8081;http://:8082" --environment=Delopment > /dev/null 2>&1 &

注意,后台运行时,不能用 ReadKey, ReadLine 之类的方法,会导致一行动就出错退出。

C#,将WinForm改成Service

1、添加引用:System.ServiceProcess
2、建类:

class ServiceProc : ServiceBase
{
    MainService ms = new MainService();

    public ServiceProc()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        ms.NoticeEvent += Ms_NoticeEvent;
        ms.Start();
    }

    private void Ms_NoticeEvent(string type, string content, CommunalClass.Entities.LogLevels level)
    {
        LogsRecord.Write("INFO", $"[{DateTime.Now.ToString("mm:ss")}][type]{content}");
    }

    protected override void OnStop()
    {
        ms.Stop();
        Environment.Exit(Environment.ExitCode);
    }

    private System.ComponentModel.IContainer components = null;

    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    private void InitializeComponent()
    {
        components = new System.ComponentModel.Container();
        this.ServiceName = "SystemMonitorService";
    }
}

3、右键点击刚刚建的类,查看设计器,在设计界面上,右健,“添加安装程序”;
4、新的安装类上,会自动添加2个组件:serviceProcessInstaller1、serviceInstaller1;
5、serviceProcessInstaller1 属性:Account,改成 LocalSystem;
6、serviceInstaller1 属性:Description 描述,DisplayName 显示在服务中的名字,StartType 改成 Automatic 自动启动;
7、配置文件中加一项:run_as_service,用来配置是否以服务的方式启动程序,这样可以方便的以后随时用WINFORM方式启动;
8、改 Program.cs:

/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
    Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
    AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    if (AppSet.Default.run_as_service)
    {
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] { new ServiceProc() };
        ServiceBase.Run(ServicesToRun);
    }
    else
        Application.Run(new Form1());
}

static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
    try { trip.CommunalClass.LogsRecord.write("AppDomainError", e.ExceptionObject.ToString()); }
    catch { }
}

static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
    try { trip.CommunalClass.LogsRecord.write("AppError", e.Exception.ToString()); }
    catch { }
}

9、此时大功告成,再就是写几个批处理文件:

-------------- 安装:service_install.bat --------------

@echo off 
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe myapp.exe
pause

-------------- 卸载:service_uninstall.bat --------------

@echo off 
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /u myapp.exe
pause

-------------- 开始:service_start.bat --------------

@echo off 
net start ServiceName
pause

-------------- 停止:service_stop.bat --------------

@echo off 
net stop ServiceName
pause

ASP.NET可用的线程毕竟是有限的,可能是当时瞬间的并发请求太多,ASP.NET来不及创建足够的线程处理这些请求。

我们来看一下.Net framework中线程相关的设置

machine.config中的processModel(位于C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config)

有4个相关设置:maxWorkerThreads(默认值是20), maxIoThreads(默认值是20), minWorkerThreads(默认值是1), minIoThreads(默认值是1)。(这些设置是针对每个CPU核)

我们用的就是默认设置,由于我们的Web服务器是8核的,于是实际的maxWorkerThreads是160,实际的maxIoThreads是160,实际的minWorkerThreads是8,实际的minIoThreads是8。

基于这样的设置,是不是如果瞬间并发请求是169,就会出现排队?不是的,ASP.NET没这么傻!因为CLR 1秒只能创建2个线程("The CLR ThreadPool injects new threads at a rate of about 2 per second. "),等线程用完时才创建,黄花菜都凉了。
我们猜测ASP.NET只是根据这个设置去预测线程池中的可用线程是不是紧张,是不是需要创建新的线程,以及创建多少线程。

假如并发请求数平时是300,突然某个瞬间并发请求数是600,超出了ASP.NET预估的所需的可用线程数,于是那些拿不到线程的请求只能排队等待正在执行的请求释放线程以及CLR创建新的线程。
随着时间的推移,释放出来的线程+新创建的线程足以处理这些排队的请求,就恢复了正常。

优化设置

<processModel enable="true"  requestQueueLimit="5000" maxWorkerThreads="2000" maxIoThreads="1000" minWorkerThreads="150" minIoThreads="150"/>

root@mail:~# whereis caddy
caddy: /etc/caddy /usr/local/bin/caddy

Thank you. So the apt pkg installs the binary in /usr/bin, but you have the old caddy placed in /usr/local/bin/caddy.
If you run echo $PATH you'll see /usr/local/bin somewhere to the left of /usr/bin.
This means when you run the command caddy, the OS will search for the executable through the directories listed in $PATH from left to right, and will find it in /usr/local/bin (which is v1) before it finds the one in /usr/bin (which is v2).

If your “installation” of v1 was using getcaddy.com or manually placing the executable in /usr/local/bin, then resolving this should be as simple as removing the /usr/local/bin/caddy executable.

v1中文文档:https://www.bookstack.cn/read/caddy-cn-doc/README.MD
v2中文文档:https://caddy2.dengxiaolong.com/docs/
官方:https://caddyserver.com/docs/

卸载
kill 进程
systemctl disable caddy.service
rm /usr/local/bin/caddy

二进制安装:
先下载,如果需要模块的,可下载带模块的(注意选择正确的平台,arch 命令查看)
https://github.com/caddyserver/caddy/releases
https://caddyserver.com/download

下载deb安装:
wget https://github.com/caddyserver/caddy/releases/download/v2.4.6/caddy_2.4.6_linux_amd64.deb
dpkg -i caddy_2.4.6_linux_amd64.deb

直接下载程序包:
mv caddy /usr/bin/
chmod -R 777 /usr/bin/caddy
caddy version
vim /etc/systemd/system/caddy.service
内容在:https://github.com/caddyserver/dist/blob/master/init/caddy.service
groupadd --system caddy
useradd --system --gid caddy --create-home --home-dir /var/lib/caddy --shell /usr/sbin/nologin --comment "Caddy web server" caddy
systemctl daemon-reload
systemctl enable --now caddy
systemctl status caddy

直接安装:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo tee /etc/apt/trusted.gpg.d/caddy-stable.asc
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy

源码安装(其它模块):
git clone "https://github.com/caddyserver/caddy.git"
cd caddy/cmd/caddy/

安装 xcaddy----------------------------------------------------------------------
直接安装方式:
apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/gpg.key' | sudo tee /etc/apt/trusted.gpg.d/caddy-xcaddy.asc
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-xcaddy.list
apt update
apt install xcaddy

Go 安装方式:先安装 go (https://go.dev/doc/install):
wget https://go.dev/dl/go1.18.linux-amd64.tar.gz
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.18.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
go version

再安装 xcaddy

go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest

安装带 replace-response 模块的 Caddy
xcaddy build --with github.com/caddyserver/replace-response