进程/线程/多线程/Task/Async/Await/EFcore/IQueryable/IEnumerable/AsEnumerable/AsQueryable

1.进程/线程/多线程

进程:

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本 单位,是操作系统结构的基础。 在早期面向进程设计的计算机结构中,进程是程序的基本执行实体; 在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的 实体。

线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运 作单位。

  • 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
  • 线程是独立调度和分派的基本单位。

同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但
同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程
本地存储(thread-local storage)。
一个进程可以有很多线程,每条线程并行执行不同的任务。

//1. 进程/线程/多线程
//2. 同步异步
//3. 异步的三大特点
//4. C#中的多线程

    //一、进程:计算机概念,虚拟的记录,描述一个应用程序在计算机上运行的时候,所消耗的各种资源的集合---Cpu+内容+磁盘IO+网络资源;
    //---类似于某一个公司---公司正常运作;

    //二、线程:(计算机资源)一个程序的进程中,所执行的具体的某一个动作的最小执行流;小到点击某个按钮,大到通过网络发送一句话出去;
    //具体到某一个人:
    //进程必然是包含了多个线程;线程是依附于进程存在的;如果进程不在了,线程也随之消失了;


    //三、句柄:是一个long了类型的数字,对应这计算机程序中的某一个小部件;要操作程序,对应的最小的单位;
    //公司中的任何一个物件--编号--计算机---会给计算机坐个编号---(部门---座位号)

    //四、为什么计算机可以多线程?跟计算机的CPU的核数有关;
    //6核12线程:把六个核心进行逻辑切分:如果有动作需要计算机响应,操作系统就会去申请CPU来处理;CPU在执行动作的时候,CPU是分片执行:
    //分片:把每一个核每一毫秒可以执行的动作,切分成10000份;操作系统在调度的时候,执行动作,切分后去执行的多个动作的时候;开始动作A,使用的是分片后的某一份;  结束的时候,可能使用的是另外的某一份; 
    //计算机在不断的调度过程中;
    //1.从宏观角度来说:多个动作,就可以做到在某一段时间内;看似同时执行完毕了;
    //2.从微观的角度来说:某一时刻,同意时刻只能处理一件事儿--串行执行;

    //五、C#中的多线程:Thread/ThreadPool/Task 都是C#语言在操作计算机的资源(线程)时;封装的一个帮助类库;
    //线程:---同步异步:
    //单线程执行代码命令:同步执行;
    //同步方法:
    //1.线性执行,从上往下依次执行--很符合我们人类的思维逻辑,线程ID为01  (主线程/UI线程)
    // 请人吃饭:真心的请人吃饭;Richard老师请Vn吃饭;说:Vn,晚上一起去吃饭;Vn:我还要忙一会儿,Richard:那好,我等你;等你忙完,我们一起去吃饭;
    //2.同步方法执行慢;卡顿界面--只有一个线程参与计算---CPU太忙,根本无暇他顾;只有一个线程执行动作; 消耗的计算机资源少(工钱少)
    //3.同步方法:有序执行;
    

    //多线程执行代码命令:异步执行:
    //异步方法:
    //1.开启了一个新的线程(多线程--子线程)(有一个新的线程Id);且不再是线型执行了;  UI线程不等待子线程执行完毕;主线程直接往后执行;  子线程延迟执行 
    //请人吃饭:客气一下请人吃饭:Richard老师客气一下请人Vn吃饭,说:Vn,晚上一起吃饭,Vn:我还要忙一会儿,Richard:那你先忙吧,我就先去吃饭了,你忙完自己去吃饭吧!
    //2.异步方法执行快:不卡顿界面;开启了一个新的线程去执行去了;开启了五个线程去执行动作:消耗的计算机资源多(工钱多)
    //  异步方法--多线程方法--以资源换时间; 使用大量的资源,降低时间成本;
    //3.无序执行:线程开启无法控制谁先谁后;线程执行计算结束也无法控制谁先谁后;---多线程异步执行:无序执行;
  • Task开启线程的多种方式,子线程,单线程等待
  • Delay和Sleep的区别,和使用场景
  • Waitall/WaitAny/TaskFactory:ContinueWhenAny/TaskFactory:ContinueWhenAll

1.C#中的多线程Task
2.父子级线程
3.Task:Waitall WaitAny Delay
4.TaskFactory:ContinueWhenAny
5.TaskFactory:ContinueWhenAll

     //1. 进程/线程/多线程
    //2. 同步异步
    //3. 异步的三大特点
    //4. C#中的多线程

