.net core

2021/6/28 6:21:24

本文主要是介绍.net core,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

https://source.dot.net/

依赖注入框架(核心对象):

 

IOC(控制反转)容器

  1. 映射依赖,注册类型,注册服务
  2. 实例解析

 

举例:5岁小朋友需要吃食物

两种:

主动 自己动手  正转

被动,找父母   反转  对食物的控制权

 

需要类型的实例

依赖注入,是实现控制反转的一种方式

通过 依赖注入 实现控制反转

父母(第三方)食物(依赖)那给你(注入)

抽象==接口=服务

发消息(接口)=短信

发消息(接口)=微信

 

工厂模式==IOC

.net core  基础类库  扩展类库

Asp.net core web开发平台

 

.netcore 原生DI

需要引入

microsoft.extensions.dependencyinjection

microsoft.extensions.dependencyinjection.abstractions

有两个的原因 是设计上的 抽象和实现的分离  基础类型在abstractions

如果自己要做扩展,最小依赖原则,只需要引入:microsoft.extensions.dependencyinjection.abstractions

其他的中间件 类似的做法

我们添加的对象是保存在ServiceCollection 对象中 本质是个集合

添加后返回的是一个 ServiceProvider 称之为是服务提供对象

 

  var provider = new ServiceCollection()

                .AddTransient<IAccount, Account>()

                .AddScoped<IMessage, Message>()

                .AddSingleton<ITool, Tool>()

           .AddTransient Account>()//也可以这样

 

                .BuildServiceProvider();

 

provider  代表依赖注入的容器对象

一般来注册都是依赖接口的方式

Debug.Assert(provider.GetService<ITool>() is Tool);

GetService 只能获得一个对象

GetServices 可以一次获得多个

 

var services = new ServiceCollection()

                .AddTransient<Base, Account>()

                .AddTransient<Base, Message>()

                .AddTransient<Base, Tool>()

                .BuildServiceProvider()

                .GetServices<Base>().ToList();

 

 

            Debug.Assert(services.OfType<Account>().Any());

            Debug.Assert(services.OfType<Message>().Any());

单例的服务实例-保存在根容器

作用域模式   当前容器

瞬时  不保存

 

可以有子容器

 

谁负责创建 谁负责销毁

 

using (var root = new ServiceCollection()

                .AddTransient<IAccount, Account>()

                .AddScoped<IMessage, Message>()

                .AddSingleton<ITool, Tool>()

                .BuildServiceProvider())

            {

                using (var scope = root.CreateScope())

                {

                    var child = scope.ServiceProvider;

                    child.GetService<IAccount>();

                    child.GetService<IMessage>();

                    child.GetService<ITool>();

                    Console.WriteLine("释放子容器");

                }

                Console.WriteLine("释放根容器");

            }

作用域

 

  public Test(IAccount account)

            {

                Console.WriteLine($"Ctor:Test(IAccount)");

            }

 

            public Test(IAccount account, IMessage message)

            {

                Console.WriteLine($"Ctor:Test(IAccount,IMessage)");

            }

  var test = new ServiceCollection()

                .AddTransient<IAccount, Account>()

                .AddTransient<IMessage, Message>()

                .AddTransient<ITest, Test>()

                .BuildServiceProvider()

                .GetService<ITest>();

 

如果某个构造函数的参数能成为其他构造函数的超级,构造函数会选择,若是都有两个,都不能成为超级则 程序会不发选择,而异常

 

服务范围

容器==服务提供对象

子容器 只关系父容器

每个作用域对象都有一个明确边界

针对一个http请求

 

Application

Request

每一个请求针对一个子容器, 处理完成就会被释放

 

第三方

Autofac   sctutor

 

最大的应该用就是项目的扩张性和灵活性

架构问题:

Autofac   

Hosting 托管主机应用

 

服务集合--- 容器构建器-- 服务提供对象

 

Autofac

autofac.extensions.dependencyinjection

  var serviceCollection = new ServiceCollection()

                .AddTransient<IAccount, Account>()

                .AddTransient<IMessage, Message>();

 

            var containerBuilder = new ContainerBuilder();

 

            containerBuilder.Populate(serviceCollection);

 

            containerBuilder.RegisterType<Tool>().As<ITool>();

 

            var container = containerBuilder.Build();

 

            IServiceProvider provider = new AutofacServiceProvider(container);

