ASP.NET CORE

ASP.NET Core 是一个新的开源和跨平台的框架,用于构建如 Web 应用、物联网(IoT)应用和移动后端应用等连接到互联网的基于云的现代应用程序。ASP.NET Core 应用可运行于 .NET Core 和完整的 .NET Framework 之上。 构建它的目的是为那些部署在云端或者内部运行(on-premises)的应用提供一个优化的开发框架。它由最小开销的模块化的组件构成,因此在构建你的解决方案的同时可以保持灵活性。你可以在 Windows、Mac 和 Linux 上跨平台的开发和运行你的 ASP.NET Core 应用。 ASP.NET Core 开源在 GitHub 上。

C#新特性

这里记录下在C#6.0和C#7.0下常用的一些新特性

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static System.Math;//静态导入 static 类

namespace Ruanmou.Core.ConsoleProject
{
    /// <summary>
    /// C#6 新语法
    /// </summary>
    public class SharpSix
    {
        #region 自动属性初始化(Auto-property initializers)
        public string Name { get; set; } = "summit";
        public int Age { get; set; } = 22;
        public DateTime BirthDay { get; set; } = DateTime.Now.AddYears(-20);
        public IList<int> AgeList
        {
            get;
            set;
        } = new List<int> { 10, 20, 30, 40, 50 };
        #endregion

        public void Show(People peopleTest)
        {
            #region 字符串嵌入值(String interpolation)
            Console.WriteLine($"年龄:{this.Age}  生日:{this.BirthDay.ToString("yyyy-MM-dd")}");
            Console.WriteLine($"年龄:{{{this.Age}}}  生日:{{{this.BirthDay.ToString("yyyy -MM-dd")}}}");

            Console.WriteLine($"{(this.Age <= 22 ? "小鲜肉" : "老鲜肉")}");
            #endregion

            #region 导入静态类(Using Static)
            Console.WriteLine($"之前的使用方式: {Math.Pow(4, 2)}");
            Console.WriteLine($"导入后可直接使用方法: {Pow(4, 2)}");
            #endregion

            #region 空值运算符(Null-conditional operators)
            int? iValue = 10;
            Console.WriteLine(iValue?.ToString());//不需要判断是否为空
            string name = null;
            Console.WriteLine(name?.ToString());
            #endregion

            #region 对象初始化器(Index Initializers)
            IDictionary<int, string> dictOld = new Dictionary<int, string>()
            {
                { 1,"first"},
                { 2,"second"}
            };

            IDictionary<int, string> dictNew = new Dictionary<int, string>()
            {
                [4] = "first",
                [5] = "second"
            };

            #endregion

            #region nameof表达式 (nameof expressions)
            Console.WriteLine(nameof(peopleTest)); //获取peopleTest这个字符串
            #endregion
        }

        #region 在属性/方法里使用Lambda表达式(Expression bodies on property-like function members)
        public string NameFormat => string.Format("姓名: {0}", "summit");
        public void Print() => Console.WriteLine(Name);
        #endregion
    }
}

using System;
using System.Collections.Generic;
using System.Text;

namespace Ruanmou.Core.ConsoleProject
{
    /// <summary>
    /// c#7新语法
    /// </summary>
    public class SharpSeven
    {
        public void Show()
        {
            #region out参数
            {
                this.DoNoting(out int x, out int y);
                Console.WriteLine(x + y);

                this.DoNoting(out var l, out var m);

            }
            //Console.WriteLine(x + y);
            #endregion

            #region 模式
            this.PrintStars(null);
            this.PrintStars(3);

            this.Switch(null);
            this.Switch("ElevenEleven");
            this.Switch("Eleven");
            #endregion

            #region 元组
            {
                var result = this.LookupName(1);
                Console.WriteLine(result.Item1);
                Console.WriteLine(result.Item2);
                Console.WriteLine(result.Item3);
            }
            #endregion

            #region 局部函数
            {
                Add(3);
                int Add(int k)//闭合范围内的参数和局部变量在局部函数的内部是可用的,就如同它们在 lambda 表达式中一样。
                {
                    return 3 + k;
                }
            }
            #endregion

            #region 数字分隔号
            long big = 100_000;
            #endregion

        }