2.多线程:他的应用场景:

        //一、在什么情况下,可以使用多线程?
        //1.一个数据库查询:---可以使用多线程吗?不适合使用多线程;因为只有一个动作;不存在多个动作并发执行;
        //2.如果要同时去查询接口+查询缓存+查询数据库?--适合使用多线程吗?---可以开启三个线程;每个线程就负责一个动作; 
        //通过一个案例,来解析: 

        //二、高级班VIP课程讲课:
        //1.开始上课---Richard老师开始讲课--一节一节的开始讲:适合使用多线程吗?--不适合:不能同时讲多个课
        //。。。。。经过大概8个月的时间
        //2.开始项目实战---分组进行;多人合作完成; 适合使用多线程吗? ---适合;每个人就可以对应一个线程;多个人同时去开发功能---多线程并发;

        //3.如果大家其中有一个人完成了功能的开发,Richard老师就要开始准备环境了。
        //a.需要等待一堆线程中的某一个线程执行结束,马上触发一个动作;
        //解决方案: Task.WaitAny--等待几个线程中的某一个线程执行结束;---主线程会等待---会卡顿界面;一直到某一个线程执行结束后,才往后执行;--体验不好 
        //4.如果所有人开发完毕了,庆祝一下,一起吃个饭;

        //三、应用场景:
        //1.ContinueWhenAny
        //如果需要在一堆任务中,某一种执行结束后,去触发一个动作;


        //2.ContinueWhenAll
        //如果需要回调---如果需要控制顺序:

        //3.WaitAny
        //   有一个列表数据:有可能是来自于第三方接口,有可能是来自于缓存,也有可能是来自于数据库,查询的时候,我们不确定;
        // 常规玩法: 先找缓存,如果有数据,直接返回了,如果缓存没有--可能要去查询数据库,如果数据库有数据,直接返回,如果没有---查询第三方接口;
        // 多线程:同时开启三个线程,同时去查询三个地方的数据,只要是有一个地方的数据查询到了,只要是有一个地方的数据找到了,其他的两个线程我们就不管了;直接把找到的数据返回给前端就可以了;
        //
        //
        //4.WaitAll
        // 如果有一个首页,首页中包含了很多功能:考勤信息,年度top10,季度top10,公告,通知;
        // 在主页中:要加载主页-这些信息都需要查询出来: 而且这些信息都是来自于不同的地方,有的来自于接口,有的来自于缓存有的都来于数据库: 
        //有几个块信息,就开启几个线程,同时分别去各自的地方进行查询各自的数据;可以在后台等待所有的子线程执行结束;拿到结果、组件一个大的复杂实体对象,传递给视图,通过视图做绑定;--让查询并发执行: 但是这里如果是使用C#开发,不做前后端分离的话,可以考虑这种,可以提高性能;
        //现在更多的时候,可能是使用异步Ajax来完成---用户体验会更好;  资源会有所浪费,但是性能可以提高;

3.Task开启线程有哪些方式:

{
                Task task = new Task(() =>
                {
                    Debug.WriteLine($"****************task开始了: {Thread.CurrentThread.ManagedThreadId.ToString("00")} ***************");
                    Task task1 = new Task(() =>
                    {
                        Debug.WriteLine($"****************task1: {Thread.CurrentThread.ManagedThreadId.ToString("00")} ***************");
                        Thread.Sleep(1000);
                        Debug.WriteLine("我是task1线程");
                    });

                    Task task2 = new Task(() =>
                    {
                        Debug.WriteLine($"****************task2: {Thread.CurrentThread.ManagedThreadId.ToString("00")} ***************");
                        Thread.Sleep(1000);
                        Debug.WriteLine("我是task2线程");
                    });
                    task1.Start();
                    task2.Start();

                    //task1.Wait();
                    //task2.Wait();

                    Debug.WriteLine($"****************task: {Thread.CurrentThread.ManagedThreadId.ToString("00")} ***************");
                });
                task.Start();//线程启动了
                task.Wait();   //单个线程的等待;等待task 内部的内容执行完毕,这里会卡顿界面;是主线程等待;

                // task.Wait();//等待执行完成:
                task.Wait(TimeSpan.FromMilliseconds(1100));
                task.Wait(1000);//限时等待;过时不候

                // Thread thread = null;

                //thread.Abort();//线程停止;
                //thread.Start();
                //thread.IsBackground = true;//后台线程:进程结束,线程随之消失
                //thread.IsBackground = false;//前台线程:进程结束,线程把内部需要执行的动作执行完毕,然后消失

            }
 //主线程执行
            Task task = Task.Run(() =>//启动新线程完成任务
            {
                Thread.Sleep(1000);
                Console.WriteLine($"NoReturnNoAwait Sleep3000 before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(1000);
                Console.WriteLine($"NoReturnNoAwait Sleep3000 after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
            });
  TaskFactory taskFactory = new TaskFactory();
            Task<int> iResult = taskFactory.StartNew<int>(() =>
            {
                Thread.Sleep(3000);
                Console.WriteLine($"SumFactory 123 Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                return 123;
            }).ContinueWith(c=> {
                 
                Thread.Sleep(3000);
                Console.WriteLine($"SumFactory 234 Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                return 123;

            }).ContinueWith(t=> {

                Thread.Sleep(3000);
                Console.WriteLine($"SumFactory 345 Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                return 123;
            });
        #region MyRegion
        //多线程:他的应用场景:

4.在什么情况下,可以使用多线程?

        //1.一个数据库查询:---可以使用多线程吗?不适合使用多线程;因为只有一个动作;不存在多个动作并发执行;
        //2.如果要同时去查询接口+查询缓存+查询数据库?--适合使用多线程吗?---可以开启三个线程;每个线程就负责一个动作; 
        //通过一个案例,来解析: 

        //二、高级班VIP课程讲课:
        //1.开始上课---Richard老师开始讲课--一节一节的开始讲:适合使用多线程吗?--不适合:不能同时讲多个课
        //。。。。。经过大概8个月的时间
        //2.开始项目实战---分组进行;多人合作完成; 适合使用多线程吗? ---适合;每个人就可以对应一个线程;多个人同时去开发功能---多线程并发;

        //3.如果大家其中有一个人完成了功能的开发,Richard老师就要开始准备环境了。
        //a.需要等待一堆线程中的某一个线程执行结束,马上触发一个动作;
        //解决方案: Task.WaitAny--等待几个线程中的某一个线程执行结束;---主线程会等待---会卡顿界面;一直到某一个线程执行结束后,才往后执行;--体验不好 
        //4.如果所有人开发完毕了,庆祝一下,一起吃个饭;
  1. 三、应用场景:

        //1.ContinueWhenAny
        //如果需要在一堆任务中,某一种执行结束后,去触发一个动作;
        //2.ContinueWhenAll
        //如果需要回调---如果需要控制顺序:
        //3.WaitAny
        //   有一个列表数据:有可能是来自于第三方接口,有可能是来自于缓存,也有可能是来自于数据库,查询的时候,我们不确定;
        // 常规玩法: 先找缓存,如果有数据,直接返回了,如果缓存没有--可能要去查询数据库,如果数据库有数据,直接返回,如果没有---查询第三方接口;
        // 多线程:同时开启三个线程,同时去查询三个地方的数据,只要是有一个地方的数据查询到了,只要是有一个地方的数据找到了,其他的两个线程我们就不管了;直接把找到的数据返回给前端就可以了;            
        //
        //4.WaitAll
        // 如果有一个首页,首页中包含了很多功能:考勤信息,年度top10,季度top10,公告,通知;
        // 在主页中:要加载主页-这些信息都需要查询出来: 而且这些信息都是来自于不同的地方,有的来自于接口,有的来自于缓存有的都来于数据库: 
        //有几个块信息,就开启几个线程,同时分别去各自的地方进行查询各自的数据;可以在后台等待所有的子线程执行结束;拿到结果、组件一个大的复杂实体对象,传递给视图,通过视图做绑定;--让查询并发执行: 但是这里如果是使用C#开发,不做前后端分离的话,可以考虑这种,可以提高性能;
        //现在更多的时候,可能是使用异步Ajax来完成---用户体验会更好;  资源会有所浪费,但是性能可以提高;
    
        #endregion
    
        //父子级线程
        //一个Task内部,开启了几个线程以后;Task内部的线程可以理解为子线程;
        //父线程在等待的时候,子线程没有线程等待;子线程可能内容还没有执行万一,父线程就已经结束了;
    

5. async/await

1.async/await语法特训
2.async/await原理
3.async/await场景应用
4.为什么推荐使用async/await

视频1:async/await语法特训 01:23:24
视频2:async/await原理,async/await在底层的状态机实现

1.async/await场景应用
1.为什么推荐使用async/await

视频1:async/await不同框架的应用
视频2:async/await的核心价值分析,案例分析总结
视频3:async/await的使用建议

//
/// async/await:
/// ASP.NET Core MVC Webapi Winform WPF 控制台
/// 一、async/await
/// 1.C#5 (.NET4.5) 引入的语法糖
/// 2.C#7.1,Main入口也可以
/// 3.C#8.0,可以使用异步流await foreach和可释放对象 await using
///
/// 二、啥是语法糖?
/// 由编译器提供的便捷功能,就是语法糖
/// var/表达式目录树的快捷声明/new object()/属性的get;set方法/$“{}”
/// 在底层是不变,但是我们在写代码的时候,可以省事儿点
///
/// 三、await/async用法
///1 async 是用来修饰方法,如果单独出现,方法会警告,没有什么作用
///2 await在方法体内部,只能放在async修饰的方法内,必须放在task前面
///3 async/await方法里面如果没有返回值,默认返回一个Task,或者void(推荐用Task,而不是void,因为这样才能await/wait)
///4 带async+await后,返回值要多一层Task<>
///
///
///四、为什么要Async/await呢?—AwaitHistoryShow
///1.既要有顺序,又要不阻塞~~
///2.以同步编程的方式来写异步
///
///五、内部究竟咋实现滴?–ILSpay
///1.状态机的实现,根据不同的状态去执行不同的分支
///
///六、不同框架的应用
///1.Winform–存在特殊处理
///2.ASP.NETCore—放心用
///3.控制台—放心用
///4.WPF----没试过—你们试试
///5.Core WebApi—放心用
///

七、async/await具体的价值是什么?

    async/await--有啥价值?--串行执行的,有顺序的执行
1.降低了编程难度。 
2.提高性能吗?---降低计算的时间,谈不上去提高性能
3.挺高了吞吐量---提供了请求的响应能力;降低了线程的使用数量
    ///
    /// 
    ///八、ReadFile对比
    /// 1.Async--
    /// 2.Task---
    /// 3.Sync---
    /// 
    /// 
    /// 九.InvokeWeb对比
    /// 1.Async--
    /// 2.Task---
    /// 3.Sync---
    /// 
    /// 十、适合场景
    /// 1.跟第三方交互的(非托管资源,经常有async版本):
    /// 2.数据库openAsync-Redis
    /// 3.Web请求-Api
    /// 4.文件读取
    ///  
    /// 十一、不适宜的场景
    /// 1.服务器本地计算(CPU密集型,托管资源):
    /// 2.
    /// 
    /// 十二、总结:
    ///
    ///  
    /// 

8、如果给方法加上Async–在底层会生成一个状态机–状态模式

    //1.什么是状态机?-----类似于红绿灯: 红灯:停;绿灯:行;
    //2.一个对象在不同的状态可以执行的不同的行为

    //二、IL:如果给方法加上Async--在底层会生成一个状态机--状态模式
    //1.实例化状态机
    //2.把状态机实例交给一个build去执行
    //3.整理线程的上下文
    //4.stateMachine.MoveNext();  调用MoveNext方法
    //5.MoveNext如何执行:先获取一个状态  ---继续往后执行
    //6.如果有异常---一抛出异常--把状态重置为-2
    //7.如果没有异常,把状态重置重置为-2
    //8.SetResult();---把结果包裹成一个Tsak

///
/// 带返回值的Task
/// 要使用返回值就一定要等子线程计算完毕
///
/// 1.await: 线程遇到awai就返回,不阻塞:并发执行
/// 2.做到控制顺序
/// 其实就是以写同步方法 的方式;来完成多线程:–可以控制顺序
///
/// async 就只返回long

TW

有使用过.net5进行开发,熟悉web相关开发
-技能: 如果有IT团队管理经验,可能会问设计模式,不solid原则等(如果你管理经验短,就不要说你擅长管理,不要给自己挖坑)
对 EF的理解, 尤文没有使用过解决复杂问题;IQueryable,IEnumerable 是否知道
async await 有用过,能正确给出示例问题答案; 在什么场景下使用;
进程线程 具体意义和区别
值类型和引用类型的意义及使用
Lambda表达式 是否用过
拓展方法是否使用过
特性是否了解
闭包是否了解
是否使用TFS进行ci/cd方面的经验
-学习能力体现:如果你说你最近在看某个技术,那你就要对这个技术钻研一些,举例python,不能只了解皮毛,这个问题回答你也不要给自己挖坑,尽量说自己熟悉的技术、

1.(must)是否能够阅读英文技术文档,日常翻阅英文技术文档/博客的比例有多少?
答:可以阅读,30%。
2.(must)近五年是否有过用英文与别人沟通的经历。
答:没有。
3.(must)最近半年的日常工作中,每天有多少时间在coding?(例如30%/50%…)
答:100%。
4.(must)是否应用了流水线来打包部署,能否简要说下你对打包部署的使用或理解。
答:没有。打包就是将一个服务或者软件系统组成的依赖的动态链接库、exe、配置文件等封装成一个安装包,可以以一个整体提供给用户安装部署,常用的打包工具有开发工具自带的,可以写一些服务, 安装步骤和条件检测,还有第三方厂家的打包工具。
5.(must)是否使用过docker/k8s, 是否写过dockerfile?怎么理解端口mapping
答:项目中没有使用过,但学习过相关理论。端口映射是我们访问服务器时服务器端口对Docker 端口 的关联,默认情况下容器中镜像占用的端口是容器中的端口与外界是隔绝的,必须进行端口映射才能访问。
6.(must)你本人是否在项目中使用过这些特性 .net: Linq/Entity Framework/HttpHandler/Middleware/Reflection
答:这些特性在项目中都使用过。
Linq语言集成查询,应对多源,多类型进行统一的快速查询。
Entity Framework是微软推出ORM框架。
HttpHandler是定义 ASP.NET 以异步方式处理使用自定义 HTTP 处理程序的 HTTP Web 请求而实现的协定。
Middleware是.netcore推出的新概念,是为了方便随时注入服务插件。
Reflection是可以在运行时获得.NET中每一个类型(包括类、结构、委托、接口和枚举等)的成员,包括方法、属性、事件、以及构造函数等。
7.(must)是否理解DI/IOC,请简要说明下其中的生命周期
答:理解,使用两个不同角度来说明依赖倒置设计原则,DI是IOC的一种实现方式,用来反转依赖,IOC则是应该如何做,来解除相互依赖模块的耦合。
生命周期:
(1)创建容器对象
(2)注册服务
(3)创建服务提供者对象Provider
(4)获取对象

8.(optional)是否了解Restful
答:了解。基于http动作谓词的以资源为中心提供服务的一种解决方案, 起源于roy fieldingd论文,主要是一下四个原则:
1.用HTTP实现无状态性
2.用URI实现地址的可见性
3.用HTTP方法实现统一的接口
4.用XML、JSON实现资源间的连通性

#10. 依赖倒置原则

1 单一职责,
2 里氏替换,
3 迪米特法则,
4 接口隔离原则
5 开闭原则
6 依赖倒置原则

依赖倒置原则:
高层模块对低层模块的依赖,不应该依赖于细节,而应该通过抽象来依赖(其实也
就是面向抽象编程);
高层:分层以后,依赖项为高层
低层:被依赖项为低层;
细节:普通类
抽象:接口/抽象类

IOC控制反转

AOP

要说Filter,得先理解AOP面向切面编程
Aspect Oriented Programming
OOP面向对象,个体是稳定的
AOP能在不破坏封装的前提下,去额外扩展功能
1 聚焦业务逻辑,轻松扩展功能
2 代码复用,集中管理

ASP.NET Core三层AOP

1 中间件
2 Filter
3 IOC容器的AOP扩展

Filter种类

1.Authorize 顺序排第一
2.ResourceFilter 顺序排第二—主要是缓存
3.Action 排在Resouce之后
4.Result
5. AlwaysRunResult
6.Exception 处理异常的、、覆盖一部分
如果系统需要授权认证—我在请求某一个功能的时候,授权就是最基本的;

API网关技术Ocelot

添加链接描述

Ocelot官方文档

本文首先介绍了API网关的概念,进而引出asp.net core中的一个开源的API网关技术Ocelot。并介绍了Ocelot的优点以及工作原理及架构图。接下来会详细介绍Ocelot如何通过简单地配置实现路由、请求聚合、服务发现、认证、鉴权、限流熔断、并内置了负载均衡器、Service Fabric、Skywalking等等功能。

  • API网关是什么?

API网关是系统暴露在外部的一个访问入口。就像一个公司的门卫承担着寻址、限制进入、安全检查、位置引导、等等功能。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。它可能还具有其它职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理等等。
API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。通常,网关也是提供REST/HTTP的访问API。服务端通过API-GW注册和管理服务。

  • Ocelot在API网关实现上有什么优点呢?

首先,上面已经讲述了Ocelot是一个用.NET Core技术实现并且开源的API网关技术。除此之外还有什么优点呢?那就是它强大的功能以及使用上的简单了。它的功能包括了:路由、请求聚合、服务发现、认证、鉴权、限流熔断、并内置了负载均衡器、Service Fabric、Skywalking等的集成。而且这些功能都只需要简单的配置即可完成。
目前,腾讯和微软是Ocelot在官网贴出来的客户。
另外,附上Ocelot的开源地址:https://github.com/ThreeMammals/Ocelot

  • Ocelot工作流程是怎样的呢?

实际上Ocelot就是一系列按特定顺序排列的中间件。
Ocelot首先通过配置将HttpRequest对象保存到一个指定的状态直到它到达用来创建HttpRequestMessage对象并将创建的HttpRequestMessage对象发送到下游服务中的请求构造中间件。通过中间件来发出请求是Ocelot管道中做的最后一件事。它不会再调用下一个中间件。下游服务的响应会存储在每个请求 scoped repository中,并作为一个请求返回到Ocelot管道中。有一个中间件将HttpResponseMessage映射到HttpResponse对象并返回给客户端。
接下来是你使用Ocelot是可能会使用的配置。

  • 安装NuGet package

使用nuget安装Ocelot及其依赖项。您需要创建一个netstandard2.0项目并将其Package安装到项目中。然后按照下面的“启动”和“ 配置”节点启动并运行。

安装命令 Install-Package Ocelot

你可以通过下面的链接查看Ocelot的历史版本https://www.nuget.org/packages/Ocelot/ 目前最新版是10.0.4。最新版最近正在进行重构,更新比较频繁。

配置
以下配置是一个非常基础的Ocelot.json配置,他不会做任何事情,但却可以让ocelot正常运行。

{
    "ReRoutes": [],
    "GlobalConfiguration": {
        "BaseUrl": "https://api.yilezhu.cn"
    }
}

这个配置里面最重要的是BaseUrl。Ocelot需要知道它正在运行的URL,以便执行Header查找和替换以及某些管理配置。设置此URL时,它应该是客户端将看到Ocelot运行的外部URL,例如,如果您正在运行容器,则Ocelot可能会在URL上运行http://123.12.1.1:6543但在其前面有类似nginx的响应在https://api.yilezhu.cn。在这种情况下,Ocelot基本网址应为https://api.yilezhu.cn。

如果由于某种原因你正在使用容器并且希望Ocelot在http://123.12.1.1:6543上响应客户端的请求, 那么你可以这样做但是如果要部署多个Ocelot,你可能希望在命令行中传递它某种脚本。希望您使用的任何调度程序都可以传递IP。

特别需要注意的是,这里的Ocelot.json配置文件需要在VS中右键修改为“始终复制”属性。

Program配置方法
官方文档是按照下面进行配置的。不过个人还是习惯在Sartup.cs文件中进行相关的配置。博主就先贴出官方文档给出的配置方法。
然后在你的Program.cs你将按照如何代码进行配置。这里最主要的是AddOcelot() 添加 ocelot 服务), UseOcelot().Wait() (使用 Ocelot中间件).

public class Program
{
    public static void Main(string[] args)
    {
         new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config
                    .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
                    .AddJsonFile("appsettings.json", true, true)
                    .AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true)
                    .AddJsonFile("ocelot.json")
                    .AddEnvironmentVariables();
            })
            .ConfigureServices(s => {
                s.AddOcelot();
            })
            .ConfigureLogging((hostingContext, logging) =>
            {
                //add your logging
            })
            .UseIISIntegration()
            .Configure(app =>
            {
                app.UseOcelot().Wait();
            })
            .Build()
            .Run();
    }

Startup配置方法
我个人也比较习惯在Startup.cs中进行配置,不习惯在Program.cs中配置。下面是我配置的一种方式,当然你也可以自由发挥。

public void ConfigureServices(IServiceCollection services)
        {
             services.AddMvc();

            services.AddOcelot(new ConfigurationBuilder()
                    .AddJsonFile("ocelot.json")
                    .Build());
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public async void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        await app.UseOcelot();

        app.UseMvc();
}

总结
今天只是给大家介绍Ocelot的非常非常简单地使用,可以说零配置,并介绍了官方的使用方法以及我平时的使用方式,只为了快速开始Ocelot,让项目能够跑起来。接下来我们会详细的介绍Ocelot的配置。

Ocelot路由详解

路由
Ocelot的最主要的功能是接收传入的http请求并将其转发到下游服务。

Ocelot使用ReRoute节点描述将一个请求路由到另一个请求。为了让路由在Ocelot中起作用,您需要在配置中设置ReRoute:

{
“ReRoutes”: [
]
}
要配置ReRoute,您需要在ReRoutes json数组中至少添加一个:

{
“DownstreamPathTemplate”: “/api/good/{goodId}”,//下游路由模板
“DownstreamScheme”: “http”,//下游路由请求的方式
“DownstreamHostAndPorts”: [//下游路由的Host以及端口
{
“Host”: “localhost”,
“Port”: 1001,
}
],
“UpstreamPathTemplate”: “/good/{goodId}”,//上游路由请求的模板
“UpstreamHttpMethod”: [ “Put”, “Delete” ]//上游路由请求的方式
}
DownstreamPathTemplate,DownstreamScheme和DownstreamHostAndPorts定义请求将转发到的URL。

DownstreamHostAndPorts是一个集合,用于定义您希望将请求转发到的任何下游服务的主机和端口。通常这只包含一个条目,但有时你希望对下游请求服务进行负载均衡,这个时候你就可以添加多个条目,并配合负载均衡选项进行相关的负载均衡设置。

UpstreamPathTemplate是Ocelot用于标识要用于给定请求的DownstreamPathTemplate对应的URL。使用UpstreamHttpMethod以便Ocelot可以区分具有不同HTTP谓词的请求到相同的URL。您可以设置特定的HTTP方法列表,也可以设置一个空列表以允许所有的。

在Ocelot中,您可以以{something}的形式将变量的占位符添加到模板中。占位符变量需要同时出现在DownstreamPathTemplate和UpstreamPathTemplate属性中。请求时Ocelot将尝试请求时进行替换。

你也可以像下面这样配置,捕获所有的路由:

Ocelot简易教程(四)之请求聚合以及服务发现

请求聚合
Ocelot允许你声明聚合路由,这样你可以把多个正常的ReRoutes打包并映射到一个对象来对客户端的请求进行响应。比如,你请求订单信息,订单中又包含商品信息,这里就设计到两个微服务,一个是商品服务,一个是订单服务。如果不运用聚合路由的话,对于一个订单信息,客户端可能需要请求两次服务端。实际上这会造成服务端额外的开销。这时候有了聚合路由后,你只需要请求一次聚合路由,然后聚合路由会合并订单跟商品的结果都一个对象中,并把这个对象响应给客户端。使用Ocelot的此特性可以让你很容易的实现前后端分离的架构。
为了实现Ocelot的请求功能,你需要在ocelot.json中进行如下的配置。这里我们指定了了两个正常的ReRoutes,然后给每个ReRoute设置一个Key属性。最后我们再Aggregates节点中的ReRouteKeys属性中加入我们刚刚指定的两个Key从而组成了两个ReRoutes的聚合。当然我们还需要设置UpstreamPathTemplate匹配上游的用户请求,它的工作方式与正常的ReRoute类似。

服务发现
Ocelot允许您指定服务发现提供程序,并将使用它来查找Ocelot将请求转发到的下游服务的主机和端口。目前,这仅在GlobalConfiguration部分中受支持,这意味着相同的服务发现提供程序将用于为ReRoute级别指定ServiceName的所有ReRoutes。

Consul
在使用Consul前你首先要做的就是安装在Ocelot中提供Consul支持的NuGet包

Install-Package Ocelot.Provider.Consul

然后将下面的内容添加在ConfigureServices方法中

services.AddOcelot()//注入Ocelot服务
                    .AddConsul(); 

GlobalConfiguration中需要加入以下内容。如果您未指定主机和端口,则将使用Consul默认值。

111.NetCore+TFS2017 CI/CD 持续集成持续交付系列

netcore用TFS做CICD的网上文章比较少,讲的也比较简单,所以踩坑比较多,因此写几篇文章记录下,防止以后忘记了。

TFS的CI/CD过程,无非就是利用TFS帮你拉取源码—编译—然后发布到指定目录

12 值类型和引用类型区别

进程/线程/多线程/Task/Async/Await/EFcore/IQueryable/IEnumerable/AsEnumerable/AsQueryable_第1张图片


进程/线程/多线程/Task/Async/Await/EFcore/IQueryable/IEnumerable/AsEnumerable/AsQueryable_第2张图片

闭包(Closure)

在计算机科学中,闭包(Closure)是词法闭包(Lexical
Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。

Peter J. Landin 在1964年将术语闭包定义为一种包含环境成分和控制成分的实体。
下面是我理解的闭包概念。

先看看数学上的闭包。

(1,5) 是一个区间,但对这个区间做分析、计算什么的,经常会用到1和5这两个不属于这个区间的值,[1,5]就是(1,5)的闭包。

在生活上,我们办事情,找A部门,A部门说,你先得找B部门盖个章,B部门说,你先得找C部门盖个章,C部门说,这个东西不是我们的职权范围…… 踢皮球,这就是非闭包。闭包就是负责到底,你找到A部门,A部门接待的那个人负责到底,他/她去协调B部门和C部门。

在工程上,闭包就是项目经理,负责调度项目所需要的资源。老板、客户有什么事情,直接找项目经理即可,不用再去找其它的人。

在程序语言中,闭包就是一种语法糖,它以很自然的形式,把我们的目的和我们的目的所涉及的资源全给自动打包在一起,以某种自然、尽量不让人误解的方式让人来使用。至于其具体实现,我个人意见,在不影响使用的情况下,不求甚解即可。在很多情况下,需要在一段代码里去访问外部的局部变量,不提供这种语法糖,需要写非常多的代码,有了闭包这个语法糖,就不用写这么多代码,自然而然的就用了。

这样一来,可以把闭包从一个语法机制提升为一种设计原则:

闭包是从用户角度考虑的一种设计概念,它基于对上下文的分析,把龌龊的事情、复杂的事情和外部环境交互的事情都自己做了,留给用户一个很自然的接口。

在这个原则下,函数式语言中,那种所谓的闭包只是一种“闭包”,还有大量的其它类型的“闭包”等待发现和实现。

下面举出一些闭包设计原则的正例和反例。

正例:

Flex中的数据绑定语法就是一种“闭包”。x=“{b.num + c.num}”,对于这个语法,编译器自动去上下文中寻找叫 b 和 c 的变量,然后再找他们内部 num 变量,如果他们都是可绑定的话,则自动给它们添加上绑定链,当 b, c, num 等有任一变动时,更新 x 的值。

反例:

Winform 中的设计就违反了闭包原则,当不是在该UI线程中,更新某些控件的值时,会抛出异常。只能去invoke调用,而invoke的接口很难用,相信很多人对这东东极其反感。

闭包不一定是语法糖。当我们不能直接扩展编译器时,我们就无法增加语法糖来实现闭包机制,这时,就要用现有的语言机制来实现了。

下面,我们来对winform的invoke方法进行改造,使它满足闭包原则。下面是代码:

public class ControlFuncContext 
{ 
    public Control Control { get; private set; } 
    public Delegate Delegate { get; private set; }

    public ControlFuncContext(Control ctl, Delegate d) 
    { 
        this.Control = ctl; 
        this.Delegate = d; 
    }

    public void Invoke0() 
    { 
        if (Control.IsHandleCreated == true) 
        { 
            try 
            { 
                Delegate.DynamicInvoke(); 
            } 
            catch(ObjectDisposedException ex) 
            { 
            } 
        } 
    }

    public void Invoke1(T obj) 
    { 
        if (Control.IsHandleCreated == true) 
        { 
            try 
            { 
                Delegate.DynamicInvoke(obj); 
            } 
            catch (ObjectDisposedException ex) 
            { 
            } 
        } 
    }

    public void Invoke2(T0 obj0, T1 obj1) 
    { 
        if (Control.IsHandleCreated == true) 
        { 
            try 
            { 
                Delegate.DynamicInvoke(obj0, obj1); 
            } 
            catch (ObjectDisposedException ex) 
            { 
            } 
        } 
    } 
}

public static class FormClassHelper 
{
    public static void InvokeAction(this Control ctl, Action action) 
    { 
        if (ctl.IsHandleCreated == true) 
        { 
            ControlFuncContext fc = new ControlFuncContext(ctl, action); 
            ctl.Invoke(new Action(fc.Invoke0)); 
        } 
    }

    public static void InvokeAction(this Control ctl, Action action, T obj) 
    { 
        if (ctl.IsHandleCreated == true) 
        { 
            ControlFuncContext fc = new ControlFuncContext(ctl, action); 
            ctl.Invoke(new Action(fc.Invoke1), obj); 
        } 
    }

    public static void InvokeAction(this Control ctl, Action action, T0 obj0, T1 obj1) 
    { 
        if (ctl.IsHandleCreated == true) 
        { 
            ControlFuncContext fc = new ControlFuncContext(ctl, action); 
            ctl.Invoke(new Action(fc.Invoke2), obj0, obj1); 
        } 
    } 
}

使用起来很简单,直接调用扩展方法 InvokeAction 即可,不必去考虑跨线程还是不跨线程这些“环境因素”,跨线程调用,我们已经通过用户不必知晓的方式,把它封装起来了。

再举个例子,写程序经常需要这样一个功能:打开一个图像文件,然后进行处理。正常写法很麻烦,比如,那个filter格式就很容易忘记,那么,我们就把它闭包化,把不该让用户知道,不该让用户敲键盘的都给它封装起来:

public static void OpenFile(this Form element, Action callbackOnFilePath, String filter = “所有文件|.”)

    {
        String filePath;

        OpenFileDialog dlg = new OpenFileDialog();

        dlg.Filter = filter;

        dlg.FileOk += (object sender, CancelEventArgs e) =>

        {
            filePath = dlg.FileName;

if (callbackOnFilePath != null)

                callbackOnFilePath(filePath);

        };

        dlg.ShowDialog();

    }

public static void OpenImageFile(this Form element, Action callbackOnFilePath, String filter = “图像文件|.bmp;.jpg;.gif;.png”)

    {
        OpenFile(element, callbackOnFilePath, filter);

    }

再举一个例子,这个例子是as3中的。在Flex中,控件有一个callLater 方法,在下一帧时进行调用。这个方法非常有用,很多时候,非Flex项目也需要这样的一个方法。下面,我们进行模拟:

package orc.utils
{
import flash.display.Stage;
import flash.events.Event;

public class CallLaterHelper 
{ 
    public function CallLaterHelper(stage:Stage, callback:Function) 
    { 
        this.callback = callback; 
        this.stage = stage;

        stage.addEventListener(Event.ENTER_FRAME, onStageEnterFrame); 
    } 
    private var stage:Stage; 
    private var callback:Function; 
    private function onStageEnterFrame(event:Event):void 
    { 
        stage.removeEventListener(Event.ENTER_FRAME, onStageEnterFrame); 
        if(callback != null) 
        { 
            callback(); 
        } 
    } 
} 

}

然后在基础控件中,提供callLater方法:

public function callLater(callback:Function):void
{
new CallLaterHelper(this.stage,callback);
}

总结:

(1)闭包是一种设计原则,它通过分析上下文,来简化用户的调用,让用户在不知晓的情况下,达到他的目的;

(2)网上主流的对闭包剖析的文章实际上是和闭包原则反向而驰的,如果需要知道闭包细节才能用好的话,这个闭包是设计失败的;

(3)尽量少学习。

特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集、类型、方法、属性等)相关联。特性与程序实体关联后,即可在运行时使用名为“反射”的技术查询特性。这篇文章绝大部分是按照MSDN来学习的,只是加了一点点自己的东东,官方介绍的很详细,我们就一起来了解一下它的用法。

特性具有以下属性:

特性可向程序中添加元数据。元数据是有关在程序中定义的类型的信息。所有的 .NET 程序集都包含指定的一组元数据,这些元数据描述在程序集中定义的类型和类型成员。可以添加自定义特性,以指定所需的任何附加信息。

可以将一个或多个特性应用到整个程序集、模块或较小的程序元素(如类和属性)。

特性可以与方法和属性相同的方式接受参数。

程序可以使用反射检查自己的元数据或其他程序内的元数据。
这些都是官方的定义,那么对于一个初学者来说,看的懂汉字不难,但是上面的元数据是什么?

我这么通俗的解释下:

你注意过程序及编译的时候的pdb文件了吗?pdb文件里面存储了,关于程序集内部的所有的成员信息,例如,成员的数据类型,属性类型,方法返回值,方法入参类型,就是程序及内部所有的定义信息的数据信息,是存储定义信息的一类数据信息,程序集里面的所有的关于声明类的数据信息,包括方法间调用,都是存储在元数据里面。

下面开始一同学习特性的用法:

特性可以放置在几乎所有的声明中。在 C# 中,特性的指定方法为:将括在方括号中的特性名置于其应用到的实体的声明上方。

你可能感兴趣的:(C#,多线程,C#异步,开闭原则,命令模式,后端)