整合autofac 强大的注册功能

 

 public void ConfigureContainer(ContainerBuilder builder)

        {

            var assembly = Assembly.GetExecutingAssembly();

            // 程序集注册

            builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())

                // 筛选命名空间为 Services

                .Where(t => t.Namespace == assembly.GetName().Name + ".Services")

                // 暴露注册类型的接口

                .AsImplementedInterfaces()

                // 生命周期模式为Scope

                .InstancePerLifetimeScope();

        }

 

 

    public static IHostBuilder CreateHostBuilder(string[] args) =>

            Host.CreateDefaultBuilder(args)

                .ConfigureWebHostDefaults(webBuilder =>

                {

                    webBuilder.UseStartup<Startup>();

                })

                .UseServiceProviderFactory(new AutofacServiceProviderFactory());

扩展性

单例实例不用自己创建

 

Scrutor 。Net 内置 DI 的扩展包

性能高效

  services.Scan(scan => scan

                .FromAssemblyOf<Startup>()

                .AddClasses(classes =>

                    classes.Where(t => t.Name.EndsWith("Service", StringComparison.OrdinalIgnoreCase)))

                .UsingRegistrationStrategy(RegistrationStrategy.Throw)

                .AsMatchingInterface()

                .WithScopedLifetime()

            );

 

 

文件配置系统:

 

IFileProvider 抽象的文件系统 层次化目录结构

监控文件变化:

  var provider = new ServiceCollection()

                .AddSingleton<IFileProvider>(new PhysicalFileProvider(@"e:\其它"))

                .AddSingleton<FileManager>()

                .BuildServiceProvider();

            var fileManager = provider.GetService<FileManager>();

            fileManager.WatchAsync("Text.txt").Wait();

            Console.Read();

 

 public async Task WatchAsync(string path)

            {

                Console.WriteLine(await ReadAsync(path));

 

                ChangeToken.OnChange(() => _fileProvider.Watch(path), async () =>

                {

                    Console.Clear();

                    Console.WriteLine(await ReadAsync(path));

                });

            }

 

 

 

  public async Task<string> ReadAsync(string path)

            {

                await using var stream = _fileProvider.GetFileInfo(path).CreateReadStream();

                var buffer = new byte[stream.Length];

                await stream.ReadAsync(buffer, 0, buffer.Length);

                return Encoding.Default.GetString(buffer);

            }

 

读取配置文件:

 public class AppConfigDemo

        {

            public string Name  { get; set; }

            public string StartDate { get; set; }

            public string EndDate { get; set; }

        }

 

        public static void Run()

        {

            var source = new Dictionary<string, string>

            {

                ["Name"] = "AppConfig",

                ["StartDate"] = "2020年5月1日",

                ["EndDate"] = "2020年5月5日"

            };

 

            var options = new ConfigurationBuilder()

                .AddInMemoryCollection(source)

                .Build()

                .Get<AppConfigDemo>();

 

            Console.WriteLine($"Name:{options.Name}");

            Console.WriteLine($"StartDate:{options.StartDate}");

            Console.WriteLine($"EndDate:{options.EndDate}");

        }

 

读取jeson

 public class AppConfigDemo

        {

            public string Name  { get; set; }

            public string StartDate { get; set; }

            public string EndDate { get; set; }

 

            public Behavior Behavior { get; set; }

        }

 

        public class Behavior

        {

            public bool IsRead { get; set; }

            public bool IsWrite { get; set; }

        }

 

        public static void Run()

        {

            var options = new ConfigurationBuilder()

                .Add(new JsonConfigurationSource{Path = "appsettings.json"})

                .Build()

                .Get<AppConfigDemo>();

 

            Console.WriteLine($"Name:{options.Name}");

            Console.WriteLine($"StartDate:{options.StartDate}");

            Console.WriteLine($"EndDate:{options.EndDate}");

            Console.WriteLine($"Behavior.IsRead:{options.Behavior.IsRead}");

            Console.WriteLine($"Behavior.IsWrite:{options.Behavior.IsWrite}");

        }

 

 

 

 

