08
5

最近创建基于firstcode的开发模式,整理了一下如何使用Entity Framework Core 创建DbContext。

1、第一种重写DbContext的OnConfiguring方法,每次生成一个DbContext的方法的时候就会重新来这个方法这里读一下配置。

这种情况下,首先尝试通过调用 Program.CreateHostBuilder()、调用 Build(),然后访问 Services 属性来获取服务提供程序。

public class Program
{
    public static void Main(string[] args)
        => CreateHostBuilder(args).Build().Run();

    // EF Core uses this method at design time to access the DbContext
    public static IHostBuilder CreateHostBuilder(string[] args)
        => Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(
                webBuilder => webBuilder.UseStartup<Startup>());
}

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
        => services.AddDbContext<ApplicationDbContext>();

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
    }
}

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
}

2、使用不带参数的构造函数

这种情况就是在已经注入的情况下,就不再需要自己去New一个对象了,直接在使用的地方把DbContext 当成构造参数传进来

如果无法从应用程序服务提供程序获得 DbContext,则这些工具将查找项目中的派生 DbContext 类型。 然后,它们尝试使用不带参数的构造函数创建实例。 如果 DbContext 是使用 OnConfiguring 方法配置的,则这可以是默认构造函数。

从设计时工厂还可以通过实现 Microsoft.EntityFrameworkCore.Design.IDesignTimeDbContextFactory 接口来告知工具如何创建 DbContext:如果在与派生的 DbContext 相同的项目中或在应用程序的启动项目中找到实现此接口的类,则这些工具会绕过创建 DbContext 的其他方式,转而使用设计时工厂。

public class BloggingContextFactory : IDesignTimeDbContextFactory<BloggingContext>
{
    public BloggingContext CreateDbContext(string[] args)
    {
        var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
        optionsBuilder.UseSqlite("Data Source=blog.db");

        return new BloggingContext(optionsBuilder.Options);
    }
}
07
4

C#实现两个顺序链表的合并

0
归档:2023年4月分类:C#和.NET

最近开始刷leetcode,刷了一周时间,确实会上瘾,不过能巩固很多基础知识,包括算法和语言。我现在是架构与编码并行。今天遇到的是两个列表的合并,刚开始我自己写了一个笨方法来合并,虽然通过了测试,但是代码质量不高,于是研究了其他人写的代码。

//传入的两个链表本身是从小到大排序好
public ListNode MergeTwoLists(ListNode list1, ListNode list2)
{
    ListNode head = new ListNode(); //定义新的链表头
    ListNode current = head;//定义链表最新的next地址
    //遍历两个链表,任何一个完毕后就终止循环
    while (list1 != null && list2 != null)
    {
        if (list1.val < list2.val)
        {
            //如果list1的元素值小,则把当前list1赋予current.next,注意这里相当于head.next
            current.next = list1;
            list1 = list1.next;
        }
        else
        {
            current.next = list2;
            list2 = list2.next;
        }
        //将current变量指向current.next,相当于head.next,当进入下一次循环给current.next赋值的时候,相当于是给head.next.next赋值了,一直这么循环到最后
        current = current.next;
    }
    //head链表的next指向未循环完成的部分
    current.next = list1 == null ? list2 : list1;
    //返回合并后的链表
    return head.next;

}

我刚开始发懵了,居然没理解这部分代码,因为忽略了“每次循环之后current的引用指向已经发生变化”。

07
4

赋值和深复制、浅复制并不是一样的,含义是不一样的。赋值。指的是 “ 等号= ”。它相当于是给引用对象起一个别名。浅度复制和深度复制。指的是类实现 ICloneable接口,重写该接口的唯一方法。注意:不管是深度复制还是浅度复制,都是通过ICloneable接口去实现的。

值类型变量存储的是变量的值,直接储存在栈内存中。引用类型变量存储的是变量所在的内存地址,引用类型变量的实际数据存储于托管堆,变量本身仅仅是一个指向堆中实际数据的地址,存储于栈内存中,通常是四个字节。

值类型Value存储在线程堆栈中。引用类型Reference存储在托管堆上。

全局数据区:存放全局变量,静态数据,常量。代码区:存放所有的程序代码。栈区:存放为运行而分配的局部变量,参数,返回数据,返回地址等。堆区:即自由存储区

