终于下签了!!!

经过三年的漫长等待,澳洲移民局终于给我们发签了!!! 我们于2019年11月提交PR签证申请,年底新冠疫情笼罩国内,接着扩散到全世界,各国关闭边境,澳洲也经历了封锁和开放,今年年初工党上台,承诺加快签证审批,我们终于迎来曙光。 两个月前收到co的邮件,要求补充体检和无犯罪证明,现在终于正式获得了PR,想起第一次有migration的念头已经是五年前,小熊说我们的五年计划似乎都实现了。 世界杯揭幕战的时候,我脑子里闪过南非世界杯和巴西世界杯等等时刻,那时候我们全国、全球随便跑,当时突然觉得有一种想哭的感觉,这个世界原本不应该如此封闭,人不应该被困起来,那一晚我对完全的自由有了极大的渴望。 两周之后,国内居然突然以惊人的速度彻底放开,方向我支持,但速度太快了,但是箭已发出不可能回头,我们只能多做防护。 昨天世界杯决赛,梅西拿到了大力神杯,承载着80后青春记忆的一代球王终于圆梦。随着世界杯落下帷幕,也许真的可以看到世界慢慢恢复正常的曙光了,我对未来许下了美好的愿望,我们一定要实现,我们一定会实现。

December 20, 2022

C#泛型接口的协变和逆变

一、协变和逆变是什么? 先从字面上理解 协变(Covariance)、逆变(Contravariance)。 co- 是英文中表示“协同”、“合作”的前缀。协变 的字面意思就是 “与变化的方向相同”。 contra- 是英文中表示“相反”的前缀,逆变 的字面意思就是是 “与变化方向相反”。 官方:协变和逆变都是术语,前者指能够使用比原始指定的派生类型的派生程度更大(更具体的)的类型,后者指能够使用比原始指定的派生类型的派生程度更小(不太具体的)的类型。 那么问题来了,这里的“变化方向”指的是什么? C# 中对于对象(即对象引用),仅存在一种隐式类型转换,即 子类型的对象引用到父类型的对象引用的转换。这里的变化指的就是这种 子->父 的类型转换。 协变与逆变虽然从名字上看是两个完全相反的转换,但其实只是“子类型引用到父类型引用”这一过程在函数中使用的“两个不同阶段”而已,接下来将详细说明这点。 二、为什么需要协变和逆变 三、协变例子 四、逆变例子 五、.NET自带的协变和逆变委托和泛型

October 21, 2022

C#委托之Action和Func的用法

我们在使用委托的过程中,除了为每个参数和返回类型定义一个委托之外,也就是说为每一个方法(作为参数的方法)定义一个委托,我们还可以使用Action和Func委托。 泛型Action委托表示引用一个void返回类型的方法。Action委托类存在不同的变体,可以传递至多16种不同的参数类型,没有泛型参数的Action类可以调用没有参数的方法。例如:Action调用带一个参数的方法,Action<in T1,in T2>调用带两个参数的方法等 Func的用法和Action用法类似,但是Func表示引用一个带返回类型的方法,Func也存在不同的变体,至多可以传递16个参数类型和1个返回类型,例如:Func<in T1,out Resout>表示带一个参数的方法,Func<in T1,in T2,out Resout>表示调用带两个参数的方法。 总结 1:Action用于没有返回值的方法(参数可以根据自己情况进行传递);2:Func恰恰相反用于有返回值的方法(同样参数根据自己情况情况);3:记住无返回就用action,有返回就用Func

October 20, 2022

Azure Container App 应用介绍

容器技术正日益成为打包、部署应用程序的第一选择。Azure提供了许多使用容器的选项。例如,我们可以使用Azure容器注册表来存储和管理Docker Images。Azure Container Instance或Azure应用服务可用于运行隔离容器。对于需要完整容器编排、自动缩放和服务发现的更复杂的场景,Azure Kubernetes服务是一个很好的选择。问题是,Azure Kubernetes虽然是托管的,但 用起来还是有些困难,开发人员必须得学习掌握一些运维知识。 2021年,Azure提出了新服务 Azure Container App。该服务旨在减少构建 AKS 应用程序所需的知识和配置量,从而可能降低解决方案成本并加快上市时间。 1,什么是 Azure Container App ?? Azure Container App 提供位于 AKS 服务之上的无服务器托管服务,允许您部署多个容器而无需处理底层基础结构。事实上,Azure Container App 甚至不向用户公开 Kubernetes API。 当我们在 Azure Container App中部署或更改容器时,该服务将自动创建应用程序的快照—–修订版,并在一个 pod 中运行它的容器。就像在 Azure Kubernetes 中一样,这些容器共享相同的应用程序生命周期、网络和磁盘。它们可以相互交流。此外,由于它与基于 Kubernetes 的事件驱动自动缩放的集成,该服务将根据 HTTP 并发请求数等指标自动增加/减少(不支持垂直缩放)与修订相关的 Pod 数量和内存使用。作为节省一些费用上开支,我们还可以将最小副本数设置为 0。如果应用程序没有请求,该服务会将活动 pod 的数量缩减为 0,我们无需支付任何费用。 同时多个 Azure Container App 也可以部署到单个环境中。通过这样做,它们将被置于同一个虚拟网络下并与外界隔离。为了提供监视功能,每个环境都有自己的 Log Analytics 工作区,该工作区与其中的 Azure Container App共享。对于熟悉 Kubernetes 的人来说,我们可以将 Azure Container App Environment 视为 Kubernetes Namespace,将 Azure Container App Revision 视为 Kubernetes Deployment。 ...

October 10, 2022

时隔将近三年,终于分co了

从提交PR申请今天,已经过去了将近三年时间!今天收到IMMI的邮件,要求补无犯罪记录证明和全家体检,其实这两项早在疫情前一个月我们提交申请的时候就已经完成,但是因为有时效性,只能重新补。 2019年底,眼看着马上要审理我们的case,国内突发疫情,澳洲移民局直接把中国所有的cases都hold on了。后来疫情蔓延至全球,澳洲关闭边境,所有offshore的cases都暂停。今年澳洲完全放开国门,前几个月大选换了总理,终于开始加速审理我们这些被滞留的cases,这一晃已经三年时间。 这三年深刻影响了每一个人,全球化停止了,随着各国民族主义的崛起,世界已经不再友好,一切都已经回不去了。而也正是在这三年时间,我静下来(重)读了很多书,从文学到中国文化、从历史到政治哲学,因为拥有科学上网的能力,能看到未删减的图书,得以获得信息全貌,逐渐形成自己牢固的思想。 今天已经预约体检,并申请了无犯罪记录证明,后续按部就班完成各项事宜,希望这次真的Granted Directly

September 25, 2022

依赖注入简单易懂的详解

之前记录的依赖注入太复杂,今天认真看了《C#高级编程》里面对依赖注入的解释,明显就简单很多。 1、什么是依赖注入?为什么需要它? 更快的开发周期需要单元测试和更好的可更新性。更改一些代码,不应该导致意外位罝出现错误。创建更模块化的、减少依赖项的应用程序,有助于防止这种错误。 依赖注入(Dependency Injection,DI)允许从类的外部注入依赖项,因此注入依赖项的类只需要知道一个协定(通常是C#接口)。这个类可以独立于其对象的创建。 依赖注入更便于进行单元测试。在单元测试中,只需要测试特定的类,需要的依赖项可以替换为包含测试数据的特殊模拟类。 还可以使用不同的实现区分生产模式和开发模式。例如,在生产过程中,可能需要访问SAP服务器,或者可能需要对所有开发人员都无法访问的特定活动目录进行身份验证。在开发的每个调试会话期间,都不希望等待成功的身份验证,也不需要SAP服务器开发用户界面。在这里,可以给相同的协定使用不同的实现来模拟身份验证,可以使用测试数据而不是访问SAP服务器。 也可以在不同的平台上使用不同的实现。例如,可以创建一个.NET标准库,在其中为UWP、WPF和Xamarin应用程序实现所有公共功能,并可以根据需要重定向到特定于平台的代码。 依赖注入还允许用自定义特性替换标准功能。ASP.NETCore和EntityFrameworkCore主要基于依赖注入。这些技术使用数百个协定一例如,来找到控制器,将HTTP请求映射到控制器,将接收到的数据转换为参数,将数据库表映射到实体类型等。使用不同的实现,可以轻松地替换自定义功能。 DI是敏捷软件开发和持续软件交付实践的核心模式。 依赖注入不需要依赖注入容器,但该容器有助于管理依赖项。 依赖注入容器管理的服务列表越来越长,就可以看到它的优点。ASP.NETCore和EntityFrameworkCore使用Microsoft.Exteosions.DependencyInjection作为容器来管理所有依赖项,以此管理数百个服务。 尽管依赖注入和依赖注入容器在非常小的应用程序中会增加复杂性,但是一旦应用程序变得更大,需要多个服务,依赖注入就会降低复杂性,并促进非紧密绑定的实现。 2、没有依赖注入 下面的示例没有使用依赖注入;稍后将更改它,以使用依赖注入。所用的服务实现在类GreetingService中定义。这个类定义了返回字符串的Greet方法: public class GreetingService { public string Greet(stringname)=>$"Hello,{name}"; } 类HomeController使用这个服务。在Hello方法中,实例化了GreetingService,并且调用Greet方法: public class HomeController { public string Hello(string name) { var service = new GreetingService(); return service.Greet(name); } } 下面看看Program类的Main()方法。其中实例化了HomeController,调用Hello方法,将结果写入控制台: static void Main() { var controller=new HomeController(); string result=controller.Hello("Stephanie"); Console.WriteLine(result); } 程序运行时,把Hello,Stephanie写入控制台。这有什么问题吗? HomeController和GreetingService是紧密稱合的。要用不同的实现取代HomeController中的GreetingService并不容易。 这个GreetingService是一个返回字符串的简单服务。在正常的应用程序中,场景通常更复杂。例如,GreetingService可能使用HTTP请求访问API服务,或者使用EntityFramewoik访问数据库。可能要更改在一个地方使用的服务,而不是査找使用服务的所有位置。 另外,为HomeController创建单元测试时,也会测试GreetingService。在单元测试中,希望仅测试单个类的方法的功能,而不需要使用其他依赖项。在HomeController中,不能很容易地为单元测试替换GreetingService。从技术上讲,为单元测试替换GreetingService方法的内部实现是可能的。使用Microsoft Fakes框架,可以通过替换GreetingSeivice类的特定方法和属性,来更改方法的实现。这个变更是在单元测试中定义的,并且只有在单元测试运行时才会发生:通过另一个方法来“伪造”原来的方法。其实这有更好的方法:使用依赖注入。 下一节将介绍如何更改此实现,以使用依赖注入。 3、使用依赖注入实现 下面使HomeController独立于GreetingService的实现。为此,可以创建接口IGreetingService,它定义了HomeController所需的功能: public interface IGreetingService { string Greet(stringname); } GreetingService现在实现了接口IGreetingService: public class GreetingService:IGreetingService { public string Greet(stringname)=>$"Hello,{name}"; } HomeController现在只需要对一个对象的引用,该对象实现了接口IGreetingService。它用HomeController的构造函数注入,分配给私有字段,通过方法Hello来使用: public class HomeController { private readonly IGreetingService _greetingService; public HomeController(IGreetingService greetingService) { _greetingService=greetingService?? throw new ArgumentMullException(nameof(greetingService)); } public string Hello(stringname) => _greetingService.Greet(name); } 在这个实现中,HomeController利用了控制反转的设计原理。HomeController没有像以前那样实例化GreetingService。相反,定义由HomeController使用的具体类的控件在外部给出;换句话说,控制是反转的。 ...

September 9, 2022

https请求报错block:mixed-content

开发过程中,可能会遇到在https里面请求内容的时候报混合调用的错误,一般是因为网站启用了https,但是老的网页链接和请求中还有使用http的情况。接口会错block: mixed-content,图片则会报错:Mixed block。解决的办法有两种。 第一种, 页面的head中加入下面代码(将调用的http请求升级成https请求并调用): <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> 这是最方便快捷的,也是很有效的办法。 第二种, 如果是接口,可以通过本地后端(将本地后端当成service中间层),从后端再去调用其他服务器的http请求。

September 5, 2022

如何在.NET Core3.1使用log4net

1、添加log4net程序集 通过nuget添加,可以直接在程序集引用里搜索nuget包安装,也可以通过命令行安装,这里使用命令行:PM> Install-Package log4net 2、添加log4net.config配置文件 创建一个log4net.config文件,保存在项目的根目录: <log4net> <root> <level value="ALL" /> <appender-ref ref="console" /> <appender-ref ref="file" /> </root> <!--File Appender--> <appender name="file" type="log4net.Appender.RollingFileAppender"> <file value="main.log" /> <appendToFile value="true" /> <rollingStyle value="Size" /> <maxSizeRollBackups value="5" /> <maximumFileSize value="25MB" /> <staticLogFileName value="true" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %level %logger - %message%newline" /> </layout> </appender> <!--Console appender--> <appender name="console" type="log4net.Appender.ManagedColoredConsoleAppender"> <mapping> <level value="INFO" /> <forecolor value="Green" /> </mapping> <mapping> <level value="WARN" /> <forecolor value="Yellow" /> </mapping> <mapping> <level value="ERROR" /> <forecolor value="Red" /> </mapping> <mapping> <level value="DEBUG" /> <forecolor value="Blue" /> </mapping> <layout type="log4net.Layout.PatternLayout"> <conversionpattern value="%date [%thread] %-5level - %message%newline" /> </layout> </appender> </log4net> 3、加载log4net的配置的并创建相关实例 这里有两种办法,第一种最简单 ,这种情况适用于控制台应用程序,简单明了,直接用加载到程序集中: ...

August 23, 2022

亲子沟通提示:重视亲子沟通

一、耐心、认真地去“听”你的孩子讲话 有时当妈妈一边炒菜一边盛饭时,孩子在想跟妈妈说些什么时,妈妈有时是不经心地听着,有时会打断她,反而请她帮忙摆桌吃饭,但从未停下来,专心去“听”她想说的话,除非她说的话,真是什么天大的好消息(不过,这种机率低于百分之一)。 这里不是教您一定要停下手边所做的,但你可给孩子一个“确定”的时间,比如:“好,等我把饭菜摆好。”或是“再给我一分钟。“当然,最好是立即去“听”孩子要说的。 因为,你一次,二次,三次地忽略了他们后,他们便会慢慢地失去了"告诉你”的兴趣。另外,在“听”时,最好做目光接触,要孩子知道你是直的愿意听。很多时候,孩子不过想说你觉得不太要紧的事,但对他们而言,却是重要的。如果你没有经常拒绝他们,当他们真遇到困难时,自然就会地来找你谈了。 二、有些话不能说,以免伤害到孩子的感情 家长不要说一些孩子最不想听的话,即使在盛怒的时候,也要思考话语的轻重,以免伤害孩子的感情。 另外,孩子的世界与想法是和大人们不同的,当孩子很认真地告诉你什么时,你如果取笑孩子,或者有轻蔑或不相信的态度,也会伤害孩子,这样孩子以后也就不再愿意跟你谈了。 三、有意识地与孩子进行沟通,主动分享自己的感受 多与孩子说说自己的感受和以往的经历,让孩子走进自己,向孩子表达自己的期待和需求。 当然,做父母的,不需要把心中的担心向孩子表明,去增加孩子担忧的心理负担,但有时不妨主动地与孩子分享自己的心情、感受,及对事情的看法,孩子当然也就比较容易向你诉说他的心情、感受与看法了。 四、重视沟通的方法,别问一些太空洞的问题 譬如“今天如何?”“学校好吗?”也别常用,“为什么?”因为孩子会不自觉地想保护自己。以询问孩子一些有趣的、愉快的事情作为聊天的开场白。愉快的开始,能营造良好的沟通氛围,促进亲子沟通。 了解孩子的兴趣,了解现在孩子与同龄人中流行的东西 ,包括儿歌、动画片,故事书等,与孩子一起做他感兴趣的事,进行积极沟通,让孩子感受到父母对自己的关心,他会更愿意与家长沟通。 五、了解孩子的想法,理解孩子要表达的意思 由于孩子的表达能力条理性较差,因此孩子有时不能清晰表达自己 。家长要耐心等孩子把话说完,把“零散”的东西拼凑起来,准确理解孩子要表达的意思。 大部分时间,孩子只是想从他信任的成人中,确定自己的想法与做法 。所以,家长可在了解情况后,做个回答或支持。

August 15, 2022

ABP框架能力清单

ABP框架提供了一个稳定的架构用于构建企业级软件解决方案,它遵循了.NET和ASP.NETCore平台之上的最佳实践。它内置了基础架构、生产级别的模块、主题、工具、指南和文档,并尽可能地自动化开发细节和解法我们的重复性工作。 在接下来的几个小节中,我将从架构层面介绍ABP是如何完成所有这些工作。 ABP架构 ABP是一个特殊的架构,换句话说,它是一个有个性化的框架。先解释一下什么是没有个性的框架,什么是有个性的框架。 正如我在搭建架构部分所述,为搭建解决方案的基础设施需要大量决策工作;比如系统架构、开发模型、技术、模式、工具和库。 没有个性的框架,例如ASP.NETCore,这些决定大多由您决定。例如,您可以通过将UI层与数据访问层分离来创建分层解决方案,或者您可以通过直接从UI页面/视图访问数据库来创建单层解决方案。您可以使用任何库,只要它与ASP.NETCore兼容,并且您可以应用任何架构模式。无个性使ASP.NETCore在不同的场景中变得灵活和可用。但是,所有的这些都需要我们自己去做决策。 我并不是说ASP.NETCore完全没有自己的个性想法。假定您正在构建基于HTTP规范的Web应用程序或API。它清楚地定义了应该如何开发UI和API层。它还提供了一些低级的基础设施组件,例如依赖项注入、缓存和日志记录。但是,它并没有说明您的业务代码是应该要如何组建,应该使用哪些架构模式。 换句话说,ABP框架是一个有个性倾向的框架。它相信软件开发方法本质上可以更好,因此可以引导开发人员在解决方案中使用更佳的架构、模式、工具和库。 尽管ABP框架足够灵活,可以使用不同的工具和库来改变您的架构决策,但当您遵循它的实践原则时,您将获得最大的价值。请别担心,因为它为通用架构提供了良好的、行业认可的解决方案。他的架构规则将节省您的时间,提高您的生产力,并使您专注于您的业务代码而不是基础设施问题。 在接下来,我将介绍ABP所支持的四种基本架构。 领域驱动设计 ABP的主要目标是根据整洁代码原则提供一个模型来构建易维护的解决方案。它提供了一个基于DDD模式和实践的分层架构。它提供了一个分层的启动模板、基础架构以及架构应用指南。 由于ABP是一个软件框架,它专注于DDD的技术实现。本书的第3部分,实现领域驱动设计,解释了使用ABP框架构建基于DDD的最佳实践。 模块化 在软件开发中,模块化是一种拆分系统成独立模块的技术。最终目标是降低复杂性,提高可重用性,使不同的团队能够在不相互影响的情况下能并行处理不同的功能集。 ABP构建模块化有两个主要挑战: 第一个挑战是模块隔离。尽管ASP.NETCore有一些特性(例如Razor组件库)来支持模块化。但是,它仍然非常有限,因为它是一个底层通用的框架,并且仅对UI和API部分支持。另一方面,ABP框架提供了一个一致的模型和基础设施来构建完全隔离的、可重用的应用模块及数据库、领域、应用和UI层。 第二个挑战是模块之间如何通信,使之成为一个统一的应用程序。ABP为模块化系统提供常见的模型,例如在模块之间共享数据库,在模块之间通过事件或API进行通信,以及模块安装。 ABP提供了许多可在任何应用程序中使用的预构建模块。包括身份验证模块,它提供用户、角色和权限管理,同时也提供登录和注册页面。他们基本上都是可重用和自定义的。此外,ABP提供了模块启动模板,帮助您构建可重用的应用程序。这方面的一个例子可以在[第15章]使用模块化中详细介绍。 模块化非常适合管理复杂的大型单体系统。但是,ABP也可以帮助您创建微服务解决方案。 微服务 微服务和分布式架构是构建可扩展系统的公认方法。它允许不同的团队开发不同的服务并独立地对服务进行单独部署和扩展。 但是,构建微服务系统在团队开发、部署、微服务间通信、数据一致性、监控等方面存在一些重要挑战。 微服务系统是一种将不同的学科、方法、技术和工具结合在一起来解决独特问题的解决方案。每个微服务系统都有其要求和限制。每个团队都有一定程度的专业知识、知识和技能。 ABP框架从一开始就被设计为与微服务兼容。它在具有事务支持的微服务之间提供了一个用于异步通信的分布式事件总线。它还提供C#客户端代理来轻松调用远程服务的RESTAPI。 所有预构建的ABP应用模块都经过设计,以便您可以将它们转换为微服务。ABP也提供了详细指南来解释如何创建微服务兼容模块。这样,您可以从模块化单体开始,然后将其转换为微服务解决方案。 ABP团队准备了一个使用ABP框架构建的开源微服务参考方案。它演示了如何使用API网关、微服务间通信、分布式事件、分布式缓存、多个数据库提供程序和多个UI应用程序。它还包括在容器上运行解决方案的Kubernetes和Helm配置。详情参阅。 SaaS/多租户 软件即服务(SaaS)是一种广泛使用的架构模式。以下是多租户系统的典型特征: 在租户之间共享硬件和软件资源。每个租户都有用户、角色和权限。在租户之间隔离数据库、缓存和其他资源。可以启用/禁用每个租户的应用功能。可以为每个租户自定义应用配置。 ABP框架涵盖了所有这些要求甚至更多。它可以帮助您优雅地构建多租户系统,而您几乎感受不到多租户的存在。 到目前为止,我已经介绍了四种ABP基本架构模式。此外,ABP还提供了启动模板来轻松创建新的解决方案。 启动模板 使用ASP.NETCore自带的模板创建新解决方案时,只能获得单个项目,没有分层和依赖关系。您通常会花费大量时间来设置解决方案架构,包括安装工具和做配置基本。 ABP框架提供了一个架构完善、分层清晰、预配置和生产就绪的启动解决方案模板。以下截图显示了当您运行ABP框架创建的启动模板时的初始UI: 下面谈谈这个启动模板:解决方案已经做好逻辑分层。一些预构建模块,例如Account和Identity模块。已经实现了基本的登录、注册、用户和角色管理以及其他一些标准功能。预先配置好的单元测试和集成测试项目。一些管理数据库迁移以及使用HTTPAPI实用工具。 ABP的启动模板带有UI框架和数据库提供者的多个选项。你可以从Angular、Blazor或MVC(RazorPages)选择一个作为UI框架,或者使用EntityFrameworkCore或MongoDB作为数据库提供者。 ABP基础设施 ABP基于您已经了熟悉的工具和库。它没有引入新的对象关系映射器(ORM),而是使用EntityFrameworkCore。同样,它使用Serilog、AutoMapper、IdentityServer和Bootstrap,而不是自己创建类似的功能。它提供了一个解决方案集成了这些工具,并实现了常见的业务应用需求。 ABP框架按照约定简化了异常处理、验证、授权、缓存、审计日志和数据库事务管理,并允许您在需要时进行精细控制。 ABP与IdentityServer很好地集成,基于cookie和令牌的身份验证以及单点登录。它还提供了一个详细的、基于权限的授权系统来帮助您控制应用的权限。 同时也提供了后台作业、BLOB存储、文本模板、审计日志和本地化等常见组件。 在UI部分,ABP提供了完整的UI主题系统,帮助您开发无主题的模块化应用,并轻松为应用程序安装主题。它还在UI方面提供了大量功能和帮助程序,以消除重复代码。 社区 当您在公司中搭建解决方案架构时,除了开发人员没有人会去研究它。然而,ABP拥有一个庞大而活跃的社区。他们使用相同的架构和基础设施,应用类似的最佳实践,并以类似的方式开发他们的应用程序。当您遇到基础架构问题或想要获得解决业务问题的想法或建议时,这具有很大的优势。由于ABP开发人员正在应用相同或相似的模式,因此在另一个解决方案中也更容易理解他人的代码。 ABP框架自2016年以来一直存在并不断发展。截至2021年底,它在GitHub上拥有7,000多颗星、220多位贡献者、22,000多个提交、5,700个已关闭问题,以及在NuGet上超过4,000,000次下载,超过110多个专业和次要版本。我的意思是,它是一个成熟的、被接受的、值得信赖的开源项目。 来自ABP核心团队和社区的贡献者,有着不断持续输出的文章,视频教程和ABP社区网站可供大家学习。

July 8, 2022