dotnet发布运行

  • Post author:
  • Post category:其他




一 HTTP Error 400. The request hostname is invalid.

  1. 在当前项目的工程路径下,找到.vs\config 文件夹下面的applicationhost.config 这个文件。
  2. 在找到applicationhost.config 文件后,打开,在文件中找到site 那个节点,修改bindings 属性,如下图所示;这其实给在iis中编辑绑定是一样的意思。

    在这里插入图片描述
  3. 具体修改的内容有几点注意的:

    a. 如果用实际公网域名


    <binding protocol="http" bindingInformation="*:9999:localhost" />

    , localhost 直接换成公网域名即可,vs不需要使用管理员权限打开

    b. 如果用自定义域名

    localhost 替换为自定义域名,如果是管理员权限打开不需要编辑系统的hosts文件,如果是普通权限打开,需要编辑hosts文件;

    我是win7系统,hosts文件在 C:\Windows\System32\drivers\etc 下面,是隐藏的,所以要从系统菜单-工具-文件夹选项-的显示中选择显示隐藏的文件夹。

    我在修改的时候,安装的杀毒软件小红伞阻止修改host,选择允许就可以保存了,不然会提示有其他文件正在打开,不让保存。

    c. 如果使用局域网ip

    将localhost 换成具体的ip即可,注意一定要用管理员权限打开vs。不然还是不能的。我是需要使用局域网ip,在此处新增了一条binding属性,如下图所示:

    在这里插入图片描述
  4. 修改完毕config后,重启下VS,重启的时候选择是否以管理员的身份运行



二 .NET Core CLI Interface


dotnet –info

:查看当前安装的版本。


指定项目使用的SDK版本



dotnet new global.json --sdk-version <SDK版本号>

,要注意的是最后的参数是SDK版本,不是.NET Core版本。


dotnet new

:用于创建一个新项目,关于项目类型,可以用命令:

dotnet new --help

查看。


dotnet restore

:恢复项目的依赖项和工具。


dotnet restore

命令使用 NuGet 还原 project.json 文件中被指定的依赖项,以及特定于项目的工具。默认情况下,依赖项和工具的还原是并行完成的。对于依赖项,可以在还原操作时使用–packages参数指定还原包的位置。如果没有指定,则默认使用NuGet包缓存。对于特定项目的工具,dotnet restore 首先还原该工具包,然后继续还原在项目文件中指定的工具依赖项。


dotnet build

#创建MVC工程
[zebra Desktop]$mkdir work && cd work
[zebra work]$dotnet new console -n Zebra.Liu.Console
#添加Nuget包,这是添加了mysql的驱动包
[zebra work]$cd Zebra.Liu.Console/
[zebra Zebra.Liu.Console]$dotnet add package Pomelo.EntityFrameworkCore.MySql
[zebra Zebra.Liu.Console]$ls
Program.cs Zebra.Liu.Console.csproj  obj
#编译工程,输出到build文件夹中
[zebra Zebra.Liu.Console]$dotnet build -o build/
[zebra Zebra.Liu.Console]$ls
Program.cs Zebra.Liu.Console.csproj build obj
#多了一个build文件夹,用于存放编译后的文件
[zebra Zebra.Liu.Console]$ls build/
Zebra.Liu.Console.dll  #二进制文件(中间语言IL)
Zebra.Liu.Console.pdb  #symbol文件,用于调试
Zebra.Liu.Console.deps.json # *.deps.json中列出应用程序的依赖项
Zebra.Liu.Console.runtimeconfig.dev.json
Zebra.Liu.Console.runtimeconfig.json # 指定共享运行时以其版本

上面的试验可以看出build命令最后的产物,如果有项目使用了第三方的依赖,如像上面一样使用了NuGet中的MySQL驱动,那么在执行build命令时,只会从本机的NuGet缓存库中解析依赖项,也就是说,生成的dll文件,不包含MySQL的驱动。这样build的dll文件,从本机拷贝到另外的机器上,可能不能运行。如果要将依赖项也打包,可以使用另一个命令dotnet publish。

publish命令和build命令最大的区别在于:publish命令将应用程序的依赖项,从NuGet缓存复制到输出文件夹中。

build后的程序是否为可执行,主要看.csproj文件中的选项

<!-- .csproj文件内容 -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <!--
      OutputType 输出类型设置为Exe,说明这个工程,可执行
      可执行的dll和不可执行的dll文件最大的区别在于,有没有入口点以及是否可执行
     -->
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.1</TargetFramework>
  </PropertyGroup>
