程序地带

深入浅出Dotnet Core的项目结构变化


有时候,越是基础的东西,越是有人不明白。



前几天Review一个项目的代码,发现非常基础的内容,也会有人理解出错。


今天,就着这个点,写一下Dotnet Core的主要类型的项目结构,以及之间的转换和演化。


一、最基础的应用Console

控制台应用,是Dotnet Core乃至前边的Dotnet Framework中,最基础的项目。


我们来创建一个Console项目看一下:


% dotnet new console -o demo

创建完成后,打开工程。工程里只有一个文件Program.cs,里面只有一个方法Main:


namespace demo
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}

在Dotnet Core所有类型的项目中,Program.cs都是最开始的入口,main方法,也是最开始的入口方法。



这个工程中,还有一个文件也需要了解一下,demo.csproj,这是这个项目的定义文件:


<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
</Project>

这里面,OutputType告诉编辑器这个工程编译后可以直接执行,TargetFramework定义运行的框架。


注意,这个框架字串有个对照表:net5.0对应的是.Net 5.0;如果你想用Dotnet Core 3.1,对应的字符串是netcoreapp3.1,而不是net3.1。准确的说,3.1是.Net Core 3.1,而5.0是.Net 5.0。不用太纠结,微软的命名规则而已。


    为了防止不提供原网址的转载,特在这里加上原文链接:https://www.cnblogs.com/tiger-wang/p/14267942.html



这就是控制台应用Console的初始状态。


下面,我们看看这个工程如何转变为Web应用。


二、转为Web应用

第一件事,我们需要改动demo.csproj项目定义文件。


Web应用跑在WebHost上面,而不是从直接执行。所以,我们需要把OutputType项去掉。


另外,SDK也需要改一下。Console我们用的是Microsoft.NET.Sdk,Web应用要改成Microsoft.NET.Sdk.Web:


<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
</Project>

改完保存。


这时候,应该可以注意到,项目的发生了变化:


依赖的框架从Microsoft.NETCore.App变成了两个,多了一个Microsoft.AspNetCore.App,表明现在这是一个Asp.net Core的应用;
项目中自动生成了一个目录Properties,下面多了一个文件launchSettings.json。这个文件大家应该很熟悉,就不解释了。

这时候,应用已经从Console转为了Web应用。



Asp.Net Core框架提供了Host供Web加载。我们需要做的,是把Host构建器加到程序中。通常,我们需要两个构建器:


通用主机 Generic host builder
Web主机 Web host builder


1. 配置通用主机

通用主机在Microsoft.Extensions.Hosting.Host中,主要给Web应用提供以下功能:


依赖注入
日志
配置 IConfiguration
IHostedService实现

加入通用主机很简单,就一个方法CreateDefaultBuilder:


class Program
{
static void Main(string[] args)
{
Host.CreateDefaultBuilder(args)
.Build()
.Run();
}
}
2. 配置Web主机

Web主机才是真正与Web相关的内容,主要实现:


Http支持
设置Kestrol服务器为Web服务器
添加IIS支持

加入Web主机,也是一个方法ConfigureWebHostDefaults:


class Program
{
static void Main(string[] args)
{
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
})
.Build()
.Run();
}
}

这个方法用来添加Http请求管道并注入我们需要的服务。而注入我们需要的服务,就是我们最常见的Startup.cs的内容。



下面,我们先创建Startup.cs,


namespace demo
{
public class Startup
{
}
}

在前边ConfigureWebHostDefaults中,加入Startup,并补齐代码:


class Program
{
static void Main(string[] args)
{
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.Build()
.Run();
}
}


这就是Program.cs中的完整代码了。整理一下,就是我们常见的样子:


public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}

不过,到这儿还不能正常运行,因为Startup.cs现在还是空的。


3. 补齐Startup类

Startup类在Asp.net Core应用中有着重要的作用。这个类用于:


使用DI容器注入服务
设置Http Request管道以插入中间件


下面我们补齐所需的方法:


namespace demo
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
}
}
}

运行,到这儿,Web应用已经可以正常启动了。


4. 给应用添加路由

Web应用启动了,但里面什么也没有,是空的。


要访问Web应用中的任何资源,需要配置路由。这儿的路由,基本上就是传入Http请求与资源之间的映射。


我们可以用下面的中间件来启动路由:


UseRouting
UseEndpoints

加一下试试:


public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(endpoint => {
endpoint.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello from Demo");
});
});
}

这次运行,浏览器中就看到正确的输出了。


我们可以用MapGet映射更多资源:


public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(endpoint =>
{
endpoint.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello from Demo");
});
endpoint.MapGet("/test", async context =>
{
await context.Response.WriteAsync("Hello from Demo.Test");
});
endpoint.MapGet("/about", async context =>
{
await context.Response.WriteAsync("Hello from Demo.About");
});
});
}


到这儿,我们成功地把Console应用转为了Web应用。


三、延伸内容

上面完成的Web应用,算是Web应用中的基础。基于这个内容,我们还可以扩展到别的项目结构。


1. 改为MVC应用

需要在ConfigureServices 中注入AddControllersWithViews,并在Configure中添加MapDefaultControllerRoute:


public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(endpoint =>
{
endpoint.MapDefaultControllerRoute();
});
}
}
2. 改为WebAPI应用

需要注入AddControllers和MapControllers:


public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(endpoint =>
{
endpoint.MapControllers();
});
}
}
3. 改为Razor应用

需要注入AddRazorPages和MapRazorPages:


public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(endpoint =>
{
endpoint.MapRazorPages();
});
}
}
四、总结

看下来,其实过程很简单。通过这种方式,能更进一步理解Dotnet Core的项目结构以及应用的运行过程。


希望对大家能有所帮助。



本文的配套代码在:https://github.com/humornif/Demo-Code/tree/master/0038/demo




微信公众号:老王Plus


扫描二维码,关注个人公众号,可以第一时间得到最新的个人文章和内容推送


本文版权归作者所有,转载请保留此声明和原文链接


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/tiger-wang/p/14267942.html

随机推荐

操作系统课设——吃水果问题

问题描述:桌上有一盘子,桌上有一个空盘,允许存放一只水果,爸爸可向盘内放苹果,妈妈可向盘内放桔子,儿子专等吃盘内的桔...

8年而止,一切重来 阅读(487)

安装pyinstaller库

cmd命令:pipinstallpyinstaller出现以下情况:嗯,失败!~~~~后百度说:python-mpipinstal...

chinaherolts2008 阅读(651)

pagefooter如何不占位置_按钮位置的率先加注技巧

现在我们来讨论——当你在按钮位置,前面玩家都弃牌,你该如何游戏——因为这是扑克中的最重要场合之一。以下是我的按钮位置率先加注范围:表1:按钮位置...

weixin_39618730 阅读(957)

CAN过滤器

CAN过滤器1、配置过滤器必须使过滤器组工作在初始化模式,配置完成后进入正常模式CAN1->FMR|=1<<0;//过滤器组0工作在初始化模式//CAN1-&g...

物极必反1024 阅读(456)

Java学习路线及目标

 本文将告诉你学习Java的路线及要达成的目标,学习过程中可能遇到各种问题,希望对你有所帮助。对比一下自己,看看自己已经掌握了哪一些,在学习过程...

Martin编程 阅读(394)

gradle本地仓库设置

gradle本地仓库设置下载安装:配置环境gradle使用maven本地仓库全局设置创建init.gradle文件init.gradle文件的使用单个项目设置:build....

itchun 阅读(507)