        /// <summary>
        /// System.ValueTuple 需要安装这个nuget包
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        private (string, string, string) LookupName(long id) // tuple return type
        {
            return ("first", "middle", "last");
        }

        /// <summary>
        /// 具有模式的 IS 表达式
        /// </summary>
        /// <param name="o"></param>
        public void PrintStars(object o)
        {
            if (o is null) return;     // 常量模式 "null"
            if (!(o is int i)) return; // 类型模式 定义了一个变量 "int i"
            Console.WriteLine(new string(‘*‘, i));
        }

        /// <summary>
        /// 可以设定任何类型的 Switch 语句(不只是原始类型)
        /// 模式可以用在 case 语句中
        /// Case 语句可以有特殊的条件
        /// </summary>
        /// <param name="text"></param>
        private void Switch(string text)
        {
            int k = 100;
            switch (text)
            {
                case "ElevenEleven" when k > 10:
                    Console.WriteLine("ElevenEleven");
                    break;
                case "Eleven" when text.Length < 10:
                    Console.WriteLine("ElevenEleven");
                    break;
                case string s when s.Length > 7://模式
                    Console.WriteLine(s);
                    break;
                default:
                    Console.WriteLine("default");
                    break;
                case null:
                    Console.WriteLine("null");
                    break;
            }
        }

        private void DoNoting(out int x, out int y)
        {
            x = 1;
            y = 2;
        }
    }
}

应用程序剖析

一个 ASP.NET Core 应用其实就是一个在其 Main 方法中创建一个 web 服务器的简单控制台应用程序:

using System;
using Microsoft.AspNetCore.Hosting;

namespace aspnetcoreapp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseKestrel()
                .UseStartup<Startup>()
                .Build();

            host.Run();
        }
    }
}

Main 调用遵循 builder 模式的 WebHostBuilder ,用于创建一个 web 应用程序宿主。这个 builder 有些用于定义 web 服务器 (如 UseKestrel)和 startup 类型( UseStartup)的方法。在上面的示例中,web 服务器 Kestrel 被启用,但是你也可以指定其它 web 服务器。
WebHostBuilder 提供了一些可选方法,其中包括寄宿在 IIS 和 IIS Express 中的 UseIISIntegration 和用于指定根内容目录的 UseContentRoot。Build 和 Run 方法构建了用于宿主应用程序的 IWebHost 然后启动它来监听传入的 HTTP 请求。

Startup

WebHostBuilder 的 UseStartup 方法为你的应用指定了 Startup 类。
Startup 类是用来定义请求处理管道和配置应用需要的服务。 Startup 类必须是公开的(public)并且包含如下方法:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
    }

    public void Configure(IApplicationBuilder app)
    {
    }
}

ConfigureServices 定义你的应用所使用的服务(例如 ASP.NET MVC Core framework、Entity Framework Core、Identity 等等)
Configure 定义你的请求管道中的 中间件(middleware)

服务(Services)

服务是应用中用于通用调用的组件。服务通过依赖注入获取并使用。 ASP.NET Core 内置了一个简单的控制反转(IoC) 容器,它默认支持构造器注入,并且可以方便的替换成你自己选用的 IoC 容器。由于它的松耦合特性,依赖注入(DI) 使服务在整个应用中都可以使用。例如,Logging 在你整个应用中都可用。查看 Dependency Injection 获取更多信息。

中间件(Middleware)

在 ASP.NET Core 中,你可以使用 Middleware 构建你的请求处理管道。 ASP.NET Core 中间件为一个 HttpContext 执行异步逻辑,然后按顺序调用下一个中间件或者直接终止请求。一般来说你要使用一个中间件,只需要在 Configure 方法里调用 IApplicationBuilder 上一个对应的 UseXYZ 扩展方法。

ASP.NET Core 带来了丰富的内置中间件:

  • 静态文件(Static files)
  • 路由(Routing)
  • 身份验证(Authentication)
    你也可以创建你自己的自定义中间件。

