5

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

 3 years ago
source link: https://mp.weixin.qq.com/s?__biz=MjM5MjQwMDUzMw%3D%3D&%3Bmid=2247484211&%3Bidx=1&%3Bsn=7f45ac248b23c31e5088f64e98b70257
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

前几天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 。不用太纠结,微软的命名规则而已。

这就是控制台应用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应用

需要注入 AddControllersMapControllers

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应用

需要注入 AddRazorPagesMapRazorPages

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

喜欢就来个三连,让更多人因你而受益


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK