我们都知道ORM全称叫做Object Relationship Mapper,也就是可以用object来map我们的db,而且市面上的orm框架有很多,其中有一个框架 叫做dapper,而且被称为the king of ORM。 一:为什么选择Dapper 1. 性能优越: 其实在各大网站上,我们大概都会看到这样的一个对比效果图,在超过500次poco serialization的过程中所表现的性能,我们发现dapper是第二名, 当然第一名谁也无法超越,越底层的当然久越快,同时也就越麻烦。就好像谁能超过“01代码”呢??? 2. 支持多数据库 支持多数据库的本质是因为Dapper是对IDBConnection接口进行了方法扩展,比如你看到的SqlMapper.cs,一旦你这样做了,我们也知道, SqlConnection,MysqlConnection,OracleConnection都是继承于DBConnection,而DBConnection又是实现了IDBConnection的接口,对吧。。。 二:安装Dapper install dapper的方式通常有两种: 1. 通过nuget进行安装 如果你不知道怎么用nuget进行安装,或者不知道install-package是什么,可以在browser上找一下,比如下面这样: 然后我们copy到package console 试试看。 2. 在github上获取源码。 为什么要获取源码,是因为用ilspy调试dapper的源码太费劲了,毕竟现在都是异步编程了,从ilspy中看都是匿名方法很多都无法渗透,废话不多 说,我们只要把Dapper文件夹拉出来然后copy到我们的solution就可以了,如下图: 三:快速CURD操作 其实对数据库的操作莫过于CURD,在进行操作之前我们再配一个Users表。 1. 配置Users表
1 2 3 4 5 6 7 8 9 10 |
CREATE TABLE [dbo].[Users]( [UserID] [int] IDENTITY(1,1) NOT NULL, [UserName] [varchar](50) NULL, [Email] [varchar](100) NULL, [Address] [varchar](100) NULL, CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ( [UserID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] |
2. Insert操作 通常来说,有两种insert操作: <1>单条insert操作 这是一个简单的参数化insert,而且还可以塞入匿名类型,对吧,跟原始的SqlParameter相比,是不是简单的多???
1 2 3 4 5 6 7 |
static void Main(string[] args) { IDbConnection connection = new SqlConnection("Data Source=.;Initial Catalog=DataMip;Integrated Security=True;MultipleActiveResultSets=True"); var result = connection.Execute("Insert into Users values (@UserName, @Email, @Address)", new { UserName = "jack", Email = "380234234@qq.com", Address = "上海" }); } |
<2> InsertBulk操作 既然是Bulk操作,那肯定就是批量插入了,我们要做的就是将上面这个 ”匿名对象" 变成 ”匿名对象集合“ 就可以了。。。为了方便操作,这里定义 一个Users类,比如下面这样。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
static void Main(string[] args) { IDbConnection connection = new SqlConnection("Data Source=.;Initial Catalog=DataMip;Integrated Security=True;MultipleActiveResultSets=True"); //var result = connection.Execute("Insert into Users values (@UserName, @Email, @Address)", // new { UserName = "jack", Email = "380234234@qq.com", Address = "上海" }); var usersList = Enumerable.Range(0, 10).Select(i => new Users() { Email = i + "qq.com", Address = "安徽", UserName = i + "jack" }); var result = connection.Execute("Insert into Users values (@UserName, @Email, @Address)",usersList); } |
2. Query操作 其实在Dapper在query上提供的的文章太多了。。。这篇我们就按照最简单的参数化查询就好了。。。比如我要找到username=jack的记录,如下:
1 2 3 4 5 6 7 |
1 static void Main(string[] args) 2 { 3 IDbConnection connection = new SqlConnection("Data Source=.;Initial Catalog=DataMip;Integrated Security=True;MultipleActiveResultSets=True"); 4 5 var query = connection.Query<Users>("select * from Users where UserName=@UserName", new { UserName = "jack" }); 6 7 } |
图上的亮点就在于能够自动化mapper到我们object上面来,这是我们DataReader所不能办到的,对吧~~ 3.update操作 这种操作方式,我们还是使用Execute方法来实现,和insert是一种套路的哦。 4. delete操作 这里我还是采用参数化的形式来删除UserID=10这条记录,方式如下: 最终sql的table展示如下,可以看到已经正确的修改了UserID=11的记录,删除了UserID=10的record。。。。当然Dapper好玩的地方多着呢, 这篇只是一个入门而已。。。希望本篇对大家有帮助~~~
View Details访问量不大的项目我都是用EF写数据库操作,因为EF除了速度上慢以外,但开发效率极快,省略了很多sql写法,并能很方便的调用外键、集合等信息,用EF写项目最爽的事。不过有些项目网站要考虑运行速度,这时不得不用其它的ORM框架,我常用dapper,因为它效果快,而且写sql非常灵活,接下来面写一些方法看看dapper的使用 1、连接语句 var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SqlDiagnosticsDb"].ConnectionString); 使用dapper不需要考虑conn是否连接,在执行dapper时自行判断 open状态,如果没有打开它会自己打开。 2、insert
1 2 |
string query = "INSERT INTO Book(Name)VALUES(@name)"; conn.Execute(query, book); |
book类中有name属性,就可以这样方便去写,当然也可以写成
1 2 |
string query = "INSERT INTO Book(Name)VALUES(@name)"; conn.Execute(query, new{@name=book.name}); |
3、update
1 2 |
string query = "UPDATE Book SET Name=@name WHERE id =@id"; conn.Execute(query, book); |
4、 delete
1 2 3 |
string query = "DELETE FROM Book WHERE id = @id"; conn.Execute(query, book); conn.Execute(query, new { id = id }); |
5、query
1 2 3 4 5 6 7 |
string query = "SELECT * FROM Book"; //无参数查询,返回列表,带参数查询和之前的参数赋值法相同。 conn.Query<Book>(query).ToList(); //返回单条信息 string query = "SELECT * FROM Book WHERE id = @id"; book = conn.Query<Book>(query, new { id = id }).SingleOrDefault(); |
6、 传统sql in (1,2,3) 用dapper就这样写
1 2 |
conn.Query<Users>("SELECT * FROM Users s WHERE s.id IN (@ids) ",new { ids = new int[]{1,2,3}}) conn.Query<Users>("SELECT * FROM Users s WHERE s.id IN (@ids) ",new { ids = IDs.ToArray()}) |
在dapper因为安全性,不能直接用sql接接 要采用参数化, 7、批量插入
1 |
conn.Execute(@"insert MyTable(colA, colB) values (@a, @b)", new[] { new { a=1, b=1 }, new { a=2, b=2 }, new { a=3, b=3 } }) |
也可以直接写入一个集合
1 |
conn.Execute("insert user(name) values(@name)",users) |
这里users是一个user表的对象集合,可一次把集合中的所有数据插入到数据表中。 8、多表查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//查询图书时,同时查找对应的书评,并存在List中。实现1--n的查询操作 string query = "SELECT * FROM Book b LEFT JOIN BookReview br ON br.BookId = b.Id WHERE b.id = @id"; Book lookup = null; //Query<TFirst, TSecond, TReturn> var b = conn.Query<Book, BookReview, Book>(query, (book, bookReview) => { //扫描第一条记录,判断非空和非重复 if (lookup == null || lookup.Id != book.Id) lookup = book; //书对应的书评非空,加入当前书的书评List中,最后把重复的书去掉。 if (bookReview != null) lookup.Reviews.Add(bookReview); return lookup; }, new { id = id }).Distinct().SingleOrDefault(); return b; |
多表联合查询是比较麻烦一些,到现在不是完全明白,多看几个例子
1 2 |
var sql = @"select * from Posts p join Users u on u.Id = p.OwnerId Order by p.Id"; var data = conn.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post;},splitOn:"id"); |
Post类和User类,它们存在外键, conn.Query返回的类型是最后一个参数Post, 其中Post中有一属性Owner是User对象,在(post, user)=>lamda中指定了Owner值,上边的代码中的splitOn是ID,运行时,会从查询结果所有字段列表的最后一个字段开始进行匹配,一直到找到Id这个字段(大小写忽略),找到的第一个ID字段匹配User类的ID属性,那么从ID到最后一个字段都属于User,ID以前的字段都被影射到Post, 通过 (post, user) => {return post;},把两个类的实例解析出来。 9、三表查询,一个是关联主键表(单个对象),一个是关联外键表(集合)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public partial class UserInfo { public UserInfo() { this.Persion = new HashSet<Persion>(); this.MyTYC = new HashSet<MyTYC>(); } public int id { get; set; } public string name { get; set; } public Nullable<System.DateTime> createTime { get; set; } public Movies Movies { get; set; } public virtual ICollection<MyTYC> MyTYC { get; set; } } |
1 2 3 4 5 6 7 8 9 10 |
public class Movies { public int ID { get; set; } public string Title { get; set; } public string ReleaseDate { get; set; } public string Genre { get; set; } public string Price { get; set; } public UserInfo UserInfo { get; set; } } |
1 2 3 4 5 6 |
public partial class MyTYC { public int id { get; set; } public string name { get; set; } } |
1 2 3 4 |
string sql = @"select * from UserInfo u inner join [Movies].dbo.Movies m on u.id=m.ID inner join MyTYC t on u.id=t.id"; var data = conn.Query<UserInfo, Movies, MyTYC, UserInfo>(sql, (u, m, t) => { u.Movies = m; u.MyTYC.Add(t); return u; }); |
注意这里的对象和集合的获取方法:u.Movies = m; u.MyTYC.Add(t); 10、多结果查询
1 2 3 4 5 6 7 8 9 10 |
var sql = @"select * from Customers where CustomerId = @id; select * from Orders where CustomerId = @id; select * from Returns where CustomerId = @id"; using (var multi = connection.QueryMultiple(sql, new {id=selectedId})) { var customer = multi.Read<Customer>().Single(); var orders = multi.Read<Order>().ToList(); var returns = multi.Read<Return>().ToList(); } |
再来一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
class Program { //创建连接对象 protected static SqlConnection GetConnection() { var connection = new SqlConnection("Data Source=.;Initial Catalog=TestDB;Integrated Security=True"); connection.Open(); return connection; } static void Main(string[] args) { //测试输出多个结果集 var sql = @"INSERT INTO [dbo].[Student] ([Name]) VALUES ('A1'); select @@IDENTITY as A; INSERT INTO [dbo].[Student] ([Name]) VALUES ('B1'); select @@IDENTITY as A; INSERT INTO [dbo].[Student] ([Name]) VALUES ('C1'); select @@IDENTITY as A"; //初始化数据库连接 using (SqlConnection connection = GetConnection()) { List<int> ilist = new List<int>(); //执行查询,获取结果集集合 var multi = connection.QueryMultiple(sql); //遍历结果集 while(!multi.IsConsumed) { //读取当前结果集 var result = multi.Read().ToList()[0].A; if (result != null) { ilist.Add(Convert.ToInt32(result)); } } //for(int i = 0;i<3;i++) //{ // var result = multi.Read().ToList()[0].A; // if (result != null) // { // ilist.Add(Convert.ToInt32(result)); // } //} foreach (var item in ilist) { Console.WriteLine(item.ToString()); } } Console.ReadLine(); } } |
11、如果某一代码中多次操作数据库,可以把conn设置为打开,最后时再close, 比如:
1 2 3 4 5 6 |
conn.open() conn.Query(..... ..... for.... ..... conn.close() |
from:https://www.cnblogs.com/lunawzh/p/6607116.html
View DetailsElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。 我们建立一个网站或应用程序,并要添加搜索功能,但是想要完成搜索工作的创建是非常困难的。我们希望搜索解决方案要运行速度快,我们希望能有一个零配置和一个完全免费的搜索模式,我们希望能够简单地使用JSON通过HTTP来索引数据,我们希望我们的搜索服务器始终可用,我们希望能够从一台开始并扩展到数百台,我们要实时搜索,我们要简单的多租户,我们希望建立一个云的解决方案。因此我们利用Elasticsearch来解决所有这些问题及可能出现的更多其它问题。 下载地址:https://www.elastic.co/cn/downloads/elasticsearch
View DetailsABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称。 ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应用程序的新起点,它旨在成为一个通用的WEB应用程序框架和项目模板。 ABP的官方网站 : http://www.aspnetboilerplate.com ABP在Github上的开源项目:https://github.com/aspnetboilerplate ABP 的由来 “DRY——避免重复代码”是一个优秀的开发者在开发软件时所具备的最重要的思想之一。我们在开发企业WEB应用程序时都有一些类似的需求,例如:都需要登录页面、用户/角色管理、权限验证、数据有效性验证、多语言/本地化等等。一个高品质的大型软件都会运用一些最佳实践,例如分层体系结构、领域驱动设计、依赖注入等。我们也可能会采用ORM、数据库迁移(Database Migrations)、日志记录(Logging)等工具。 从零开始创建一个企业应用程序是一件繁琐的事,因为需要重复做很多常见的基础工作。许多公司都在开发自己的应用程序框架来重用于不同的项目,然后在框架的基础上开发一些新的功能。但并不是每个公司都有这样的实力。假如我们可以分享的更多,也许可以避免每个公司或每个项目的重复编写类似的代码。作者之所以把项目命名为“ASP.NET Boilerplate”,就是希望它能成为开发一般企业WEB应用的新起点,直接把ABP作为项目模板。 ABP是什么? ABP是为新的现代Web应用程序使用最佳实践和使用最流行工具的一个起点。可作为一般用途的应用程序的基础框架或项目模板。它的功能包括: 服务器端: 基于最新的.NET技术 (目前是ASP.NET MVC 5、Web API 2、C# 5.0,在ASP.NET 5正式发布后会升级) 实现领域驱动设计(实体、仓储、领域服务、领域事件、应用服务、数据传输对象,工作单元等等) 实现分层体系结构(领域层,应用层,展现层和基础设施层) 提供了一个基础架构来开发可重用可配置的模块 集成一些最流行的开源框架/库,也许有些是你正在使用的。 提供了一个基础架构让我们很方便地使用依赖注入(使用Castle Windsor作为依赖注入的容器) 提供Repository仓储模式支持不同的ORM(已实现Entity Framework 、NHibernate、MangoDb和内存数据库) 支持并实现数据库迁移(EF 的 Code first) 模块化开发(每个模块有独立的EF DbContext,可单独指定数据库) 包括一个简单的和灵活的多语言/本地化系统 包括一个 EventBus来实现服务器端全局的领域事件 统一的异常处理(应用层几乎不需要处理自己写异常处理代码) 数据有效性验证(Asp.NET MVC只能做到Action方法的参数验证,ABP实现了Application层方法的参数有效性验证) 通过Application Services自动创建Web Api层(不需要写ApiController层了) 提供基类和帮助类让我们方便地实现一些常见的任务 使用“约定优于配置原则” 客户端: Bootstrap、Less、AngularJs、jQuery、Modernizr和其他JS库: jQuery.validate、jQuery.form、jQuery.blockUI、json2等 为单页面应用程序(AngularJs、Durandaljs)和多页面应用程序(Bootstrap+Jquery)提供了项目模板。 自动创建Javascript 的代理层来更方便使用Web Api 封装一些Javascript 函数,更方便地使用ajax、消息框、通知组件、忙状态的遮罩层等等 除ABP框架项目以外,还开发了名叫“Zero”的模块,实现了以下功能: 身份验证与授权管理(通过ASP.NET Identity实现的) 用户&角色管理 系统设置存取管理(系统级、租户级、用户级,作用范围自动管理) 审计日志(自动记录每一次接口的调用者和参数) ABP不是什么? ABP 提供了一个应用程序开发模型用于最佳实践。它拥有基础类、接口和工具使我们容易建立起可维护的大规模的应用程序。 然而: 它不是RAD工具之一,RAD工具的目的是无需编码创建应用程序。相反,ABP提供了一种编码的最佳实践。 它不是一个代码生成工具。在运行时虽然它有一些特性构建动态代码,但它不能生成代码。 它不是一个一体化的框架。相反,它使用流行的工具/库来完成特定的任务(例如用EF做ORM,用Log4Net做日志记录,使得Castle Windsor作为赖注入容器, AngularJs 用于SPA 框架)。 就我使用了ABP几个月的经验来看,虽然ABP不是RAD,但是用它开发项目绝对比传统三层架构要快很多。 虽然ABP不是代码生成工具,但因为有了它,使我们项目的代码更简洁规范,这有利于使用代码生成工具。 我自己使用VS2013的Scaffolder+T4开发的代码生成器,可根据领域对象的UML类图自动生成全部前后端代码和数据库,简单的CURD模块几乎不需要编写代码,有复杂业务逻辑的模块主要补充领域层代码即可。这样就能把时间多花在领域模型的设计上,减少写代码的时间。 下面通过原作者的“简单任务系统”例子,演示如何运用ABP开发项目 从模板创建空的web应用程序 ABP提供了一个启动模板用于新建的项目(尽管你能手动地创建项目并且从nuget获得ABP包,模板的方式更容易)。 转到www.aspnetboilerplate.com/Templates从模板创建你的应用程序。 你可以选择SPA(AngularJs或DurandalJs)或者选择MPA(经典的多页面应用程序)项目。可以选择Entity Framework或NHibernate作为ORM框架。 这里我们选择AngularJs和Entity Framework,填入项目名称“SimpleTaskSystem”,点击“CREATE […]
View Details跨平台是ASP.NET Core一个显著的特性,而KestrelServer是目前微软推出了唯一一个能够真正跨平台的Server。KestrelServer利用一个名为KestrelEngine的网络引擎实现对请求的监听、接收和响应。KetrelServer之所以具有跨平台的特质,源于KestrelEngine是在一个名为libuv的跨平台网络库上开发的。 目录 一、libuv 二、KestrelServer 三、KestrelServerOptions 四、ApplicationLifetime 五、设置监听地址 一、libuv 说起libuv,就不得不谈谈libev,后者是Unix系统上一个事件循环和事件模型的网络库。libev因其具有的高性能成为了继lievent和Event perl module之后一套最受欢迎的网络库。由于Libev不支持Windows,有人在libev之上创建了一个抽象层以屏蔽平台之间的差异,这个抽象层就是libuv。libuv在Windows平台上是采用IOCP的形式实现的,右图揭示了libuv针对Unix和Windows的跨平台实现原理。到目前为止,libuv支持的平台已经不限于Unix和Windows了,包括Linux(2.6)、MacOS和Solaris (121以及之后的版本)在内的平台在libuv支持范围之内。 二、KestrelServer 如下所示的代码片段体现了KestrelServer这个类型的定义。除了实现接口IServer定义的Features属性之外,KestrelServer还具有一个类型为KestrelServerOptions的只读属性Options。这个属性表示对KestrelServer所作的相关设置,我们在调用构造函数时通过输入参数options所代表的IOptions<KestrelServerOptions>对象对这个属性进行初始化。构造函数还具有另两个额外的参数,它们的类型分别是IApplicationLifetime和ILoggerFactory,后者用于创建记录日志的Logger,前者与应用的生命周期管理有关。
1 2 3 4 5 6 7 8 9 |
1: public class KestrelServer : IServer 2: { 3: public IFeatureCollection Features { get; } 4: public KestrelServerOptions Options { get; } 5: 6: public KestrelServer(IOptions<KestrelServerOptions> options,IApplicationLifetime applicationLifetime, ILoggerFactory loggerFactory); 7: public void Dispose(); 8: public void Start<TContext>(IHttpApplication<TContext> application); 9: } |
我们一般通过调用WebHostBuilder的扩展方法UseKestrel方法来完成对KestrelServer的注册。如下面的代码片段所示,UseKestrel方法具有两个重载,其中一个具有同一个类型为Action<KestrelServerOptions>的参数,我们可以利用这个参数直接完成对KestrelServerOptions的设置。
1 2 3 4 5 |
1: public static class WebHostBuilderKestrelExtensions 2: { 3: public static IWebHostBuilder UseKestrel(this IWebHostBuilder hostBuilder); 4: public static IWebHostBuilder UseKestrel(this IWebHostBuilder hostBuilder, Action<KestrelServerOptions> options); 5: } |
三、KestrelServerOptions 由于Server负责请求的监听、接收和响应,所以Server是影响整个Web应用响应能力和吞吐量最大的因素之一,为了更加有效地使用Server,我们往往针对具体的网络负载状况对其作针对性的设置。对于KestrelServer来说,在构造函数中作为参数指定的KestrelServerOptions对象代表针对它所做的设置。我们针对KestrelServer所做的设置主要体现在KestrelServerOptions类型的如下5个属性上。
1 2 3 4 5 6 7 8 9 |
1: public class KestrelServerOptions 2: { 3: //省略其他成员 4: public int MaxPooledHeaders { get; set; } 5: public int MaxPooledStreams { get; set; } 6: public bool NoDelay { get; set; } 7: public TimeSpan ShutdownTimeout { get; set; } 8: public int ThreadCount { get; set; } 9: } |
KestrelServerOptions注册的KetrelServer在管道中会以依赖注入的方式被创建,并采用构造器注入的方式提供其构造函数的参数options,由于这个参数类型为IOptions<KestrelServerOptions>,所以我们利用Options模型以配置的方式来指定KestrelServerOptions对象承载的设置。比如我们可以将KestrelServer的相关配置定义在如下一个JSON文件中。
1 2 3 4 5 |
1: { 2: "noDelay" : false, 3: "shutdownTimeout" : "00:00:10", 4: "threadCount" : 10 5: } |
为了让应用加载这么一个配置文件(文件名假设为“KestrelServerOptions.json”),我们只需要在启动类型(Startup)类的ConfigureServces方法中按照如下的方式利用ConfigurationBuilder加载这个配置文件并生成相应的Configuration对象,最后按照Options模型的编程方式完成KestrelServerOptions类型和该对象的映射即可。
1 2 3 4 5 6 7 8 9 10 11 |
1: public class Startup 2: { 3: //其他成员 4: public void ConfigureServices(IServiceCollection services) 5: { 6: IConfiguration configuration = new ConfigurationBuilder() 7: .AddJsonFile("KestrelServerOptions.json") 8: .Build(); 9: services.Configure<KestrelServerOptions>(configuration); 10: } 11: } |
四、ApplicationLifetime 我们将所有实现了IApplicationLifetime接口的所有类型及其对应对象统称为ApplicationLifetime。从命名的角度来看,ApplicationLifetime貌似是对当前应用生命周期的描述,而实际上它存在的目的仅仅是在应用启动和关闭(只要是关闭)时对相关组件发送通知而已。如下面的代码片段所示,IApplicationLifetime接口具有三个CancellationToken类型的属性(ApplicationStarted、ApplicationStopping和ApplicationStopped),我们可以利用它们是否已经被取消(Cancel)确定当前应用的状态(已经开启、正在关闭和已经关闭)。如果试图关闭应用,StopApplication方法应该被调用以发出应用正在被关闭的通知。对于KestrelServer来说,如果请求处理线程中发生未被处理异常,它会调用这个方法。
1 2 3 4 5 6 7 8 |
1: public interface IApplicationLifetime 2: { 3: CancellationToken ApplicationStarted { get; } 4: CancellationToken ApplicationStopping { get; } 5: CancellationToken ApplicationStopped { get; } 6: 7: void StopApplication(); 8: } |
ASP.NET Core默认使用的ApplicationLifetime是具有如下定义的一个同名类型。可以看出它实现的三个属性返回的CancellationToken对象是通过三个对应的CancellationTokenSource生成。除了实现IApplicationLifetime接口的StopApplication方法用于发送“正在关闭”通知之外,这个类型还定义了额外两个方法(NotifyStarted和NotifyStopped)用于发送“已经开启/关闭”的通知。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
1: public class ApplicationLifetime : IApplicationLifetime 2: { 3: private readonly CancellationTokenSource _startedSource = new CancellationTokenSource(); 4: private readonly CancellationTokenSource _stoppedSource = new CancellationTokenSource(); 5: private readonly CancellationTokenSource _stoppingSource = new CancellationTokenSource(); 6: 7: public CancellationToken ApplicationStarted 8: { 9: get { return this._startedSource.Token; } 10: } 11: public CancellationToken ApplicationStopped 12: { 13: get { return this._stoppedSource.Token; } 14: } 15: public CancellationToken ApplicationStopping 16: { 17: get { return this._stoppingSource.Token; } 18: } 19: 20: public void NotifyStarted() 21: { 22: this._startedSource.Cancel(false); 23: } 24: public void NotifyStopped() 25: { 26: this._stoppedSource.Cancel(false); 27: } 28: public void StopApplication() 29: { 30: this._stoppingSource.Cancel(false); 31: } 32: } |
一个ASP.NET Core应用利用管道处理请求,所以管道的生命周期等同于应用自身的生命周期。当我们调用Run方法开启WebHost时,请求处理管道被构建出来。如果管道在处理请求时发生未被处理的异常,管道的Sever会调用ApplicationLifeTime对象的StopApplication方法向WebHost发送关闭应用的通知以便后者执行一些回收释放工作。 五、设置监听地址 在演示的实例中,我们实际上并不曾为注册的KestrelServer指定一个监听地址,从运行的效果我们不难看出,WebHost在这种情况下会指定“http://localhost:5000”为默认的监听地址,Server的监听地址自然可以显式指定。在介绍如何通过编程的方式为Server指定监听地址之前,我们有先来认识一个名为ServerAddressesFeature的特性。 我们知道表示Server的接口IServer中定义了一个类型为IFeatureCollection 的只读属性Features,它表示用于描述当前Server的特性集合,ServerAddressesFeature作为一个重要的特性,就包含在这个集合之中。我们所说的ServerAddressesFeature对象是对所有实现了IServerAddressesFeature接口的所有类型及其对应对象的统称,该接口具有一个唯一的只读属性返回Server的监听地址列表。ASP.NET Core默认使用的ServerAddressesFeature是具有如下定义的同名类型。
1 2 3 4 5 6 7 8 9 |
1: public interface IServerAddressesFeature 2: { 3: ICollection<string> Addresses { get; } 4: } 5: 6: public class ServerAddressesFeature : IServerAddressesFeature 7: { 8: public ICollection<string> Addresses { get; } 9: } |
对于WebHost在通过依赖注入的方式创建的Server,由它的Features属性表示的特性集合中会默认包含这么一个ServerAddressesFeature对象。如果没有一个合法的监听地址被添加到这个 ServerAddressesFeature对象的地址列表中,WebHost会将显式指定的地址(一个或者多个)添加到该列表中。我们显式指定的监听地址实际上是作为WebHost的配置保存在一个Configuration对象上,配置项对应的Key为“server.urls”,WebHostDefaults的静态只读属性ServerUrlsKey返回的就是这么一个Key。
1 2 3 4 5 6 |
1: new WebHostBuilder() 2: .UseSetting(WebHostDefaults.ServerUrlsKey, "http://localhost:3721/") 3: .UseMyKestrel() 4: .UseStartup<Startup>() 5: .Build() 6: .Run(); |
WebHost的配置最初来源于创建它的WebHostBuilder,后者提供了一个UseSettings方法来设置某个配置项的值,所以我们可以采用如下的方式来指定监听地址(“http://localhost:3721/”)。不过,针对监听地址的显式设置,最直接的编程方式还是调用WebHostBuilder的扩展方法UseUrls,如下面的代码片段所示,该方法的实现逻辑与上面完全一致。
1 2 3 4 5 |
1: public static class WebHostBuilderExtensions 2: { 3: public static IWebHostBuilder UseUrls(this IWebHostBuilder hostBuilder, params string[] urls) 4: =>hostBuilder.UseSetting(WebHostDefaults.ServerUrlsKey, string.Join(ServerUrlsSeparator, urls)) ; 5: } |
from:https://www.cnblogs.com/artech/p/KestrelServer.html
View Details原文地址—-Kestrel server for ASP.NET Core By Tom Dykstra, Chris Ross, and Stephen Halter Kestrel是一个基于libuv的跨平台ASP.NET Core web服务器,libuv是一个跨平台的异步I/O库。ASP.NET Core模板项目使用Kestrel作为默认的web服务器。 Kestrel支持以下功能: HTTPS 用于启用不透明升级的WebSockets 位于Nginx之后的高性能Unix sockets Kestrel 被.NET Core支持的所有平台和版本所支持 查看或下载示例代码 何时使用Kestrel和反向代理服务器 如果你的应用只接收来自内部网络的请求,你可以只使用Kestrel本身。 如果你将你的应用部署在公共网络上,我们建议你使用IIS,Nginx或者Apache作为反向代理服务器。一个反向代理服务器接收来自网络的HTTP请求并且在经过一些初步处理后将请求传递到Kestrel服务器。 出于安全性的理由,反向代理常常被edge deployments所采用。因为Kestrel相对较新,对抵御安全攻击至今还没有一个完整的功能补充。安全性处理包括但不限于适当的超时,大小的限制,以及并发连接限制等问题。 另一个需要反向代理的场景是,你有多个需要在单独的服务器上运行并分享同一端口的应用。因为Kestrel不支持在多进程间分享同一端口,所以应用并不能直接和Kestrel合作。当你在某个端口上配置Kestrel运行侦听时,不算主机头如何标识,Kestrel会为该端口处理所有的流量。反向代理可以为多个应用共享唯一端口并将流量发送给Kestrel。 即使不需要反向代理服务器,使用它也可以简化负载均衡和SSL设置 — 只要你的反向代理服务器需要SSL证书,并且该服务器可以和你的应用在内部网中通过普通HTTP进行通信。 如何在ASP.NET Core应用中使用Kestrel 安装 Microsoft.AspNetCore.Server.Kestrel Nuget包。 在应用的Main方法中调用WebHostBuilder的UseKestrel 扩展方法,指定你需要的Kestrel选项,如以下示例所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public static int Main(string[] args) { Console.WriteLine("Running demo with Kestrel."); var config = new ConfigurationBuilder() .AddCommandLine(args) .Build(); var builder = new WebHostBuilder() .UseContentRoot(Directory.GetCurrentDirectory()) .UseConfiguration(config) .UseStartup<Startup>() .UseKestrel(options => { if (config["threadCount"] != null) { options.ThreadCount = int.Parse(config["threadCount"]); } }) .UseUrls("http://localhost:5000"); var host = builder.Build(); host.Run(); return 0; } |
URL 前缀 默认情况下,ASP.NET Core项目绑定了http://localhost:5000。通过使用UseUrls扩展方法——编辑urls命令行参数,或者是通过ASP.NET Core配置系统,你可以为Ketrel配置URL前缀和端口号以用来侦听请求。关于这些方法更多的信息,请参考Hosting。有关于当你使用IIS作为反向代理时,URL绑定是如何工作的信息,请参考ASP.NET Core 模块。 Kestrel URL前缀可以是以下格式中的任一种。 IPv4 地址和端口号
1 2 |
http://65.55.39.10:80/ https://65.55.39.10:443/ |
IPv6 地址和端口号
1 2 |
http://[0:0:0:0:0:ffff:4137:270a]:80/ https://[0:0:0:0:0:ffff:4137:270a]:443/ |
IPv6中的 [::] 等价于 IPv4 0.0.0.0。 主机名和端口号
1 2 3 4 |
http://contoso.com:80/ http://*:80/ https://contoso.com:443/ https://*:443/ |
主机名称,*,以及+,都不是特殊的。任何没有公认的IP 或是“localhost”的地址将绑定到所有的IPv4和IPv6的IP上。如果你需要为不同的ASP.NET Core应用在同一端口上绑定不同的主机名,请使用WebListener或者诸如IIS,Nginx或Apache这样的反向代理服务器。 * "Localhost" 名称和端口号或回送IP地址和端口号
1 2 3 |
http://localhost:5000/ http://127.0.0.1:5000/ http://[::1]:5000/ |
当localhost被指定时,Kestrel会尝试去绑定到IPv4和IPv6的环回接口。如果被请求的端口号正在任一环回接口上被其他服务所使用,Kestrel将会启动失败。如果任一环回接口出于各种原因而不可用(最通常的情况是因为IPv6暂不被支持),Kestrel将记录下一个警告信息。 Unix socket
1 |
http://unix:/run/dan-live.sock |
如果你指定了端口号0,Kestrel将动态地绑定到合适的端口号。除了localhost名称,绑定到0端口号被其他任何主机名称或IP地址所允许。 当你指定了端口号0,你可以使用IServerAddressesFeature接口去决定运行时Kestrel实际绑定到哪个端口。下列示例用于获取绑定端口并且在console上显示出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(); var serverAddressesFeature = app.ServerFeatures.Get<IServerAddressesFeature>(); app.UseStaticFiles(); app.Run(async (context) => { context.Response.ContentType = "text/html"; await context.Response .WriteAsync("<p>Hosted by Kestrel</p>"); if (serverAddressesFeature != null) { await context.Response .WriteAsync("<p>Listening on the following addresses: " + string.Join(", ", serverAddressesFeature.Addresses) + "</p>"); } await context.Response.WriteAsync($"<p>Request URL: {context.Request.GetDisplayUrl()}<p>"); }); } |
SSL的URL前缀 如果你调用UseSSL扩展方法,请确保在https:中包含URL前缀,如下所示:
1 2 3 4 5 6 7 8 9 |
var host = new WebHostBuilder() .UseKestrel(options => { options.UseHttps("testCert.pfx", "testPassword"); }) .UseUrls("http://localhost:5000", "https://localhost:5001") .UseContentRoot(Directory.GetCurrentDirectory()) .UseStartup<Startup>() .Build(); |
Note HTTPS和HTTP不能在同一端口上被托管。 下一步 更多的信息,请参考以下资源: Sample app for this […]
View Details1、首先打开php.ini文件,修改post_max_size设定POST数据所允许的最大限制值,php中默认post_max_size=2M;在php.in文件中按Ctrl+F,然后输入post_max_size,找到post_max_size将其改为自己需要上传限制文件的大小,比如改为post_max_size=300M; 2、修改完之后并不能上传较大的文件,则继续修改php.ini中的参数upload_max_filesize,其表示为上传文件的最大值。默认值upload_max_filesize=8M,修改为upload_max_filesize=300M; 3、如果上传仍然有问题,则继续修改。可能跟上传时间有关系。找到php.ini文件中的max_execution_time,默认值max_execution_time=30,其意思就是该页面最长执行的时间为30s,30s之后则上传停止,从而导致上传失败。修改为max_execution_time=0;0表示没有限制。 附: 另外要注意的是,post_max_size 应该大于upload_max_filesize 。 from:https://blog.csdn.net/rision666/article/details/51590803
View Details控制反转:我们向IOC容器发出获取一个对象实例的一个请求,IOC容器便把这个对象实例“注入”到我们的手中,在这个过程中你不是一个控制者而是一个请求者,依赖于容器提供给你的资源,控制权落到了容器身上。这个过程就是控制反转。 依赖注入:我们向容器发出请求以后,获得这个对象实例的过程就叫依赖注入。 IoC模式其实是工厂设计模式的升华,在微软较早的PetShop项目通过反射技术做了很多工厂。我认为可能是IoC的原型。 关于Ioc的框架有很多,比如Castle Windsor、Unity、Spring.NET、StructureMap,我们这边使用微软提供的Unity做示例,你可以使用 Nuget 添加 Unity ,也可以引用Microsoft.Practices.Unity.dll和Microsoft.Practices.Unity.Configuration.dll,下面我们就一步一步的学习下 Unity依赖注入 的详细使用。 Unity是微软推出的IOC框架, 使用这个框架,可以实现AOP面向切面编程,便于代码的后期维护,此外,这套框架还自带单例模式,可以提高程序的运行效率。 下面是我自己的案例,以供日后参考: 使用VS2015的Nuget管理器下载Unity。 程序员接口类:
1 2 3 4 5 6 7 |
namespace UnityDemo { public interface IProgrammer { void Working(); } } |
程序员类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
using System; namespace UnityDemo { public class CSharp : IProgrammer { public void Working() { Console.WriteLine("programming C# ..."); } } public class VB : IProgrammer { public void Working() { Console.WriteLine("programming VB ..."); } } public class Java : IProgrammer { public void Working() { Console.WriteLine("programming Java ..."); } } } |
App.config配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?xml version="1.0" encoding="utf-8"?> <configuration> <!--<startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/> </startup>--> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/> </configSections> <unity> <containers> <container name="Programmer"> <register type="UnityDemo.IProgrammer,UnityDemo" mapTo="UnityDemo.CSharp,UnityDemo" name="CSharp"></register> <register type="UnityDemo.IProgrammer,UnityDemo" mapTo="UnityDemo.VB,UnityDemo" name="VB"></register> <register type="UnityDemo.IProgrammer,UnityDemo" mapTo="UnityDemo.Java,UnityDemo" name="Java"></register> </container> </containers> </unity> </configuration> |
主程序代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
using Microsoft.Practices.Unity; using Microsoft.Practices.Unity.Configuration; using System; using System.Configuration; namespace UnityDemo { class Program { private static IUnityContainer container = null; static void Main(string[] args) { RegisterContainer(); var programmer = container.Resolve<IProgrammer>("CSharp"); //var programmer = container.Resolve<IProgrammer>("VB"); programmer.Working(); Console.ReadKey(); } private static void RegisterContainer() { container = new UnityContainer(); UnityConfigurationSection config =(UnityConfigurationSection) ConfigurationManager.GetSection(UnityConfigurationSection.SectionName); config.Configure(container, "Programmer"); } } } |
运行结果: 这个Demo的思想: 定义一个程序员接口IProgrammer,有3个实现这个接口的程序员类,分别是CSharp、VB、Java, 然后配置App.config文件,里面首先定义一个配置节点(configSection),名称为Unity,引用的命名空间是微软的Unity, 接着下面定义一个unity节点,里面的容器集合(containers),集合里面可以有多个容器,这个Demo里的只有一个容器,里面包含了3个注册节点(register),分别是CSharp,VB、Java,注意,里节点中的name属性用于在程序调用时选择类的。 在主程序的代码中, 1、有一个Unity的容器container; 2、注册容器的方法RegisterContainer,作用是到App.config中读取容器的信息,把接口和3个类的映射关系注册到容器中; 3、主程序运行前,先注册容器,然后通过容器的Resolve方法,实例化一个programmer类,原理大概是,我们把类名传入到容器中,容器会根据类名,找到App.config中对应的register映射关系,容器就会通过反射得到相应的程序员类,返回这个类。 4、此时programmer类就实例化完成,可以使用了。 使用了Unity,以后如果需要追加新的类,只需要实现IProgrammer接口,在配置文件追加映射关系,执行代码中修改name的值就能使用新的类了。 这样,我们不需要删除旧的代码,就能追加新的功能,便于维护代码。 本人的Demo下载 转自: https://www.cnblogs.com/chenyucong/p/6272600.html
View Details官网生成的ABP + module zero出现Default language is not defined!的错误,原因是数据库没有language数据,而不是缺少language.xml资源文件,所以先创建数据库就好了。 解决方法: 1.选择Web项目作为起始项目。 2.打开程序包管理控制台,选择“EntityFramework”项目作为默认项目,然后运行EF的’Update-Database’命令。该命令会创建数据库。 3.运行该应用,默认的用户名是’admin’,密码是’123qwe’。 在执行第2步时遇到了如下错误: Update-Database : 无法将“Update-Database”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后重试。 原因可能是EntityFramework没有安装,Install-Package EntityFramework就好了。什么?还是不行?全部重新生成再重新打开vs试试吧! https://blog.csdn.net/klo220/article/details/51138582
View DetailsGradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置。 面向Java应用为主。当前其支持的语言限于Java、Groovy、Kotlin和Scala,计划未来将支持更多的语言。
View Details