你也可以在 ASP.NET Core 中使用任何基于 OWIN 的中间件。

服务器(Servers)

ASP.NET Core 托管模式并不直接监听请求;而是依赖于一个 HTTP server 实现来转发请求到应用程序。这个被转发的请求会以一组 feature 接口的形式被包装,然后被应用程序组合到一个 HttpContext中去。 ASP.NET Core 包含了一个托管的跨平台 web 服务器,被称为 Kestrel,它往往会被运行在一个如 IIS 或者 nginx 的生产 web 服务器之后。

内容根目录(Content root)

内容根目录是应用程序所用到的所有内容的根路径,例如它的 views 和 web 内容。内容根目录默认与宿主应用的可执行程序的应用根目录相同;一个替代的地址可以通过 WebHostBuilder 来设置。

Web根目录(Web root)

你的应用的Web根目录(Web root)是你项目中所有公共的、静态的资源,如 css、js 和 图片文件的目录。静态文件中间件将默认只发布 Web 根目录(Web root)和其子目录中的文件。 Web 根目录(Web root)默认为 /wwwroot,但是你也可以通过 WebHostBuilder 来指定另外一个地址。

配置(Configuration)

ASP.NET Core 使用了一个新的配置模型用于处理简单的键值对。新的配置模型并非基于System.Configuration 或者 web.config ;而是从一个有序的配置提供者集合拉取数据。内置的配置提供者支持多种不同的文件格式如(XML,JSON, INI)和用于支持基于环境的配置环境变量。
默认的MVC项目是通过 Asp.net Core 预制的"空"模板创建的,项目中已经有一个 appsettings.json 的文件了。 我们可以对文件补充键值对,在StartUp类,Configure方法中就可以直接读取配置。

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory factory)
{
    #region 配置文件的读取
    //xml path
    Console.WriteLine($"option1 = {this.Configuration["Option1"]}");
    Console.WriteLine($"option2 = {this.Configuration["option2"]}");
    Console.WriteLine(
        $"suboption1 = {this.Configuration["subsection:suboption1"]}");
    Console.WriteLine("Wizards:");
    Console.Write($"{this.Configuration["wizards:0:Name"]}, ");
    Console.WriteLine($"age {this.Configuration["wizards:0:Age"]}");
    Console.Write($"{this.Configuration["wizards:1:Name"]}, ");
    Console.WriteLine($"age {this.Configuration["wizards:1:Age"]}");
    #endregion
}

依赖注入

在.NET Core中DI的核心分为两个组件:IServiceCollection和 IServiceProvider。
IServiceCollection 负责注册;IServiceProvider 负责提供实例。通过默认的 ServiceCollection(在Microsoft.Extensions.DependencyInjection命名空间下)有三个方法:

var serviceCollection = new ServiceCollection()
  .AddTransient<ILoginService, EFLoginService>()
  .AddSingleton<ILoginService, EFLoginService>()
  .AddScoped<ILoginService, EFLoginService>();

对应的实例生命周其包括三种:
Transient: 每一次GetService都会创建一个新的实例
Scoped: 在同一个Scope内只初始化一个实例 ,可以理解为( 每一个request级别只创建一个实例,同一个http request会在一个 scope内)
Singleton :整个应用程序生命周期以内只创建一个实例

ASP.NET Core可以在Startup.cs的 ConfigureService中配置DI,大家看到 IServiceCollection这个参数应该就比较熟悉了。

Controller中使用时,一般可以通过构造函数或者属性来实现注入,但是官方推荐是通过构造函数。这也是所谓的显式依赖。

private ILoginService<ApplicationUser> _loginService;
public AccountController(
  ILoginService<ApplicationUser> loginService)
{
  _loginService = loginService;
}

参考:
ASP.NET Core 介绍
解读ASP.NET 5 & MVC6系列(7):依赖注入
全面理解 ASP.NET Core 依赖注入

ASP.NET CORE

上一篇:JS开发技巧:惰性加载函数


下一篇:Easyexcel2.2.6遇到 class net.sf.cglib.core.DebuggingClassWriter has interface org.objectweb.asm.ClassVisitor as super class的问题