动态加载文件变化

 public class AppConfigDemo

        {

            public string Name  { get; set; }

            public string StartDate { get; set; }

            public string EndDate { get; set; }

 

            public Behavior Behavior { get; set; }

        }

 

        public class Behavior

        {

            public bool IsRead { get; set; }

            public bool IsWrite { get; set; }

        }

 

        public static void Run()

        {

            var config = new ConfigurationBuilder()

                .AddJsonFile("appsettings.json", true, true)

                .Build();

            

            Read(config.Get<AppConfigDemo>());

            ChangeToken.OnChange(() => config.GetReloadToken(), () =>

            {

                Read(config.Get<AppConfigDemo>());

            });

            Console.Read();

        }

 

        public static void Read(AppConfigDemo options)

        {

            Console.Clear();

            Console.WriteLine($"Name:{options.Name}");

            Console.WriteLine($"StartDate:{options.StartDate}");

            Console.WriteLine($"EndDate:{options.EndDate}");

            Console.WriteLine($"Behavior.IsRead:{options.Behavior.IsRead}");

            Console.WriteLine($"Behavior.IsWrite:{options.Behavior.IsWrite}");

        }

}

 

 

 

读取xml

 public class AppConfigDemo

        {

            public string Name  { get; set; }

            public string Ver { get; set; }

        }

 

 

        public static void Run()

        {

            Environment.SetEnvironmentVariable("APP_NAME", "AppDemo");

            Environment.SetEnvironmentVariable("APP_VER", "Alpha");

 

            var config = new ConfigurationBuilder()

                .AddEnvironmentVariables("APP_")

                .Build()

                .Get<AppConfigDemo>();

 

            Console.WriteLine($"Name:{config.Name}");

            Console.WriteLine($"Ver:{config.Ver}");

        }

    }

 

Hosting  与管道

Hosting 托管主机

定义个托管服务

  public class SystemClock : IHostedService

        {

            private Timer _timer;

 

            public Task StartAsync(CancellationToken cancellationToken)

            {

                _timer = new Timer(state =>

                {

                    Console.WriteLine($"Current Time:{DateTime.Now.ToLongTimeString()}");

                }, null,0, 1000);

 

                return Task.CompletedTask;

            }

 

            public Task StopAsync(CancellationToken cancellationToken)

            {

                _timer?.Dispose();

                return Task.CompletedTask;

            }

        }

 

        public static void Start()

        {

            var host = new HostBuilder()

                .ConfigureServices(collection => collection

                    .AddHostedService<SystemClock>())

                    .Build();

            host.Run();

        }

    }

 

 

托管服务所依赖的服务,也可以注册到 容器中

 

配置选项

 var collector = new Collector();

            var host = new HostBuilder()

                .ConfigureAppConfiguration(builder => builder.AddJsonFile("appsettings.json"))

                .ConfigureServices((context, collection) => collection

                    .AddSingleton<ITemperatureCollector>(collector)

                    .AddSingleton<IHumidityCollector>(collector)

                    .AddSingleton<IAirQualityCollector>(collector)

                    .AddHostedService<AirEnvironmentService>()

                    .AddOptions()

                    .Configure<AirEnvironmentOptions>(

                        context.Configuration.GetSection("AirEnvironment"))

                ).Build();

 

            host.Run();

 

 

三个核心对象:

Ihostservice 启动或者停止 服务两个方法

Ihostbuilder  Ihost

一个程序,只有一个主机对象

和程序一起启动或者停止

 

管道:

请求处理管道 ==http处理请求

var host = Host.CreateDefaultBuilder()

                .ConfigureWebHost(builder => builder

                    .UseKestrel()

                    .Configure(app => //管道中间件

                        app.Run(context =>

                            context.Response.WriteAsync("Hello!"))

                    )

                ).Build();

            host.Run();

 

ConfigureWebHost 自己定义    ConfigureWebHostDefault

请求处理管道 一个服务器(监听)一组中间件

请求消息 响应消息

Func 委托   requesstDelegate

requesstDelegate http 请求处理器

 

注册中间件 通过委托的方式进行

   public static void Start()

        {

 

            var host = Host.CreateDefaultBuilder()

                .ConfigureWebHostDefaults(builder => builder

                    .Configure(app => app

                        .Use(Middleware1)

                        .Use(Middleware2)

                    )

                ).Build();

            host.Run();

        }

 

        private static RequestDelegate Middleware1(RequestDelegate next)

        {

            async Task App(HttpContext context)

            {

                await context.Response.WriteAsync("Middleware 1 Begin.");

                await next(context);

                await context.Response.WriteAsync("Middleware 1 End.");

            }

 

            return App;

        }

 

 

        private static RequestDelegate Middleware2(RequestDelegate next)

        {

            async Task App(HttpContext context)

            {

                await context.Response.WriteAsync("Middleware 2 Begin.");

            }

 

            return App;

        }

}

根据注册的顺序来执行,后面没有,就直接返回

 

注册强类中间件

  public class HelloMiddleware : IMiddleware

        {

            public async Task InvokeAsync(HttpContext context, RequestDelegate next)

            {

                await context.Response.WriteAsync("Hello");

            }

        }

 

        public static void Start()

        {

 

            var host = Host.CreateDefaultBuilder()

                .ConfigureWebHostDefaults(builder => builder

                    .ConfigureServices(collection => collection.AddSingleton<HelloMiddleware>())

                    .Configure(app => app

                        .UseMiddleware<HelloMiddleware>()

                    )

                ).Build();

            host.Run();

        }

    }

基于约定来注册中间件

  1. 有效的公共构造函数(参数必须包含一个requestdelegate 参数 也可以包含其他类型的参数顺序无所谓)
  2. 必须有 invoke 或者invokeAsync 的方法

基于约定的中间件 框架会自己注册并且是以单例的方式进行注册

  public class HelloMiddleware

        {

            private readonly RequestDelegate _next;

            private readonly string _content;

            private readonly bool _isToNext;

 

            public HelloMiddleware(RequestDelegate next, string content, bool isToNext = false)

            {

                _next = next;

                _content = content;

                _isToNext = isToNext;

            }

 

            public async Task InvokeAsync(HttpContext httpContext)

            {

                await httpContext.Response.WriteAsync($"Hello {_content}!\r\n");

                if (_isToNext) await _next(httpContext);

            }

        }

 

        public static void Start()

        {

 

            var host = Host.CreateDefaultBuilder()

                .ConfigureWebHostDefaults(builder => builder

                    .Configure(app => app

                        .UseMiddleware<HelloMiddleware>("Rick", true)

                        .UseMiddleware<HelloMiddleware>("Motry")

                    )

                ).Build();

            host.Run();

        }

}

可以通过startup 类来完成服务和中间件的注册

经典的startup类

 public class Startup

        {

//可有可无,并且系统也会注册很多公共服务,系统的服务注册完成后,才会执行注册 个人自己写的服务

            public void ConfigureServices(IServiceCollection services)

            {

 

            }

 

            public void Configure(IApplicationBuilder app)

            {

 

            }

        }

 

        public void Strat()

        {

            var host = Host.CreateDefaultBuilder()

                .ConfigureWebHostDefaults(builder => builder

                    .UseStartup<Startup>())

                .Build();

            

            host.Run();

        }

    }

查看系统默认注册了哪些公共的服务的示例:

 public void ConfigureServices(IServiceCollection services)

            {

                foreach (var service in services)

                {

                    var serviceName = service.ServiceType.Name;

                    var implType = service.ImplementationType;

                    if (implType != null)

                    {

                        Console.WriteLine($"{service.Lifetime, -15}{serviceName,-40}{implType.Name}");

                    }

                }

            }

 

            public void Configure(IApplicationBuilder app)

            {

 

            }

        }

 

        public static void Start()

        {

            var host = Host.CreateDefaultBuilder()

                .ConfigureWebHostDefaults(builder => builder

                    .UseStartup<Startup>())

                .Build();

            

            host.Run();

        }

}

 