</Project>


dotnet watch run


dotnet watch 是一个开发阶段在源文件发生变动的情况下使用 dotnet 命令的工具。 当代码发生变动的时候可以用来执行编译,运行测试,或者发布操作。


dotnet clean


清除上一个生成的输出,包括中间文件夹(obj)和最终输出文件夹(bin)中的文件


dotnet sln


使用dotnet sln命令,可以在*.sln,文件中添加,删除,获取项目。

dotnet sln [<solution_name>] add <project> <project>
dotnet sln [<solution_name>] add <globbing_pattern>
dotnet sln [<solution_name>] remove <project> <project>
dotnet sln [<solution_name>] remove <globbing_pattern>
dotnet sln [<solution_name>] list

注意:dotnet sln命令只会对solution_name.sln文件中操作,要生成*.sln文件,可以使用dotnet new sln命令


dotnet add/remove/list reference


管理项目之间的引用关系

# 项目1引用项目2
[zebra work]$dotnet add 项目1 reference 项目2



三 MSBuild

MSBuild 是 Microsoft Build Engine 的缩写,MSBuild 是 Visual Studio 的生成系统。我们在VS中使用“生成解决方案”的背后就是依赖MSBuild来实现,但我们完全可以在cmd中使用MSBuild来完成应用的构建。

它不仅仅是一个构造工具,应该称之为拥有相当强大扩展能力的自动化平台。MSBuild平台的主要涉及到三部分:执行引擎、构造工程、任务。其中最核心的就是执行引擎,它包括定义构造工程的规范,解释构造工程,执行“构造动作”;构造工程是用来描述构造任务的,大多数情况下我们使用MSBuild就是遵循规范,编写一个构造工程;MSBuild引擎执行的每一个“构造动作”就是通过任务实现的,任务就是MSBuild的扩展机制,通过编写新的任务就能够不断扩充MSBuild的执行能力。所以这三部分分别代表了引擎、脚本和扩展能力。

MSBuild 引入了一种新的基于 XML 的项目文件格式,这种格式容易理解、易于扩展并且完全受 Microsoft 支持。MSBuild 项目文件的格式使开发人员能够充分描述哪些项需要生成,以及如何利用不同的平台和配置生成这些项。另外,项目文件的格式还使开发人员能够创作可重用的生成规则,这些规则可以分解到不同的文件中,以便可以在产品内的不同项目之间一致地执行生成。以下各节描述了 MSBuild 项目文件格式的一些基本要素。



四 发布



1 ASP.NET Core Web Api发布到Linux(CentOS 7 64)

在Linux上安装需要的环境,然后将上面成功运行的项目发布:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

将文件夹拷贝到linux下,进入文件夹运行:

dotnet WebApplication1.dll



2 linux下ASP.Net core打包docker镜像

在上面发布的core2.2版本文件夹下面创建名称为

Dockerfile

的文件,内容:

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2
EXPOSE 8080

WORKDIR /app
COPY . /app
ENTRYPOINT ["dotnet", "WebApplication1.dll"]

对于core3版本:

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
COPY . /app
ENTRYPOINT ["dotnet", "demoapi.dll"]

FROM是指定该镜像的运行环境;然后指定容器映射端口8080;最后dotnet运行项目。

把目录文件通过dockerfile加载到docker镜像:

docker build -t gateway:1.0 .



调用命令 docker images 会发现已经有这个镜像了。

在这里插入图片描述

最后,运行镜像:

docker run -p 8080:8080 testsite:1.0

(8080:8080表示的是容器内端口映射容器外端口)。



3 vs2019创建docker支持

选中”启用Docker支持“,这样可以自动生成Dockerfile文件,这个文件是用来生成Docker镜像;如果没有选中”启用Docker支持“,也可在项目生成后,右击项目-添加-Docke支持;

选择Docker运行系统,代码编写阶段Dockerfile文件可以随意修改和删除,使用Docker调试或生成镜像时重新添加一个就行了。

在这里插入图片描述

生成了Dockerfile文件。生成的内容一大堆,在不修改情况下使用VS自带的Docker运行没有问题,但部署时却有麻烦,简化一下就行了;

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
COPY . .
ENTRYPOINT ["dotnet", "SamruoFrame.Service.Cache.Redis.dll"]

Dockerfile文件默认在发布时不会复制到发布文件夹中,属性修改为:始终复制。



4 编辑程序并生成镜像

程序以正常发布生成,使用”文件夹”模式,以上几个发布方式需要Azure,本文不涉及此内容(主要是没钱)

在这里插入图片描述

生成镜像有多种方式,我使用本地生成;进入发布目录,运行Powershell,使用命令行生成镜像

docker build -t samruo/redis:1.1 .

//语法:docker build [OPTIONS] PATH | URL | -
//--tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签。
//需要注意的是 1:name不能用大写;2:语句最后必须加“ .” 且前面要有一个空格。

在这里插入图片描述

这里出现了一个错误信息:

SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have ‘-rwxr-xr-x’ permissions. It is recommended to double check and reset permissions for sensitive files and directories.

经查是因为我在Windows下生成,但将使用在Linux下,所以有个目录权限问题。考虑到我的程序只用来做服务,且采用集群,不会在本地保存文件,理论上不会有此问题,就先使用这个方法。



5 将镜像放到阿里仓库

为方便集群化部署,以及后继运维方便,将镜像放到仓库中是个好办法。实现Docker仓库的方法有很多,国内和国外都的,Docker Hub速度太慢,我使用阿里的镜像仓库,因为本身服务器是在阿里云。

首先要有个阿里云帐号;登录后进入控制台,搜索”容器镜像服务“,首次使用需要开通服务,根据阿里云的使用经验,貌似使用容器镜像服务免费,还有个”弹性容器实例ECI“是需要收费的,其实就是个Docker,按秒计费的。

第一步:创建命名空间

在这里插入图片描述

第二步:创建镜像仓库

在这里插入图片描述

仓库创建后,点击仓库名称进入详情页

在这里插入图片描述



6 上传镜像和版本更新

1、 登录阿里云Docker Registry

sudo docker login --username=【这里是阿里云登录帐号】 registry.cn-hangzhou.aliyuncs.com

在这里插入图片描述

2、将镜像推送到Registry

sudo docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/samruo_docker/redis:[镜像版本号]
sudo docker push registry.cn-hangzhou.aliyuncs.com/samruo_docker/redis:[镜像版本号]

正确执行命令后,镜像将出现在”镜像版本“之中;

在这里插入图片描述

版本更新只需要修改命令行后面的”镜像版本号“即可,非常简单。到此,镜像仓库部署完成。



7 在Linux的Docker中使用镜像

建立了镜像后在部署操作将非常简单。执行以下命令前需要执行登录操作,见上节上传镜像,如已登录则无需执行。

//从Registry中拉取镜像,在一台服务器中,同一个版本的镜像只需要拉取一次即可
docker pull registry.cn-hangzhou.aliyuncs.com/samruo_docker/redis:[镜像版本号]

在这里插入图片描述

//部署镜像
//语法:docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

 docker run --name samruo-redis-1 -d -p 5902:80 registry.cn-hangzhou.aliyuncs.com/samruo_docker/redis:1.1

// --name="nginx-lb": 为容器指定一个名称;
// -d: 后台运行容器,并返回容器ID;
// -p: 指定端口映射,格式为:主机(宿主)端口:容器端口;这里和80端口与Dockerfile文件中的EXPOSE 80对应;

在这里插入图片描述

在同一台宿主服务器上只要”主机(宿主)端口“不重复,可以部署多个同一镜像,不会相互干扰,这也将用于集群化需求。成功执行后将只返回容器ID;

查看镜像部署情况:

docker ps -a



在这里插入图片描述



8 使用VS2019发布镜像到Docker仓库

1.Dockerfile完全不需要修改,可保持自动创建时的内容.EXPOSE可根据开放端口不同,自行调整.

2.使用”发布”->“容器注册表”:首次发布需要创建发布模板,如下:

在这里插入图片描述

在下图中填写阿里容器仓库地址:

格式为:https://服务区域地址/命名空间 (具体见自己开通仓库的公网地址)

注意不要填写仓库名称,仓库名称VS将自动补充,也就是项目名称,这也是唯一于手工上传相比不可控之处.

填写用户名和密码,好像没什么用,最好在上传时,以代码登录一下.见以下内容.

在这里插入图片描述

保存后分发镜像模板就完成了,以后只要点击发布就能自动上传到私有仓库中.

在这里插入图片描述

每次发布镜像最好区分版本号,见上图”图像标记”(话说这翻译也是够直接),修改上图所未标记后,点击”发布”即可.

VS自动创建的Dockerfile文件有20行,发布需要点时间,这时可以打开PowerShell 运行 登录阿里云Docker Registry命令:

$ sudo docker login --username=[阿里帐号] registry.cn-hangzhou.aliyuncs.com



我这里执行手动登录的原因,是遇到发布时提示帐号验证错误,应该是VS调用本地Docker Desktop来执行上传,但Docker Desktop本身未登录,所以会执行出错.

好了,现在每次发布新的版本只需要点一下”发布”并修改一下版本号,就可以方便的更新程序镜像了。



9 串口映射到docker

将物理机的串口映射到容器中去:

docker run --rm -it --device /dev/ttyS1:/dev/ttyS0 ubuntu:14.04 /bin/sh


将物理机的串口映射到Web镜像容器中去:

docker run --rm -it --device /dev/ttyS1:/dev/ttyS0 -p 9600:9694 gateway:1.0



10 外部访问

public static IHostBuilder CreateHostBuilder(string[] args) =>
     Host.CreateDefaultBuilder(args)
         .ConfigureWebHostDefaults(webBuilder =>
         {
             webBuilder
             .UseUrls("http://*:5000")  // 所有IP
             .UseStartup<Startup>();
         });

关闭防火墙。



五 Centos环境配置



1 centos7的virbr0问题

ifconfig virbr0 down
brctl delbr virbr0
systemctl disable libvirtd.service



2 net模式下自动获取IP地址

cd /etc/sysconfig/network-scripts
vim ifcfg-ens33

在这里插入图片描述



3 解决虚拟机复制粘贴不能用的问题

报错信息如下:

Error when getting information for file “//tmp/VMwareDnD/p6v6B6/.”: No such file or directory



1、卸载预装的“open-vm-tools”包,检测是否预装了

open-vm-tools



yum list installed | grep open-vm-*



2、卸载预装的程序包:

yum remove open-vm-tools



3、再次确认是否卸载成功:

rpm -qa | grep open-vm-*



4、重启虚拟机:

reboot



5、安装 VMware Tools:

sudo ./vmware-install.pl

,前置条件检测时,因为我们之前卸载了预装的open-vm-tools依赖包,所以这里会提示不继续安装,不要管它,输入“yes”继续执行安装,接下来的选项基本都是默认一路回车即可。

6、open-vm-tools:

yum install open-vm-tools -y



7、重启。



4 安装包配置

离线情况下,直接使用rpm包;

sudo rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm



5 安装 SDK

[root@test src]#mkdir -p /usr/local/dotnetcore
[root@test src]#tar -zxf dotnet-sdk-6.0.201-linux-x64.tar.gz -C /usr/local/dotnetcore
[root@test src]# vi /etc/profile
增加以下几行
#set dotnet core
export DOTNET_ROOT=/usr/local/dotnetcore
export PATH=$PATH:$DOTNET_ROOT
#生效环境变量
[root@test src]#source /etc/profile



六 get和post接口



1 Get参数接受

1、基础类型接收参数

namespace App.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class HomeController : ControllerBase
    {
        [HttpGet]
        public string Get(string name, string gender, int age)
        {
            return $"姓名:{name}\n性别:{gender}\n年龄:{age}";
        }
    }
}

2、实体类型接收参数

namespace App.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class HomeController : ControllerBase
    {
        [HttpGet]
        public string Get([FromQuery] Person person)
        {
            return $"姓名:{person.Name}\n性别:{person.Gender}\n年龄:{person.Age}";
        }
    }
}



2 post方式可以直接括号内接受参数

在.NetCore WebApi中,Post方式的api接收参数时不能像Get那些,直接把接受参数写到方法后边括号内,如:

[HttpPost]
public string GetAreaGroupList(string id){
   return id;
}

这个是因为api默认推理规则,绑定源推理,借助这些规则,无需通过将属性应用于操作参数来手动识别绑定源,其中几种规则为

[FromBody]针对复杂类型参数进行推断。但其不适用于具有特殊含义的任何复杂的内置类型,如IFormCollection和CancellationToken。

[FromForm]针对IFormFile和IFormFileCollection类型的操作参数进行推断。

[FromRoute]针对与路由模板中的参数相匹配的任何操作参数名称进行推断。

[FromQuery]针对任何其他操作参数进行推断。

但是有时不想这么复杂编写api,只想在括号内一个一个写接受参数,那就把默认推理规则关掉就好了。

.NetCore中禁用api推理规则,在Startup.cs ConfigureServices中这样写:

services.AddControllers(cfg => { cfg.Filters.Add(new ExceptionHandleAttribute()); })
    .ConfigureApiBehaviorOptions(options =>
    {
        //options.SuppressConsumesConstraintForFormFileParameters = true;//禁用当[FromForm]属性批注时,推理multipart/form-data请求内容类型
        options.SuppressInferBindingSourcesForParameters = true;//禁用api的推理规则,这样就支持post方式直接括号接受参数和model参数方式
    });



3 获取请求body


https://blog.csdn.net/WuLex/article/details/122249541



4 参数传递接受


https://blog.csdn.net/qq_18932003/article/details/119967284



5 控制器与方法返回输出

asp.net core有三种返回 数据 和 HTTP状态码 的方式,最简单的就是直接返回指定的类型实例,如下:

public IEnumerable<WeatherForecast> Get()
{
}

除了这种,也可以返回

IActionResult

实例和

ActionResult

实例。

返回指定的类型只能返回数据,附带不了http状态码,而 IActionResult 实例可以将数据 + Http状态码 一同带给前端,最后就是 ActionResult 它封装了前面两者,可以实现两种模式的自由切换。

在 Action 中返回 IActionResult 实例

如果你要返回 data + httpcode 的双重需求,那么 IActionResult 就是你要找的东西,下面的代码片段展示了如何去实现。

[HttpGet]
public IActionResult Get()
{
  if (authors == null)
      return NotFound("No records");

  return Ok(authors);
}

上面的代码有 Ok,NotFound 两个方法,对应着 OKResult,NotFoundResult, Http Code 对应着 200,404。当然还有其他的如:CreatedResult, NoContentResult, BadRequestResult, UnauthorizedResult, 和 UnsupportedMediaTypeResult,都是 IActionResult 的子类。

在 Action 中返回 ActionResult 实例

ActionResult 是在 ASP.NET Core 2.1 中被引入的,它的作用就是包装了前面这种模式,怎么理解呢? 就是即可以返回 IActionResult ,也可以返回指定类型,从 ActionResult 类下的两个构造函数中就可以看的出来。

public sealed class ActionResult<TValue> : IConvertToActionResult
{
    public ActionResult Result  {get;}

    public TValue Value  {get;}

    public ActionResult(TValue value)
    {
        if (typeof(IActionResult).IsAssignableFrom(typeof(TValue)))
        {
            throw new ArgumentException(Resources.FormatInvalidTypeTForActionResultOfT(typeof(TValue), "ActionResult<T>"));
        }
        Value = value;
    }

    public ActionResult(ActionResult result)
    {
        if (typeof(IActionResult).IsAssignableFrom(typeof(TValue)))
        {
            throw new ArgumentException(Resources.FormatInvalidTypeTForActionResultOfT(typeof(TValue), "ActionResult<T>"));
        }
        Result = (result ?? throw new ArgumentNullException("result"));
    }
}

有了这个基础,接下来看看如何在 Action 方法中去接这两种类型。

[HttpGet]
public ActionResult<IEnumerable<Author>> Get()
{
  if (authors == null)
       return NotFound("No records");
   return authors;
}

和文章之前的 Get 方法相比,这里直接返回 authors 而不需要再用 OK(authors) 包装,是不是一个非常好的简化呢? 接下来再把 Get 方法异步化,首先考虑下面返回 authors 集合的异步方法。

private async Task<List<Author>> GetAuthors()
{
    await Task.Delay(100).ConfigureAwait(false);
    return authors;
}

值得注意的是,异步方法必须要有至少一个 await 语句,如果不这样做的话,编译器会提示一个警告错误,告知你这个方法将会被 同步执行,为了避免出现这种尴尬,我在 Task.Delay 上做了一个 await。

下面就是更新后的 Get 方法,注意一下这里我用了 await 去调用刚才创建的异步方法,代码参考如下

[HttpGet]
public async Task<ActionResult<IEnumerable<Author>>> Get()
{
   var data = await GetAuthors();
   if (data == null)
        return NotFound("No record");
   return data;
}

如果你有一些定制化需求,可以实现一个自定义的 ActionResult 类,做法就是实现 IActionResult 中的 ExecuteResultAsync 方法即可。


https://www.cnblogs.com/jcsoft/p/12222527.html



https://blog.csdn.net/wojiuguowei/article/details/123968155



6 路由模板


https://www.cnblogs.com/zhan520g/p/10303225.html



版权声明:本文为essity原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。