为了理解值类型变量和引用类型变量的内存分配模型,我们应先区分两种不同的内存区域——线程堆栈Thread Stack和托管堆Managed Heap。每一个正在运行的程序都对应着一个进程Process,在一个进程内部,可以有一个或多个线程Thread,每个线程都拥有一块“自留地”,成为线程堆栈,大小为1M,用于保存自身的一些数据,如函数中定义的局部变量、函数调用时传送的参数值等。现在我们可以解释第一句话——值类型存储在线程堆栈中,也就是说所有值类型的变量都是在线程堆栈中分配的。另一块内存区域称为堆Heap,在.NET这种托管环境下,堆由CLR(Common Language Runtime)管理,所以又称托管堆Managed Heap。例如使用new关键字创建类的对象实例时,分配给对象的内存单元就位于托管堆中。

1、赋值。赋值和深度复制,浅度复制完全是不同的概念,并没有什么关系,很多文章说赋值对于值类型是深度复制,对于引用类型是浅度复制,这种说法是不正确的,它的本质是在线程栈上产生一样的副本。

2、浅度复制。值类型成员独立,但是引用类型成员共享。

3、深度复制。值类型成员和引用类型成员都是独立的,即完完全全的一个全新的副本,称之为深度复制。

(1)String字符串对象是引用对象,但是很特殊,它表现的如值对象一样,即对它进行赋值,分割,合并,并不是对原有的字符串进行操作,而是返回一个新的字符串对象。但这其实是运算符重载的结果,将string实现为语义遵循一般的、直观的字符串规则。 String对象被分配在堆上,而不是栈上。

(2)Array数组对象是引用对象,在进行赋值的时候,实际上返回的是源对象的另一份引用而已;因此如果要对数组对象进行真正的复制(深拷贝),那么需要新建一份数组对象,然后将源数组的值逐一拷贝到目的对象中。

12
1

.NET7下string的改进

0
归档:2023年1月分类:C#和.NET

string是开发过程中,使用频度最高的类型之一,所以在构建类型时作了很多处理,如“不可变性”,“保留性”等特点。string的常量是在""引号中进行赋值的。

var str1 = "这是一段文字";
Console.WriteLine(str1);

为了字符串的格式化,引入了$""定义方式,这样就可以在字符串中用{}来标注格式化的内容了。

var str2 = $"时间:{DateTime.Now}";
Console.WriteLine(str2);
//输出结果是:时间:1/6/2023 15:37:13

var str2_1 = $"时间:{DateTime.Now:yyyy-MM-dd}";
Console.WriteLine(str2_1);
//输出结果是:时间:2023-01-06

为了解决字符串内容的换行,引定入@"",来定义有换行的字符串,比如下面的一条SQL查询,可以按格式化后的样式来定义。$和@可以混用,不分先后。

var str3 = @"SELECT ID
    ,Question
    ,Score
    ,QuestionTypeID
    ,SubjectTypeID
    FROM Questions";
Console.WriteLine(str3);

var str3_1 = @$"SELECT ID
    ,Question
    ,Score
    ,QuestionTypeID
    ,SubjectTypeID
    FROM Questions WHERE Score>{10}";
Console.WriteLine(str3_1);

其实原始字符串还解决了一个问题,就是字符串中有"的问题,以前需要有转义字符来实现,现在原始字符串都搞定了。

Console.WriteLine("\"a\" 是小写的");//通过\来转义
Console.WriteLine(@"""a"" 是小写的");//前缀是@时,通过"转义

最佳demo是json字符串的定义,用原始字符串的方式定义json字符串,最合适不过了。

var jsonString = """
                 {
                     "irstName": "John",
                     "astName": "Smith",
                     "ex": "male",
                     "ge": 25,
                     "ddress": 
                     {
                         "treetAddress": "21 2nd Street",
                         "ity": "New York",
                         "tate": "NY",
                         "ostalCode": "10021"
                     }
                 }
                 """;

Console.WriteLine(jsonString)

通过下图,看到的json原始字符串,一目了然:

02
1

[转]NPM和webpack的关系

0
归档:2023年1月分类:C#和.NET

入门前端的坑也很久了,以前很多大小项目,前端都是传统式开发,一直在重复造轮子;接触VUE后,对vue-cli有了解后,仅仅知道vue-cli是一个vue项目的脚手架,可以快速的构建一个vue的基于npm的模块化项目,vue内部的打包机制其实还是借助webpack;但是对webpack\npm\node\nodejs这几个在前端模块化中的高频词总是傻傻分不清,不知道他们之间的具体关系,今天花了些功夫查阅了网上大神的回答和官方教程给出的解释写一篇小白文,总结一下这几个概念或者说高频词汇之间的关系

what is webpack?

Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。即WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。

webpack的核心作用

模块化开发中,我们会编写大量模块,如果不打包就上线,那么页面加载或交互时,将会发起大量请求。为了性能优化,需要使用webpack这样的打包器对模块进行打包整合,以减少请求数。就像简单的vue项目,所有组件最终都将被打包到一个app.js中。
相较于无差别打包依赖模块的传统打包器,webpack的核心优势在于它从入口文件出发,递归构建依赖关系图。通过这样的依赖梳理,webpack打包出的bundle不会包含重复或未使用的模块,实现了按需打包,极大的减少了冗余。

webpack是一个工具,这个工具可以帮你处理好各个包/模块之间的依赖关系(modules with dependencies),并将这些复杂依赖关系的静态文件打包成一个或很少的静态文件,提供给浏览器访问使用;除此之外,webpack因为可以提高兼容性,可以将一些浏览器尚不支持的新特性转换为可以支持格式,进而减少由新特性带来的浏览器的兼容性问题。

好,我们通过介绍,我们有个概念,webpack是一个打包工具,可以帮你把你的项目这里的项目其实就是指通过模块化开发的项目 打包为简洁版的浏览器可识别的静态资源。

what is npm?

介绍了webpack,我们可能会疑问,我的JS,CSS,HTML文件分开写,挺好的呀,为什么要使用webpack工具,进行复杂的各项配置。在传统前端开发模式下,我们确实是按照JS/CSS/HTML文件分开写的模式就可以,但是随着前端的发展,社区的壮大,各种前端的库和框架层出不穷,我们项目中可能会使用很多额外的库,如何有效管理这些引入的库文件是一个大问题,而且我们知道基于在HTML中使用script引入的方式,有两个弊端,一个是会重复引入,二是当库文件数量很多时管理成为一个大难题。面对这样的局面,为了简化开发的复杂度,前端社区涌现了很多实践方法。模块化就是其中一项成功实践,而npm就是这样在社区 其实就是node社区中产生的。

npm 由三个独立的部分组成:网站、注册表(registry)、命令行工具 (CLI)。

网站 是开发者查找包(package)、设置参数以及管理 npm 使用体验的主要途径。
注册表 是一个巨大的数据库,保存了每个包(package)的信息。CLI 通过命令行或终端运行。开发者通过 CLI 与 npm 打交道。

一般来说提起npm有两个含义,一个是说npm官方网站,一个就是说npm包管理工具。npm社区或官网是一个巨大的Node生态系统,社区成员可以随意发布和安装npm生态中的包,也就是不用在重复造轮子了,别人造好了,你直接安装到你的项目中就可以使用,但是因为前面说了,当包引入数量很多时管理就成为了一个问题,这个就是npm为开发者行了方便之处,npm已经为你做好了依赖和版本的控制,也就是说使用npm可以让你从繁杂的依赖安装和版本冲突中解脱出来,进而关注你的业务而不是库的管理。

webpack就是将你从npm中安装的包打包成更小的浏览器可读的静态资源,这里需要注意的是,webpack只是一个前端的打包工具,打包的是静态资源,和后台没有关系,虽然webpack依赖于node环境。

what is node or nodejs?

其实node和nodejs两个概念没有太大差别,我个人认为唯一的区别就是,人们说起node的时候语境更多的是再说node环境,而说nodejs时更多的是在说node是一门可以提供后端能力的技术。本质上来说,node就是nodejs,nodejs就是node

简单的说 Node.js 就是运行在服务端的 JavaScript。Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。

node环境基于V8引擎提供了一种可以让JS代码跑在后端的能力,这就是node。其实这里的node本身和我们这篇讲的前端模块化没啥关系。但是因为npm是产生与node社区,node中也是通过npm来加载模块的,所以有必要说一下他们之间的关系。

npm 是 Node.js 官方提供的包管理工具,他已经成了 Node.js 包的标准发布平台,用于 Node.js 包的发布、传播、依赖控制。

webpack npm node之间关系?

webpack是npm生态中的一个模块,我们可以通过全局安装webpack来使用webpack对项目进行打包;

webpack的运行依赖于node的环境,没有node是不能打包的,但是webpack打包后的项目本身只是前端静态资源和后台没有关系,也就是说不依赖与node,只要有后台能力的都可以部署项目。

npm是于Node社区中产生的,是nodejs的官方包管理工具,当你下载安装好node的时候,npm cli 就自动安装好了。

正是因为npm的包管理,使得项目可以模块化的开发,而模块化的开发带来的这些改进确实大大的提高了我们的开发效率,但是利用它们开发的文件往往需要进行额外的处理才能让浏览器识别,而手动处理又是非常繁琐的,这就是webpack工具存在的意义

原文地址:https://blog.csdn.net/AngelLover2017/article/details/84801673

21
10

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

0
归档:2022年10月分类:C#和.NET

一、协变和逆变是什么?

先从字面上理解 协变(Covariance)、逆变(Contravariance)。

co- 是英文中表示“协同”、“合作”的前缀。协变 的字面意思就是 “与变化的方向相同”。
contra- 是英文中表示“相反”的前缀,逆变 的字面意思就是是 “与变化方向相反”。

官方:协变和逆变都是术语,前者指能够使用比原始指定的派生类型的派生程度更大(更具体的)的类型,后者指能够使用比原始指定的派生类型的派生程度更小(不太具体的)的类型。

那么问题来了,这里的“变化方向”指的是什么?

C# 中对于对象(即对象引用),仅存在一种隐式类型转换,即 子类型的对象引用到父类型的对象引用的转换。这里的变化指的就是这种 子->父 的类型转换。

协变与逆变虽然从名字上看是两个完全相反的转换,但其实只是“子类型引用到父类型引用”这一过程在函数中使用的“两个不同阶段”而已,接下来将详细说明这点。

二、为什么需要协变和逆变

三、协变例子

四、逆变例子

五、.NET自带的协变和逆变委托和泛型

20
10

C#委托之Action和Func的用法

0
归档:2022年10月分类:C#和.NET

我们在使用委托的过程中,除了为每个参数和返回类型定义一个委托之外,也就是说为每一个方法(作为参数的方法)定义一个委托,我们还可以使用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

10
10

[转]Azure Container App 应用介绍

0
归档:2022年10月分类:C#和.NET

容器技术正日益成为打包、部署应用程序的第一选择。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。

最后就是,Azure Container App 将可用选项减少为一个简单的入口切换,一旦启用,它就会提供 HTTPS 入口和完全限定域名 (FQDN)。

2、修改

当我们在 Azure Container App 中部署或更改容器时,该服务会自动获取 Azure Container Instance 的不可变快照。然后它在一个单独的 pod 上部署一个新版本。但是,并非所有更改都会触发此行为。在 Azure Container App 中,我们可以区分两种类型的更改:

  1)修订范围更改。

  2)应用范围的变化。

当我们创建新版本时,旧版本的流量会完全转移到新版本。我们可以使用流量拆分规则来定义它们之间的流量平衡方式。这些包括将一定比例的流量引导到特定的修订版。

3、和 Dapr 集成

Azure Container App 提供与开源项目 Dapr(分布式应用程序运行时)的内置兼容性。启用后,Dapr 应用程序将与我们修订版一起部署,通过 HTTP 或 gRPC 提供对 Dapr API 提供的功能的访问。

三,结尾
  相对于操作有些复杂的 Azure Kubernetes 和昂贵的使用的定价,Azure Container App 这项服务变得越来越流行。目前,该服务作为公共预览版提供,因此我们已经可以开始使用它了。

作者:Allen

公告栏

欢迎大家来到我的博客,我是dodoro,希望我的博客能给你带来帮助。