说明下: public Startup(IConfiguration configuration, IHostEnvironment hostingEnvironment)

            {

                Debug.Assert(configuration != null);

                Debug.Assert(hostingEnvironment != null);

            }

 

Startup 类中只能注册 公共的服务,和 执行顺序有关

 

中间件的注入,不仅支持构造函数注入,也支持特定的方法注入

InvokeAsync 可以

在基于约定的中间件中 最好不用构造函数注入

因为基于约定的中间件是单例方式注册,可能会导致其他服务一直不能被释放掉

放到InvokeAsync方法中 第一个 参数为HttpContext

 private readonly RequestDelegate _next;

 

            public TestMiddleware(RequestDelegate next)

            {

                

                _next = next;

            }

 

            public async Task InvokeAsync(HttpContext httpContext,Test1 test1, Test2 test2)

            {

                Debug.Assert(test1 != null);

                Debug.Assert(test2 != null);

                await httpContext.Response.WriteAsync("Test");

 

            }

 

在 mvc 项目中 注入主要用在两个位置,一个是控制器 构造函数注入,一个试图

 

 

工作流

项目实战

可以拆分成 微服务的架构来进行

使用 Dapper 来实现  JadeFramework

Automapper

Linux 和 docker 中有大小写区分 所以命令建议

 类名

用小写 加 下划线

改造 一个模型 对应个 仓促 对应个service

Ares 对页面分组

多租户问题 目前没有处理

JWT

前后端分离

流程发起

流程审核

流程设计

通知 使用 singalR 框架  实时通信

短信 微信 邮件 电话

 singalR   messagehub  sinagR

 // 4、使用SignalR

            services.AddSignalR().AddNewtonsoftJsonProtocol();

引包:

microsoft.aspnetcore.signalr.protocols.newtonsoftjson

 

创建 MessageHub  建立客户端链接

消息发送过程  1 发给 hub  hun在发给2

 

SignalRMessageGroups 保存用户的信息

 

  // 2、映射SignalR 连接中心

                endpoints.MapHub<MessageHub>("/messageHub", options => options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransports.All);

MessageHubGroup 扩展

 

事件总线(消息总线) 就是通用的订阅发布系统

 

RuanMou.WorkFlow   BLT.APS.Project

 

CREATE TABLE IF NOT EXISTS `oa_message_user` (

  `Id` long NOT NULL COMMENT '主键',

  `MessageId` long NOT NULL COMMENT '流程实例id',

  `UserId` long NOT NULL COMMENT '当前节点id',

  `IsRead` varchar(2) DEFAULT NULL COMMENT '节点名称',

)

 

ABP

 

 

 

特性:abp cli 模块化 都租户 认证授权

虚拟文件系统 主题 后台作业 事件总线

对象映射  依赖注入 数据过滤

单体和微服务都可以

手动创建一个 ABP

模块化 封装细节 提供接口

模块之间没有必然联系 互补影响

代码质量提升

多人协助 会不干扰

高内聚低耦合

模块分为两种:根据功能和用途分

应用程序模块:实现业务

框架模块:核心模块 通用功能

模块了负责管理整个模块的生命周期

模块配置  首先执行

模块初始化

模块销毁

模块间的依赖关系 决定模块的启动顺序

启动流程

模块的加载顺序:先加载依赖 在加载自己

拓扑排序算法 根据依赖关系

启动模块最后一个执行

  1. 注册abp基础设施与核心服务
  2. 加载整个应用的所有模块,执行每一个模块的配置方法(3个)
  3. 按顺序遍历所有模块,执行每个模块的初始化方法(3个)

 

ABP依赖注入两种方式:

手动注册

自动注册:

按照约定 (所有模块类,所有控制器)

按照依赖接口 (HelloWorldService:IScopedDependency)

按照依赖特性 // [Dependency(ServiceLifetime.Transient)]

// [ExposeServices(typeof(IHelloService))]

配置选项

DDD 领域模型

领域模型:实体(唯一并可以持续变化)和值对象

实体类(充血模型)

聚合

Domain 领域

仓储:用来协调领域(实体)和数据映射(数据模型ORM)

仓储=只能通过聚合根来持久化和数据检索

数据访问层

持久化方案

 



这篇关于.net core的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程