.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)

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

数据访问层

持久化方案

cap mq


https://www.sohu.com/a/290918943_120050810


https://www.cnblogs.com/zcqiand/p/14257654.html


https://blog.csdn.net/greenwaves3000/article/details/111467442


http://www.csharpkit.com/2017-10-08_70806.html


https://developer.aliyun.com/article/706163


http://www.bubuko.com/infodetail-3566007.html

 

posted @ 2021-06-28 00:42  一码事  阅读(250)  评论(0编辑  收藏  举报