关于.net:如何在-C-8-中使用-异步流

异步编程曾经风行很多年了,.NET 引入的 async 和 await 关键词让异步编程更具备可读性,但有一个遗憾,在 C# 8 之前都不能应用异步的形式解决数据流,直到 C# 8 引入的 IAsyncEnumerable<T> 才解决了这个问题。 说到 IAsyncEnumerable<T> ,得先说一说 IEnumerable<T> ,大家都晓得,它是用同步的形式来迭代 collection 汇合的,而这里的 IAsyncEnumerable<T> 则是用异步形式,换句话说: IAsyncEnumerable<T> 在迭代汇合的过程中不会阻塞调用线程。 IAsyncDisposable, IAsyncEnumerable<T>, IAsyncEnumerator<T>异步迭代器 容许咱们能够用异步的形式解决数据,在这之前要理解上面三个接口:IAsyncDisposable, IAsyncEnumerable<T> 和 IAsyncEnumerator<T>,他们都是在 .NET Standard 2.1 中被引入,上面的代码片段展现了这三个接口的定义。 public interface IAsyncDisposable{ ValueTask DisposeAsync();}public interface IAsyncEnumerable<out T>{ IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken token = default);}public interface IAsyncEnumerator<out T> : IAsyncDisposable{ ValueTask<bool> MoveNextAsync(); T Current { get; }}为什么要应用异步迭代器能够设想一下你有一个数据拜访层须要从数据库中一次性读取所有的数据,要想应用这个性能很简略,能够间接调用 底层提供的异步办法 XXXAsyc 实现异步调用并且一次性返回所有数据。 只有不是将所有数据都出现在页面上的话,这种解决方案问题不是太大,很多时候更多的是通过 分页读取 的模式,其实在这方面还有一个比拟好的做法就是在数据可用时立刻返回给调用者。 精确的说,这里可应用 异步迭代器 的形式来解决,如果你的办法是同步返回的话,你能够应用 return yield + 返回值 IEnumerable<T> 模式,很遗憾的是,这种形式没有扩展性,因为它是须要阻塞调用线程的。 ...

February 1, 2021 · 2 min · jiezi

关于.net:如何在-C-8-中使用-Index-和-Range

C# 8 中有几个比拟好玩的新个性,比方上面的这两个:System.Index 和 System.Range,别离对应着索引和切片操作,这篇文章将会探讨这两个类的应用。 System.Index 和 System.Range 构造体能够用它们在运行时对汇合进行 index 和 slice,上面就是 System.Index 构造体的定义。 namespace System{ public readonly struct Index { public Index(int value, bool fromEnd); }}而后就是 System.Range 构造体的定义。 namespace System{ public readonly struct Range { public Range(System.Index start, System.Index end); public static Range StartAt(System.Index start); public static Range EndAt(System.Index end); public static Range All { get; } }}应用 System.Index 从尾部向前对汇合进行索引在 C# 8.0 之前没有任何形式能够从汇合的尾部向前进行索引,当初你能够应用 ^ 操作符实现对汇合的从后往前索引,如下代码所示: System.Index operator ^(int fromEnd);接下来用一个例子来了解该操作符的应用,思考上面的string数组。 ...

February 1, 2021 · 2 min · jiezi

关于.net:如何在-ASPNet-Core-中实现-数据保护API

在 ASP.Net Core 数据保护栈中提供了一种非常简单的办法来加密API,从而爱护数据的平安,通常落地的做法就是 数据加密 和 数据解密,这篇文章咱们就来一起看看如何应用 数据保护API。 了解加密和哈希在平安畛域,加密和hash是两个十分重要的概念,经常被开发者混用,其实这是不对的,加密是用一种加密算法将一种数据转换成另外一种数据,同时也要留神,这是一种双向操作,已加密的数据只能通过一个适合的密钥去解密,加过密的数据又称为密文,在现在的零碎间通信,数据加密还是非常简单高效的。 相比之下,hash 是一种将 text 转成 音讯摘要 的技术,要值得注意的是,hash值是惟一的,这就意味着不同的text文本不可能生成同一个 hash 值,而且还要留神的是,当 text 转成了 hash 值之后,你很难再将 hash 值再还原成 text 文本。 总的来说,加密是一种双向技术,能够应用同一个密钥对数据进行加密解密,hash是一种单向技术,它能够将 text 转成 音讯摘要,而这个摘要很难再还原成原始text。 装置 Microsoft.AspNetCore.DataProtection要想应用 数据保护API, 能够应用 Visual Studio 2019 中的 NuGet package manager 可视化界面,还能够用 NuGet package manager console 在命令行窗口中键入如下命令。 dotnet add package Microsoft.AspNetCore.DataProtection -Version 2.2.0配置数据保护API依照 ASP.NET Core 的默认常规,先将 DataProtection 注入到 ServiceCollection 中,如下代码所示。 public class Startup { // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddDataProtection(); } }如果你想将加密和解密用到的 密钥 独自寄存到文件系统中的话,能够在注入时略微批改一下,如下代码所示: ...

February 1, 2021 · 2 min · jiezi

关于.net:如何在-ASPNet-Core-MVC-中实现文件上传

ASP.Net Core MVC 实现了将 上传文件 间接映射到 model 中,只有这个 model 实现了 IFormFile 接口即可,回忆一下, model binding 的作用就是将 Request 映射到 Action 办法参数的过程,这样就简化了原来须要间接对 Request 的拜访,同时也不便后续做单元测试,本篇中的 IFormFile 接口就简化了对 Request 中的 file 拜访。 上传一个文件在这一节中咱们将会演示如何通过 IFromFile 接口来对接 client 上传一个或者多个文件,先看一下 IFromFile 接口的定义。 public interface IFormFile{ string ContentType { get; } string ContentDisposition { get; } IHeaderDictionary Headers { get; } long Length { get; } string Name { get; } string FileName { get; } Stream OpenReadStream(); void CopyTo(Stream target); Task CopyToAsync(Stream target, CancellationToken cancellationToken = null);}而后咱们创立一个 FileUploadController 类,构建一个 UploadFile 办法来接管 client 上传的文件。 ...

January 28, 2021 · 2 min · jiezi

关于.net:如何在-ASPNet-Web-Forms-中使用依赖注入

依赖注入技术就是将一个对象注入到一个须要它的对象中,同时它也是管制反转的一种实现,不言而喻,这样能够实现对象之间的解耦并且更不便测试和保护,依赖注入的准则早曾经指出了,应用程序的高层模块不依赖于低层模块,而应该对立依赖于形象或者接口。 在 .Net Framework 4.7.2 中引入了对依赖注入的反对,终于在 ASP.Net Web Forms 中能够应用依赖注入机制了,这篇文章将会探讨如何在 ASP.Net Web Forms 中去应用。 创立 WebForm 我的项目在 ASP.Net Web Forms 中应用依赖注入,肯定要记得将我的项目框架设为 4.7.2 以上,要么右键我的项目在属性面板上抉择 4.7.2 版本。 也能够间接在 web.config 做如下设置。 <system.web> <compilation debug="true" targetFramework="4.7.2" /> <httpRuntime targetFramework="4.7.2" />...</system.web>接下来就能够通过 Nuget 装置 AspNet.WebFormsDependencyInjection.Unity 包,能够通过 Visual Studio 2019 的 NuGet package manager 可视化界面装置 或者 通过 NuGet package manager 命令行工具输出以下命令: dotnet add package AspNet.WebFormsDependencyInjection.Unity创立实体 和 接口当初创立一个名为 Author 实体类 和 IAuthorRepository 接口。 public class Author { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } } public interface IAuthorRepository { bool Create(Author author); Author Read(int id); List<Author> Read(); }而后再用 AuthorRepository 类实现一下 IAuthorRepository 接口,代码如下: ...

January 28, 2021 · 2 min · jiezi

关于.net:如何在-ASPNet-Core-中使用-Swagger

大家在开发完 webapi 后,常常为了不便接口单方对接,须要将 webapi 接口文档化,那有没有什么快捷可交互的文档呢?能够利用快捷工具 Swagger,它的可视化 UI 可轻松助你 API 文档化的同时还不便测试 API。 Swashbuckle 就是一个用于生成 Swagger 文档的开源工具包,这篇文章将会探讨如何利用 Swashbuckle 来为你的 Restful API 生成可交互的文档。 装置 Swagger 中间件要想利用 Swagger 文档化,须要 nuget 援用 Swashbuckle.AspNetCore 包,还能够通过 Visual Studio 2019 的 NuGet package manager 可视化界面装置 或者 通过 NuGet package manager 命令行工具输出以下命令: dotnet add package Swashbuckle.AspNetCore配置 Swagger 中间件为了配置 Swagger,在 Startup.ConfigureServices 办法中增加如下代码,留神上面的 AddSwaggerGen 办法是用于给 API 文档 增加一些元数据。 services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Info { Version = "v1", Title = "Swagger Demo", Description = "Swagger Demo for ValuesController", TermsOfService = "None", Contact = new Contact() { Name = "Joydip Kanjilal", Email = "joydipkanjilal@yahoo.com", Url = "www.google.com" } }); });接下来就要启动 Swagger了,在 Startup.Configure 办法下增加如下代码: ...

January 28, 2021 · 3 min · jiezi

关于.net:如何在-C-中使用-MSMQ

MSMQ 是 Windows 自带的音讯队列,它提供了在多机器,多零碎之间实现牢靠的音讯互联,MSMQ 反对可扩大,线程平安,应用简略等强势个性。 MSDN 上说:音讯队列技术使不同时刻运行的程序能够在异构网络或者异构零碎中进行交互,即便对方不在线也没有关系,应用程序仅关怀如何从队列中读取或写入音讯。 通常和 MSMQ 交互的应用程序有两种角色,发布者 和 消费者,发布者应用程序将音讯发送后,不要求消费者应用程序放弃备战状态,实际上这个音讯是被送到 操作系统保护的 音讯队列 中,供后续某个时刻须要此音讯的 接收者应用程序 生产。 创立队列能够在 Windows 控制面板上通过 Turn Windows features on or off 选项进行 MSMQ 的装置,一旦 MSMQ 装置好之后,接下来就能够创立队列了,你能够在 Computer Management 上的 Message Queuing 节点上可视化创立,也能够通过编程的形式创立,本篇就来探讨前面这种形式。 编程创立 MSMQ先援用 System.Messaging 命名空间,而后应用 MessageQueue.Create 创立音讯队列,上面的代码展现了如何实现。 MessageQueue.Create(@".\Private$\IDG");队列创立好之后,接下来就能够向其发送 message 了,如下代码所示: MessageQueue.Create(@".\Private$\IDG"); messageQueue = new MessageQueue(@".\Private$\IDG");messageQueue.Label = "This is a test queue.";messageQueue.Send("This is a test message.", "IDG");有一点要留神,在发送音讯之前,你须要查看队列是否存在,如果不存在,你必须要先创立一个,如果存在则不用再创立,上面的代码展现了如何去实现。 static void Main(string[] args) { MessageQueue messageQueue = null; string description = "This is a test queue."; string message = "This is a test message."; string path = @".\Private$\IDG"; try { if (MessageQueue.Exists(path)) { messageQueue = new MessageQueue(path); messageQueue.Label = description; } else { MessageQueue.Create(path); messageQueue = new MessageQueue(path); messageQueue.Label = description; } messageQueue.Send(message); } catch { throw; } finally { messageQueue.Dispose(); } }下面是音讯的发送,接下来再看一下如何从 音讯队列 中获取音讯,代码如下: ...

January 28, 2021 · 2 min · jiezi

关于.net:如何在-ASPNET-Core-中使用-NLog-的高级特性

NLog 是一个开源的轻量级日志框架,提供了丰盛的日志路由和治理性能,同时 NLog 也是非常容易的去配置和扩大,其实在之前的文章中我曾经探讨过了 Nlog,在这篇我筹备持续和大家讨论一下 NLog 的更多高级性能。 接下来看看如何通过 .config 和 代码形式 配置 NLog,如何去 轮转日志,如何将 Log 对接 database,如何应用异步的模式进步日志写入性能,同时我还会分享一些 NLog 的教训技巧。 装置 NLog能够通过 NuGet Package Manager 可视化界面 或者 NuGet Package Manager Console 控制台 装置以下包文件。 NLog.Web.AspNetCoreNLog.Extensions.LoggingNLog.Config当你装置完 NLog.Config 之后,有一个叫做 NLog.config 文件会主动援用到你的我的项目中,值得注意的是,NLog.Config 对 NLog 来说不是惟一的,话中有话就是你即能够用 config 模式配置,也能够用 基于代码 的模式配置。 应用 .config 文件配置 NLogNLog 提供了两种配置形式。 file-based 配置模式code-based 配置模式回到方才的问题,如何采纳 file-based 模式,方才被引入的 NLog.Config 内容如下: <?xml version="1.0" encoding="utf-8" ?><nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"autoReload="true"> <extensions> <add assembly="NLog.Web.AspNetCore"/> </extensions> <targets> <target name="logfile" xsi:type="File" fileName="D:\logs\LogMessages-${shortdate}.log" /> </targets> <rules> <logger name="*" minlevel="Trace" writeTo="logfile" /> </rules></nlog>上面的代码展现了如何在 Controller 下用 NLog 记录日志。 ...

January 28, 2021 · 3 min · jiezi

关于.net:如何在-NetCore-中使用-AutoMapper-高级功能

AutoMapper 是一个基于约定的面向对象的映射器,它的性能罕用于将一个 input 对象 转成一个不同类型的 output 对象,input 和 output 对象之间的属性可能雷同也可能不雷同,这一篇咱们来一起钻研一下 AutoMapper 的一些高级玩法。 装置 AutoMapper要想在我的项目中应用 AutoMapper ,须要通过 nuget 援用 AutoMapper 和 AutoMapper.Extensions.Microsoft.DependencyInjection 包,能够通过 Visual Studio 2019 的 NuGet package manager 可视化界面装置 或者 通过 NuGet package manager 命令行工具输出以下命令: Install-Package AutoMapperInstall-Package AutoMapper.Extensions.Microsoft.DependencyInjection配置 AutoMapper一旦 AutoMapper 胜利装置之后,接下来就能够将它引入到 ServiceCollection 容器中,如下代码所示: public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddAutoMapper(typeof(AuthorProfile)); }应用 profiles 对立治理 mapping 信息能够应用 profiles 来对立组织你的 mapping 信息,要创立 profile,须要实现 AutoMapper 提供的 Profile 类,而后在你方才创立的 Profile 子类的构造函数中增加映射信息,上面的代码展现了如何创立一个从 Proifle 继承的 AuthorProfile 类以及相干信息。 ...

January 28, 2021 · 3 min · jiezi

关于.net:如何实现-ASPNET-Core-WebApi-的版本化

Web API 的版本化能够尽量保障在雷同url状况下保留一个 api 的多个版本,通常一个 webapi 会有多个client,这些client包含:app,web,html5,crawl 等等同构或者异构的平台,当 api 降级之后,往往降级前的 api 也得保留,当保护两个api的时候就是一个不小的挑战,毕竟还是存在一些 client 用户须要拜访老的api,这时候就须要将 webapi 版本化。 装置 Versioning 包要想应用 webapi 的版本化性能,须要用 nuget 援用 Microsoft.AspNetCore.Mvc.Versioning 包,还能够通过 Visual Studio 2019 的 NuGet package manager 可视化界面装置 或者 通过 NuGet package manager 命令行工具输出以下命令: dotnet add package Microsoft.AspNetCore.Mvc.Versioning启动 API 版本化当包胜利增加到我的项目之后,接下来就能够在 Startup.ConfigureServices 中将 ApiVersioning 注入到容器中,如下代码所示: public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddApiVersioning(); } }在调用 AddApiVersioning() 的时候记得 using Microsoft.AspNetCore.Mvc.Versioning,除了这个默认办法,还能够做一些全局配置,如下代码所示: public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddApiVersioning(v => { v.ReportApiVersions = true; v.AssumeDefaultVersionWhenUnspecified = true; v.DefaultApiVersion = new ApiVersion(1, 0); }); } }应用 QueryString 指定版本号先来看一下代码,思考如下的 api。 ...

January 28, 2021 · 3 min · jiezi

关于.net:net的常规命名规范示例

1.用Pascal规定来命名办法和类型。(笔者注:单词首字母大写) public class DataGrid { public void DataBind() { } } 2.用Camel规定来命名局部变量和办法的参数. (笔者注:首单词小写,其余单词首字母大写;笔者应用此形式命名成员变量) public class Product { private string _productId; private string _productName; public void AddProduct (string productId,string productName) { } } 补充:应用匈牙利形式命名局部变量,办法参数和控件命名。 如int iCount,string strName Label的lblTitle,Button btnSubmit等 3.所有的(公有)成员变量前加前缀“_”。 public class DataBase { private string _connectionString; } 不要应用public成员变量,而用.net里的属性get,set 4.接口的名称加前缀 “I”。 public interface IConvertible { byte ToByte(); } 5.自定义的属性以“Attribute”结尾。 public class TableAttribute:Attribute { } 6.自定义的异样以Exception结尾。 public class TableAttribute:Attribute { } ...

January 27, 2021 · 1 min · jiezi

关于.net:如何在-ASPNET-Core-中使用-NLog-的高级特性

NLog 是一个开源的轻量级日志框架,提供了丰盛的日志路由和治理性能,同时 NLog 也是非常容易的去配置和扩大,其实在之前的文章中我曾经探讨过了 Nlog,在这篇我筹备持续和大家讨论一下 NLog 的更多高级性能。 接下来看看如何通过 .config 和 代码形式 配置 NLog,如何去 轮转日志,如何将 Log 对接 database,如何应用异步的模式进步日志写入性能,同时我还会分享一些 NLog 的教训技巧。 装置 NLog能够通过 NuGet Package Manager 可视化界面 或者 NuGet Package Manager Console 控制台 装置以下包文件。 NLog.Web.AspNetCoreNLog.Extensions.LoggingNLog.Config当你装置完 NLog.Config 之后,有一个叫做 NLog.config 文件会主动援用到你的我的项目中,值得注意的是,NLog.Config 对 NLog 来说不是惟一的,话中有话就是你即能够用 config 模式配置,也能够用 基于代码 的模式配置。 应用 .config 文件配置 NLogNLog 提供了两种配置形式。 file-based 配置模式code-based 配置模式回到方才的问题,如何采纳 file-based 模式,方才被引入的 NLog.Config 内容如下: <?xml version="1.0" encoding="utf-8" ?><nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"autoReload="true"> <extensions> <add assembly="NLog.Web.AspNetCore"/> </extensions> <targets> <target name="logfile" xsi:type="File" fileName="D:\logs\LogMessages-${shortdate}.log" /> </targets> <rules> <logger name="*" minlevel="Trace" writeTo="logfile" /> </rules></nlog>上面的代码展现了如何在 Controller 下用 NLog 记录日志。 ...

January 26, 2021 · 3 min · jiezi

关于.net:如何在-C-中使用-反射

C# 中的 反射 罕用于在程序的运行时获取 类型 的元数据,可获取的信息包含已加载到过程中的 程序集 和 类型 信息,它和 C++ 中的 RTTI(Runtime Type Information) 的作用是差不多的。 为了可能应用反射,须要在我的项目中援用 System.Reflection 命名空间,在应用反射的开始,你会获取一个 Type 类型的对象,从这个对象上进一步获取 程序集,类型,模块 等信息,能够通过 反射 动静的生成某个类型的实例,甚至还能动静调用这个类型上的办法。 在 System.Reflection 命名空间下,定义了如下几大外围类型。 AssemblyModuleEnumMethodInfoConstructorInfoMemberInfoParameterInfoTypeFieldInfoEventInfoPropertyInfo当初咱们一起钻研一下怎么应用,思考上面定义的 Customer 类。 public class Customer { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Address { get; set; } }上面的代码片段展现了如何通过 反射 来获取 Customer 的类名以及 Customer 的所属命名空间。 ...

January 26, 2021 · 2 min · jiezi

关于.net:如何在-ASPNET-Core-中-使用-cookies

cookie 罕用于保留用户相干并保留在客户端电脑上的一段数据,在大多数浏览器下,每一个cookie 都会是一个小文件的模式存在,只有 Firefox 例外,它将所有的 cookie 都保留在一个文件中,cookie 是以 key-value 的模式体现的,能够通过这个 key 去 读取,删除,写入 等操作。 ASP.NET Core 中应用 cookie 机制来保护 session 状态,在客户端的每一次申请中,server 端都会将 sessionid 放在 cookie 中发送给客户端来实现用户跟踪,这篇文章咱们就来探讨如何应用 cookie 机制。 读取 Cookie要想读取 Cookie 能够采纳 ASP.NET Core 中的 Request.Cookies 属性,上面的代码片段展现了如何从 Request 对象中读取 cookie。 string cookie = Request.Cookies["Key"];如果你想给 cookie 设置一个过期工夫,能够应用 Cookies.Append 重载办法,如下代码所示: CookieOptions option = new CookieOptions(); option.Expires = DateTime.Now.AddMilliseconds(10); Response.Cookies.Append(key, value, option); 从下面代码中能够看到,在生成 Cookie 的过程中能够应用 CookieOptions 来给其配置一些额定参数,大体参数如下: Domain用于指定 cookie 关联的域级别。 Expiration time用于指定 cookie 的过期工夫 ...

January 26, 2021 · 2 min · jiezi

关于.net:如何在-ASPNET-Core-中-使用-功能开关

.NET Core 中的 性能治理 (Feature Management) 包可用于实现 性能开关,什么意思呢? 就是能够通过 性能开关 个性动静的扭转应用程序的行为而不须要扭转任何的业务逻辑代码,听起来是不是挺有意思,本篇咱们就来探讨如何应用这个包。 装置 Feature Management 包要想应用 性能治理,须要通过 NuGet 装置 Microsoft.FeatureManagement.AspNetCore,可通过 Visual Studio 2019 下的 NuGet Package Manager 可视化治理界面 或者 通过 .NET CLI 命令行工具输出如下命令。 dotnet add package Microsoft.FeatureManagement.AspNetCore在 ASP.NET Core 中增加为了可能在我的项目中用上 性能治理,须要在 Startup.ConfigureServices 办法下进行 service 注入,如下代码所示: public class Startup { // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddFeatureManagement(); } }有一点要留神: 性能治理 中的 性能开关 读取的值来自于 .NET Core 中的配置文件,如果你想让 性能开关 的值来源于 Configuration 文件的不同节点,必须在 service 注册时独自指定一下,如下代码所示: ...

January 25, 2021 · 2 min · jiezi

关于.net:如何在-ASPNET-Core-中使用-ActionFilter

ASP.NET Core MVC 中的 Filters 容许咱们在 申请解决管道 中的某一个阶段的之前和之后执行自定义代码,不同类型的 filter 对应着 申请解决管道 的不同阶段,比如说:ActionFilter 能够在 Action 办法的之前或者之后执行自定义代码,这篇文章咱们就来探讨 ASP.NET Core MVC 中内建的 ActionFilter,为什么它十分有用以及在程序中如何应用它。 Filter 过滤器其实在 ASP.NET Core MVC 中有很多的内建 filter,大体列举如下: ActionFilters它会在 Action 办法的执行前和执行后 执行。 AuthorizationFilters它会在 申请解决管道 的开始处被执行,次要用来获取用户的 凭证信息 来验证用户是否被受权。 ResourceFilters它会在 authorization 之后 和 模型绑定 之前被执行,能够利用它实现一些缓存逻辑。 ExceptionFilters它会捕捉到 申请解决管道 中的所有异样,所以可用它来实现一些自定义的异样解决。 到底用哪一种类型的 filter,还是取决于你到底想实现什么业务,举个例子,如果你想 短路 request,提前结束 pipeline 管道返回后果,是不是就能够用 ResourceFilters 哈,再举一个例子,如果你想批改 Action 的入参 并且想对 Action 的后果进行批改,那么 ActionFilter 就是你的最佳抉择。 ASP.NET Core MVC 中有一个个性叫 ActionFilterAttribute,它实现了如下接口 IActionFilter, IAsyncActionFilter, IResultFilter, IAsyncResultFilter, IOrderedFilter,能够利用它实现不同层级的Filter,如: Action级,Controller级,全局级,稍后咱们将会一一探讨。 ...

January 25, 2021 · 2 min · jiezi

关于.net:如何在-ASPNET-Core-中写出更干净的-Controller

你能够遵循一些最佳实际来写出更洁净的 Controller,个别咱们称这种办法写进去的 Controller 为瘦Controller,瘦 Controller 的益处在于领有更少的代码,更加繁多的职责,也便于浏览和保护,而且随着工夫的推移也容易做 Controller 的多版本。 这篇文章咱们一起探讨那些让 Controler 变胖变臃肿的一些坏滋味,并且一起摸索让 Controller 变瘦的伎俩,尽管我的一些在 Controller 上的最佳实际可能不是业余的,但我每一步都提供相干源代码来进行优化,接下来的章节中,咱们会探讨什么是 胖Controller,什么是 坏滋味,什么是 瘦Controller,它能带给咱们什么福利? 并且如何让 Controller 变瘦,变简略,利测试,易保护。 从 Controller 中移除数据层代码当在写 Controller 的时候,你应该恪守 繁多职责,也就意味着你的 Controller 只需做一件事件,换句话说,只有一个因素或者惟一一个因素能让你批改 Controller 中的代码,如果有点懵的话,思考上面的代码片段,它将 数据拜访代码 糅进了 Controller 。 public class AuthorController : Controller{ private AuthorContext dataContext = new AuthorContext(); public ActionResult Index(int authorId) { var authors = dataContext.Authors .OrderByDescending(x=>x.JoiningDate) .Where(x=>x.AuthorId == authorId) .ToList(); return View(authors); } //Other action methods}请留神下面的代码在 Action 中应用了 dataContext 从数据库读取数据,这就违反了繁多职责准则,并间接导致了 Controller 的臃肿。 ...

January 25, 2021 · 2 min · jiezi

关于.net:如何在-ASPNET-Core-中-自定义中间件

ASP.NET Core 是一个跨平台,开源的,轻量级,高性能 并且高度模块化的web框架,同时扩展性也是十分强,你能够在 request -> response 申请管道中安插各种中间件来依据本人的场景定制化,比如说:监督,路由,批改 request 或 response 音讯体,这篇文章咱们就来探讨 ASP.NET Core 中间件以及如何应用。 ASP.NET Core 中存在一条 中间件 链条,这条链是由一组 委托办法 组成,这些委托办法会一个接一个的被执行,request 申请会从这些中间件链条中流转,被流转到的组件,要么解决这个申请,要么将申请传给下一个中间件。 配置 中间件管道中间件的管道配置是在 Startup.Configure 办法中 ,精确的说这里就是组装你的 ASP.Net Core 申请管道,ASP.Net运行时会主动调用这个 Configure 办法,代码如下: public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IdentityDbContext dbContext) { app.UseDeveloperExceptionPage(); app.UseStaticFiles(); app.UseMvcWithDefaultRoute(); }下面的代码展现了如何将 mvc 增加到 ASP.Net Core 的 申请解决管道 中,接下来筹备实现自定义中间件。 创立自定义中间件能够利用 IApplicationBuilder 接口的扩大办法来构建你的中间件,为了代码可维护性,倡议将自定义的中间件逻辑独自放在一个类中,或者一个独自的我的项目中,这样你在更新这些代码的时候不须要更新业务逻辑层的代码。 有多种办法能够构建自定义中间件,我筹备来演示那最简略的一种,首先创立一个名为 MyCustomMiddleware 的cs类,骨架代码大略是这样: public class MyCustomMiddleware { //This is our custom middleware }接下来在类的构造函数中新增一个 RequestDelegate 参数,这个 RequestDelegate 委托的签名是接管 HttpContext 参数 并返回 Task,上面是批改后的 MyCustomMiddleware。 ...

January 25, 2021 · 2 min · jiezi

关于.net:如何在-ASPNET-Core-中使用-静态文件

ASP.NET Core 反对间接向客户端提供动态文件,比方:Html文件,图片,js文件,为了可能让 ASP.NET Core 解决动态文件,须要应用 动态文件中间件 并做一些必要配置就能够了,这篇文章咱们就来一起探讨下。 装置 动态文件中间件要想装置 动态文件中间件,必须将 Microsoft.AspNetCore.StaticFiles 增加到 ASP.NET Core 的申请管道中,能够应用 Visual Studio 2019 中的 NuGet package manager 可视化界面,要么用 NuGet package manager console 在命令行窗口中键入如下命令。 dotnet add package Microsoft.AspNetCore.Rewrite根底信息配置上面的代码展现了在 Startup 中如何对 动态文件中间件 进行配置。 public void Configure(IApplicationBuilder app, IWebHostEnvironment env){ app.UseStaticFiles(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); endpoints.MapRazorPages(); });}ASP.NET Core 中解决 动态文件动态文件都是对立配置在 wwwroot 文件夹下, 能够看到 wwwroot文件夹下还有 css,images,js 等文件夹,值得注意的是这些文件夹之间能够采纳相对路径进行拜访。 如果 动态文件中间件 曾经胜利配置好,接下来能够应用上面的门路拜访 test.png 图片。 ...

January 25, 2021 · 2 min · jiezi

关于.net:如何在-C-中使用-投影Projection

投影(Projection) 是一种能够将查问后果进行 塑性 的一种操作,你能够应用 投影 将一个 object 转成仅蕴含你须要属性的新对象,这篇文章中,咱们就一起看看如何应用 投影 性能。 C# 中的投影LINQ 集成查问中有两个反对投影的扩大办法,别离为: Select 和 SelectMany 操作,能够用它们投影单个或者多个属性,或者投影查问的后果集到一个新的匿名类型中,还能够在投影的过程中执行: 再计算,过滤,或者其余一些必要的操作。 Select 投影为了演示目标,我先结构一个 Author 类,代码如下: public class Author { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Address { get; set; } public Author(int id, string firstName, string lastName, string address) { this.Id = id; this.FirstName = firstName; this.LastName = lastName; this.Address = address; } }上面的代码展现了如何应用 Select 操作去查问数据。 ...

January 24, 2021 · 2 min · jiezi

关于.net:如何使用-C-在异步代码中处理异常

异样解决是一种解决运行时谬误的技术,而 异步编程 容许咱们在解决资源密集型的业务逻辑时不须要在 Main 办法或者在 执行线程 中被阻塞,值得注意的是,异步办法和同步办法的异样解决机制是不一样的,本篇咱们就来探讨下如何在异步办法中解决异样。 ## 异步办法 VS 同步办法 的异样解决 在同步代码中抛出异样,它会始终以冒泡的形式往上抛,直到遇到能够解决这个异样的 catch 块为止,能够设想,异步办法中的异样抛出必定要比这个简单。 大家都晓得 异步办法 能够有三种返回类型,如:void, Task, Task<TResult>,当异样办法的返回值是 Task ,Task<TResult> 的办法中抛出异样的话,这个异样对象会被塞到 AggregateException 对象中,而后包裹在 Task 中进行返回,有些敌人可能要问,如果异步办法中抛出了几个异样怎么办?其实也是一样的情理,这些异样对象都会被塞到 AggregateException 中通过 Task 去返回。 最初,如果异样呈现在返回值为 void 的异步办法中,异样是在调用这个异步办法的 SynchronizationContext 同步上下文上触发。 返回 void 异步办法中的异样上面的程序展现了返回 void 的异步办法中抛出了异样。 class Program { static void Main(string[] args) { ThisIsATestMethod(); Console.ReadLine(); } public static void ThisIsATestMethod() { try { AsyncMethodReturningVoid(); } catch (Exception ex) { Console.WriteLine(ex.Message); } } private static async void AsyncMethodReturningVoid() { await Task.Delay(1000); throw new Exception("This is an error message..."); } } ...

January 24, 2021 · 2 min · jiezi

关于.net:如何在-ASPNET-Core-中使用-URL-Rewriting-中间件

URL rewriting 是依据事后配置好的一组规定去批改 request url,值得注意的是:URL Rewriting 的重写性能和 url 重定向 是两个概念,本篇咱们就来探讨下如何在 ASP.NET Core 中对 url 进行 rewriting。 装置 URL Rewriting 中间件要想应用 URL Rewriting 性能,须要通过 nuget 援用 Microsoft.AspNetCore.Rewrite 包,能够通过 Visual Studio 2019 的 NuGet package manager 可视化界面装置 或者 通过 NuGet package manager 命令行工具输出以下命令: dotnet add package Microsoft.AspNetCore.Rewriteurl重定向 和 url重写url重定向 和 url重写 是两个齐全不同的概念,url重定向是 server 端返回 Http Status Code 301 或者 302 给 客户端并且通知客户端应用另一个链接拜访资源,客户端拿到新链接后实现跳转,从这个过程中能够看出,这个操作是产生在客户端,而且还多了一个不可回避的 round-trip。 相同,url重写 是server端的操作,它会依据预先指定的一组规定去批改request url,在 rewriting 的过程中,批改后的 request url 不会和 重定向 一样再发送给客户端,只有是在一个申请内,client 基本不关怀 server 端外部是如何实现资源切换的,值得注意的是,URL rewriting 也不是什么新的技术,在 ASP.NET 时代就有了。 ...

January 24, 2021 · 2 min · jiezi

关于.net:如何在-C-中使用-constreadonlystatic

平时在开发时常常会用到 const,readonly,static 关键字,能够必定这些关键词是齐全不同的概念,但有时候他们在用法上很类似以至于在场景中不晓得抉择哪一个,这篇文章咱们就来探讨 C# 中的 const,static 和 readonly 关键词,放在一起比拟一下看看如何抉择。 了解 constconst 罕用来定义一个常量,什么意思呢?就是这个常量在你程序的生命周期内都不会被扭转,因而,必须在申明常量时为其赋值,从技术角度上来说:这个常量值又被称为 编译时 值,用 const 定义的变量又被称为 编译时 常量,值得注意的是: 这个常量是不可变的,也就是一旦被定义好之后不能够对其进行批改。 上面的代码片段展现了如何应用 const 去定义这个 编译时 常量。 const string connectionString = "Specify your database connection string here.";肯定要记住,常量必须在定义的时候给它赋值,同时也要记住不能够用 const 定义 object 类型,因为它只反对 C# 的基元类型,比方:ints, floats, chars, booleans 和 strings,接下来通过一个例子来理解以下为啥不能用 object,思考上面的 Author 类。 public class Author { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Address { get; set; } }如果用 const 将 Author 定义为常量的话,编译器必定是不批准的,如下图: ...

January 24, 2021 · 1 min · jiezi

关于.net:如何在-C-中使用-Buffer

缓冲区 是内存中的一组字节序列,缓冲 是用来解决落在内存中的数据,.NET 缓冲 指的是解决 非托管内存 中的数据,用 byte[] 来示意。 当你想把数据写入到内存或者你想解决非托管内存中的数据,能够应用 .NET 提供的 System.Buffer类,这篇文章就来探讨如何应用 Buffer。 Buffer 下的办法列表Buffer 类蕴含了上面几个办法: BlockCopy(Array, Int32, Array, Int32)用于将指定地位开始的 原数组 copy 到 指定地位开始的 指标数组。 ByteLength(Array)示意数组中 byte 字节的总数。 GetByte(Array, Int32)在数组一个指定地位中提取出一个 byte。 SetByte(Array, Int32, Byte)在数组的一个指定地位中设置一个 byte。 MemoryCopy(Void, Void, Int64, Int64)从第一个源地址上copy 若干个byte 到 指标地址中。 了解 Array 和 Buffer在理解 Buffer 之前,咱们先看看 Array 类,Array 类中有一个 Copy() 办法用于将数组的内容 copy 到另一个数组中,在 Buffer 中也提供了一个相似的 BlockCopy() 办法和 Array.Copy() 做的一样的事件,不过 Buffer.BlockCopy() 要比 Array.Copy() 的性能高得多,起因在于前者是依照 byte 拷贝,后者是 content 拷贝。 ...

January 24, 2021 · 2 min · jiezi

关于.net:如何在-C-中使用-委托

委托是一个类型平安的函数指针,它能够援用与委托具备雷同签名的办法,你能够利用 委托 实现事件或者回调函数,多播委托 能够援用一个或者多个具备雷同签名的办法。 了解 委托实质上来说,委托蕴含了一个对办法的援用,概念上和 C ++ 上的函数指针是一样的,惟一不一样的是 C# 中的 委托 是类型平安的,你能够将办法作为参数传给 委托,而从让 委托 持有对办法的援用,委托罕用于定义成 回调函数 和 事件处理,个别用 delegate 关键词去申明,能够将 delegate 定义成 类平级,也能够嵌套在 类中。 应用 委托 个别有以下三个步骤: 初始化 declaration实例化 instantiation调用 invocation委托签名的语法格局如下: delegate result-type identifier ([parameters])上面的代码展现了如何套用语法格局实现一个委托。 public delegate void MyDelegate(string text);下面的代码能够看出,委托的名字为 MyDelegate, 它的返回值为 void,并且接管一个 string 类型的参数,这就意味着,委托需指向的办法也必须和这个委托具备雷同的签名,下面只是 委托 的一个定义,要应用的话,还得塞入一个同签名的办法,代码如下。 MyDelegate d = new MyDelegate(ShowText);一旦定义实现并且胜利实例化后,接下来就能够执行这个委托了,如下代码所示: d("Hello World...");这里的 d 就是 委托实例,除了下面这种调用办法,还能够调用委托的 Invoke() 来执行委托所援用的办法。 d.Invoke("Hello World...");如果你有一个办法接管两个参数作为入参,两个参数的累计值作为办法的返回值,那这种委托该怎么定义呢?残缺代码如下: using System;namespace Delegates{ public delegate int MyDelegate(int x, int y); class Program { static int Sum(int x, int y) { return x + y; } static void Main() { MyDelegate d = new MyDelegate(Sum); int result = d.Invoke(12, 15); Console.WriteLine(result); Console.ReadLine(); } }} 委托实际首先看下残缺的代码清单。 ...

January 23, 2021 · 2 min · jiezi

关于.net:如何在-C-中使用-ValueTask

异步编程 置信大家曾经应用很多年了,尤其在 C# 5.0 中引入的 await,async 关键词让代码编写的更加简略粗犷,你能够利用 异步编程 来进步应用程序的 响应速度 和 吞吐率。 异步办法中举荐的做法是返回 Task,如果异步办法中须要返回一些数据的话,能够将 Task 改成 Task<T>,还有一种状况是你的异步办法什么都不须要返回,那就改成 void 就能够了。 在 C# 7.0 之前,异步办法的返回值有以下三种。 TaskTask<T>void在 C# 7.0 之后,除了下面三种还能够返回 ValueTask 和 ValueTask<T>,这些类都是在 System.Threading.Tasks.Extensions 命名空间下,这篇文章我筹备和大家一起探讨下 ValueTask。 为什么要应用 ValueTaskTask 可用来示意操作的状态,什么意思呢?比如说:这个操作是否实现?是否被勾销 等等,同时 异步办法 中能够返回 Task 或者 ValueTask,这里有个潜在的问题不晓得大家是否留神到,因为Task 是一个援用类型,如下代码: public class Task : IAsyncResult, IDisposable { }这就意味着每次调用异步办法都会在 托管堆 上生成一个 Task 实例,如果霎时调用 1w 次,那么托管堆上也霎时存在 1w 个 Task 实例,那这有什么问题呢? 问题在于有些场景下,你的异步办法是能够间接返回数据的,或者说能够齐全同步的,比方:你的异步办法仅仅是从缓存中取数据,这时候无谓的给 GC 减少回收压力就不那么柔美了。 static Task<int> GetCustomerCountAsyc(string key) { return Task.FromResult<int>(NativeCache[key]); }这时候就须要用 ValueTask 了,它提供了如下两点益处: ...

January 23, 2021 · 2 min · jiezi

关于.net:如何在-ASPNET-Core-中使用-Route-特性

ASP.NET Core 中的 Route 中间件的职责在于将 request 匹配到各自 Route 处理程序上,Route 分两种:基于约定 和 根本个性 模式。 基于约定 模式的Route采纳集中化的形式,而 基于个性 的形式容许你在 Action 或者 Controller 上独自定义,到底采纳哪一种能够基于你本人的利用场景,本篇就来探讨如何应用 基于个性 模式。 创立 Controller 类创立一个 DefaultController 类,新增如下代码。 public class DefaultController : Controller { [Route("")] [Route("Default")] [Route("Default/Index")] public ActionResult Index() { return new EmptyResult(); } [Route("Default/GetRecordsById/{id}")] public ActionResult GetRecordsById(int id) { string str = string.Format ("The id passed as parameter is: {0}", id); return Ok(str); } }Controller 级别定义 Route 个性Route个性可用于 Controller 和 Action 级别,值得注意的是,如果应到到前者,那么 Controller 下的所有 Action 都受这个 Route 管控。 ...

January 23, 2021 · 2 min · jiezi

关于.net:如何在-Core-Web-API-中以三种方式返回数据

在 ASP.NET Core 中有三种返回 数据 和 HTTP状态码 的形式,最简略的就是间接返回指定的类型实例,如下代码所示: [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { [HttpGet] public IEnumerable<WeatherForecast> Get() { var rng = new Random(); return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }) .ToArray(); } }除了这种,也能够返回 IActionResult 实例 和 ActionResult <T> 实例。 尽管返回指定的类型 是最简略粗犷的,但它只能返回数据,附带不了http状态码,而 IActionResult 实例能够将 数据 + Http状态码 一起带给前端,最初就是 ActionResult<T> 它封装了后面两者,能够实现两种模式的自在切换,????吧。 接下来一起探讨下如何在 ASP.NET Core Web API 中应用这三种形式。 ...

January 23, 2021 · 2 min · jiezi

关于.net:如何在-C-中使用-数据注解

数据注解 是一种能够利用到 类 或者 类成员上用来指定类之间关系的一种 Attribute,它的利用场景比拟多,可用来形容 UI 上如何进行数据展现,还能够用来做类属性的规定验证,这篇文章就来探讨为什么 注解 值得你去学习,以及如何在 .NET Core 中应用。 应用 System.ComponentModel.DataAnnotations要想运行本篇的例子,须要将 System.ComponentModel.DataAnnotations 援用到我的项目中。 值得注意的是,Attribute 罕用来给 class 或者 property 标注元数据信息,很显然 注解 Atrribute 也是 Attribute 的一种,它的分类大略有以下几种。 Validation attribute从名字上就能看出,次要用在 实体属性上,目标是用来管控 属性值 的有效性。 Display attribute用来指定数据如何在 UI 上展现。 Modeling attribute用来指定类之间的关系。 了解 数据注解 类在 System.ComponentModel.Annotations 命名空间下有如下几个注解类。 ConcurrencyCheckKeyMaxLengthRequiredStringLengthTimestamp数据注解 案例展现当初新建一个 Author 类,代码如下: public class Author { [Required(ErrorMessage = "{0} is required")] [StringLength(50, MinimumLength = 3, ErrorMessage = "First Name should be minimum 3 characters and a maximum of 50 characters")] [DataType(DataType.Text)] public string FirstName { get; set; } [Required(ErrorMessage = "{0} is required")] [StringLength(50, MinimumLength = 3, ErrorMessage = "Last Name should be minimum 3 characters and a maximum of 50 characters")] [DataType(DataType.Text)] public string LastName { get; set; } [DataType(DataType.PhoneNumber)] [Phone] public string PhoneNumber { get; set; } [DataType(DataType.EmailAddress)] [EmailAddress] public string Email { get; set; } }上面的代码片段展现了如何给 Author 的属性赋值。 ...

January 23, 2021 · 3 min · jiezi

关于.net:如何使用-Dapper-中的异步方法

Dapper 是一个 容易上手,轻量级,灵便高效,开源的 迷你 ORM,由 Stack Overflow 团队的 Sam Saffron 出品,你能够利用 Dapper 简化数据拜访并且反对高性能, 还有一点, Dapper 提供了很多异步办法,本篇咱们就来聊一聊如何在 ASP.NET Core 中应用 Dapper 的异步办法。 装置 Dapper能够通过 Visual Studio 2019 IDE 中的 NuGet package manager 可视化界面装置,也能够在 .NET CLI 命令行中输出以下命令。 dotnet add package Install-Package Dapper一旦 package 胜利装置到你的我的项目中,接下来就能够正式应用了。 应用异步办法Dapper提供了几个异步办法,可用于异步的执行 CURD 操作,上面是 Dapper 的异步办法清单。 ExecuteAsyncQueryAsyncQueryFirstAsyncQueryFirstOrDefaultAsyncQuerySingleAsyncQuerySingleOrDefaultAsyncQueryMultipleAsync为了演示目标,我就应用前两个异步办法进行演示。 QueryAsync 和 ExecuteAsync创立一个 Author 实体类 public class Author { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Address { get; set; } }接下来创立一个 IAuthorRepository 接口 ...

January 22, 2021 · 2 min · jiezi

关于.net:如何-ASPNET-Core-中实现重定向

ASP.NET Core 是一个跨平台,开源的,轻量级的,模块化的,用于构建高性能的 web 开发框架, ASP.NET Core MVC 内置了多种形式将一个 request 申请跳转到指定的url,这篇文章咱们就来探讨如何去实现。 了解 RedirectActionResultASP.NET Core MVC 中内置了几种 Redirect,比如说:RedirectResult, RedirectToActionResult, RedirectToRouteResult 和 LocalRedirectResult,这些类都继承于 ActionResult 并可给前端返回 Http 302,Http 301,Http 307 和 Http 308 这些状态码。 接下来的文章中咱们就来看看如何应用这些类。 应用 RedirectResult能够应用上面任何一个办法来返回 RedirectResult。 Redirect 返回 Http 状态码为 302RedirectPermanent 返回 Http 状态码为 301RedirectPermanentPreserveMethod 返回 Http 状态码为 308RedirectPreserveMethod 返回 Http 状态码为 307具体状态码代表什么意思,大家可查业余材料,上面的代码展现了如何应用这些办法。 Redirect("/Home/Index");RedirectPermanent("/Home/Index");RedirectPermanentPreserveMethod("/Home/Index");RedirectPreserveMethod("/Home/Index");如果你被这些办法搞蒙圈了,能够间接应用 RedirectResult ,而后通过 permanent 和 preserveMethod 两个参数去调节返回什么样的 Http 状态码即可, 代码如下所示: public RedirectResult Index(){ return new RedirectResult(url: "/Home/Index", permanent: true, preserveMethod: true);} ...

January 22, 2021 · 2 min · jiezi

关于.net:如何在-ASPNET-Core-中使用-API-Analyzer

ASP.NET Core 2.2 引入了 API 分析器,它有利于进步 API 的文档化,API分析器 能够利用在任何带有 ApiController 个性的 Controller 上,本篇就和大家一起探讨下。 装置 API 分析器如果你应用的是 ASP.NET Core 2.2 的话,用 Visual Studio 中的 NuGet Package Manager 可视化面板 或者 NuGet Package Manager Console 命令行输出如下命令装置 Api Analyzer。 Install-Package Microsoft.AspNetCore.Mvc.Api.Analyzers值得注意的是,在 ASP.NET Core 3.0 中曾经内置了 Microsoft.AspNetCore.Mvc.Api.Analyzers,所以不须要独自装置。 创立 model 和 repository生成一个 Author 类,代码如下: public class Author { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } }为了简略起见,我筹备创立一个非常简单的 Repository,不连贯数据库,如下代码所示: ...

January 22, 2021 · 3 min · jiezi

关于.net:如何使用-C-中的-Lambda-表达式

.NET 3.5 中引入了 Lambda 表达式,它的呈现也让 Linq 真正的落地,Lambda 表达式 像一个匿名办法,但比匿名办法更具备灵活性,当应用 lambda 表达式时,你不须要指定输出参数的类型,也就看得出 Lambda 表达式 具备更短更洁净的个性。 分析 lambda 表达式从实质上来说,Lambda 表达式 就是一个不须要当时定义的办法,没有办法名,也没有拜访修饰符,lambda 表达式 能够分成两局部来了解,即 右边 和 左边,前者示意办法的入参,后者示意办法体。 上面是 lambda 表达式 的语法结构。 (Input parameters) => Expression or statement blocklambda 表达式 反对两种语法结构,即:expression 和 statement ,什么意思呢? expression 就是 右边的 input + 左边的 表达式,如果比拟懵的话,看如下代码:input => expression;statement 就是 右边的 input + 左边的可反对多语句的 {} 组成,不明确的话,请看如下代码:input => { statements };Lambda 表达式的案例展现手写 lambda 表达式真的是太简略了,你仅仅须要移除原来 匿名办法 模式下的 delegate 和 入参类型, 先来看一下 匿名办法 怎么写。 ...

January 22, 2021 · 2 min · jiezi

关于.net:如何在-ASPNET-Core-5-中重载-Action-方法

ASP.NET Core 5 是一个开源的用于构建现代化web程序的开发框架,因为 ASP.NET Core 5 是基于 .NET Core 运行时,有了它,你能够将 web程序 运行在 Windows,Linux 和 Mac 上,值得注意的是, ASP.NET Core 5 整合了 Web API 和 MVC。 接下来回到本篇主题,何为办法重载? 就是让多个不同签名的办法共享一个办法名的技术,这种技术在 C# 中被宽泛应用,但用在 ASP.NET 5 中就不是那么直观了,这篇文章咱们就来探讨如何重载 Action。 action 是什么Action 就是 Controller 下标记为 public 并且 没有被 [NonAction] 个性标记的办法,如下代码: public class HomeController : Controller { public IActionResult Index() { return View(); } }尽管看起来和一般办法一样,然而这些办法必须恪守上面这些束缚。 Action 办法必须是 publicAction 不能是 staticAction 办法不能像 一般办法 一样能够参数重载当你创立好 MVC 我的项目,默认的 Index Action 也会主动创立,在 Startup.Configure 下的路由配置中也默认配置了此Action,如下代码所示: ...

January 22, 2021 · 2 min · jiezi

关于.net:如何使用-C-中的-Lazy

提早初始化 是一种将对象的创立提早到第一次须要用时的技术,换句话说,对象的初始化是产生在真正须要的时候才执行,值得注意的是,术语 提早初始化 和 提早实例化 的意思是雷同的——能够调换应用,通过应用 提早初始化 技术,能够防止应用程序不必要的计算和内存耗费,这篇文章咱们将会探讨如何在 C# 中应用 提早初始化。 有些敌人听完这些可能会懵逼,接下来用一个简略的例子来理解下 提早加载 的场景,思考上面两个类, Customer 和 Order, Customer 类蕴含了一个 Orders 属性,一个人必定会有很多的订单,也就意味着它可能蕴含了很多的数据,甚至还须要连贯数据库去获取 Orders 记录,在这种场景下,没必要给 customer 汇合中的所有人都带上残缺的 orders,这个初始化开销是微小的,优化点就是不加载 Orders,直到某些 customer 真的须要 Orders 时才按需灌入。 应用 Lazy<T>你能够本人写一段逻辑来实现 提早初始化,在 .Net Framework 4.0 之后就没必要了, 因为在 System 命名空间下曾经提供了 Lazy<T>,而且还是 线程平安 的,能够应用这个类来提早 资源密集型 的对象按需创立。 当应用 Lazy<T> 的时候,这里的 T 就是你要提早的汇合,那如何做到按需加载呢?调用 Lazy<T>.Value 即可,上面的代码片段展现了如何应用 Lazy<T>。 Lazy<IEnumerable<Order>> orders = new Lazy<IEnumerable<Order>>();IEnumerable<Order> result = lazyOrders.Value;当初,思考上面的两个类: Author 和 Blog,一个作者能够写很多文章,所以这两个类之间是 一对多 的关系,上面的代码片段展现了这种关系。 public class Author { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Address { get; set; } public List<Blog> Blogs { get; set; } } public class Blog { public int Id { get; set; } public string Title { get; set; } public DateTime PublicationDate { get; set; } }值得注意的是,关系型数据库中的 一对多 关系映射到对象模型就是 Author 类中减少一个 List Blogs 属性,应用这个属性,Author 就能够维持一个或者多个 Blog 实例对象,对吧。 ...

January 21, 2021 · 2 min · jiezi

关于.net:如何使用-C-中的-FileSystemWatcher

开局一张图,在 System.IO 下的 FileSystemWatcher 罕用于监督文件系统的变更,当文件系统中的文件或者文件夹被批改会主动触发相应的回调事件。 为了可能理解 FileSystemWatcher 是怎么运作的,你能够指定一个被监督的文件夹,当被监督的文件夹批改后,大略会触发如下的一些事件。 Changed: 当文件或者文件夹曾经实现批改时触发此事件Created:当文件或者文件夹曾经胜利创立触发此事件Deleted:当文件或者文件夹曾经胜利删除触发此事件Error:当变更的过程中产生谬误触发此事件。Renamed:当文件或者文件夹曾经胜利被重命名时触发此事件创立一个简略的 file 监督接下来咱们在 Visual Studio 中创立一个 Console 程序,用来理解如何进行文件监督,不过倡议把 Console 部署成 Windows Service,这样不便在零碎中常驻监控,一旦被监督的门路产生变更就会主动发出通知事件。 该说的都说了,接下来一起钻研代码吧。 static void Main(string[] args) { string path = @"D:\IDG"; MonitorDirectory(path); Console.ReadKey(); }上面的代码片段展现了 MonitorDirectory 办法的外部逻辑,这个办法可用于监督指定的文件夹并且当文件夹变更时触发事件,能够看到文件夹门路是通过参数传进去的。 private static void MonitorDirectory(string path) { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(); fileSystemWatcher.Path = path; fileSystemWatcher.Created += FileSystemWatcher_Created; fileSystemWatcher.Renamed += FileSystemWatcher_Renamed; fileSystemWatcher.Deleted += FileSystemWatcher_Deleted; fileSystemWatcher.EnableRaisingEvents = true; }能够着重理解一下下面的 event 是如何被灌入的,而且我还写了一句 fileSystemWatcher.EnableRaisingEvents = true, 这是什么意思呢? 示意以后的门路正式开始被监控,一旦监控的门路呈现变更,FileSystemWatcher 中的指定事件将会被触发。 ...

January 21, 2021 · 2 min · jiezi

关于.net:如何使用-C-中的-Tuple

开局一张图,首先申明的是 Tuple 不是什么陈腐概念,在编程语言 F#,Python 中早就有这个了,Tuple 是一种 有序的,无限不可变的,反对混淆类型的固定个数的 一种数据结构,有些敌人可能就想问了,这里的混淆是什么意思? 其实就是说 Tuple 中的若干元素类型,即能够是同类型,也能够是不同类型。 值得注意的是,Tuple 中的元素是 只读的,而且其元素的程序也是在 Tuple 创立的时候指定好的,不能对其中的元素进行后续批改 也不能批改 Tuple 的大小。 为什么要应用 Tuple上面列举了几种应用 Tuple 的场景: 如果你的办法须要返回多个值 或者 办法须要传递多个值。如果你不想为某些性能专门去定义一个类。如果你有若干个混淆元素,并且想提供对其简略的拜访形式。下面三种状况都是 Tuple 最善于的利用场景,值得用 Tuple 去解决。 有些敌人可能会想到 匿名类,但认真想想, 匿名类 也有其缺点,比如说办法的返回值是不可能指定为匿名类型的,对吧。 当然 Tuple 也是有缺点的,列举如下: 当你拜访 Tuple 中的元素时,你会发现只能应用 Item1, Item2, Item3 这样的模式,很显然这种太不易读了,而且一旦 Tuple 中的元素过多,保护起来也是一种累赘。Tuple 是援用类型不是值类型,意味着它会在 托管堆 上进行内存调配,如果 Tuple 过大并且没有很好的开释,对程序也是一个不小的性能挑战。C# 中应用 Tuple叨叨叨的说了这么多,接下来看看如何应用,在 C# 中提供了一个 Tuple 类,这个类下有一个静态方法 Create 可用来生成 Tuple 实例,顺便提一下,这个 Create 办法提供了 8 个重载办法,上面展现了这些办法签名清单。 public static class Tuple{ public static Tuple<T1> Create<T1>(T1 item1) { return new Tuple<T1>(item1); } public static Tuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2) { return new Tuple<T1, T2>(item1, item2); } public static Tuple<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3) { return new Tuple<T1, T2, T3>(item1, item2, item3); } public static Tuple<T1, T2, T3, T4> Create<T1, T2, T3, T4>(T1 item1, T2 item2, T3 item3, T4 item4) { return new Tuple<T1, T2, T3, T4>(item1, item2, item3, item4); } public static Tuple<T1, T2, T3, T4, T5> Create<T1, T2, T3, T4, T5>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) { return new Tuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5); } public static Tuple<T1, T2, T3, T4, T5, T6> Create<T1, T2, T3, T4, T5, T6>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6) { return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6); } public static Tuple<T1, T2, T3, T4, T5, T6, T7> Create<T1, T2, T3, T4, T5, T6, T7>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7) { return new Tuple<T1, T2, T3, T4, T5, T6, T7>(item1, item2, item3, item4, item5, item6, item7); } public static Tuple<T1, T2, T3, T4, T5, T6, T7, Tuple<T8>> Create<T1, T2, T3, T4, T5, T6, T7, T8>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8) { return new Tuple<T1, T2, T3, T4, T5, T6, T7, Tuple<T8>>(item1, item2, item3, item4, item5, item6, item7, new Tuple<T8>(item8)); }}接下来看看如何创立和初始化 Tuple。 ...

January 21, 2021 · 2 min · jiezi

关于.net:如何在-ASPNET-Core-中使用-Session

ASP.NET Core 是一个跨平台,开源的,轻量级,高性能 并且 高度模块化的web框架,Session 能够实现用户信息存储从而能够在同一个客户端的屡次申请之间实现用户追踪,在 ASP.Net Core 中能够应用 Microsoft.AspNetCore.Session 中间件来启用 Session 机制。 中间件的价值在于能够在 request -> response 的过程中做一些定制化的操作,比如说:监督数据,切换路由,批改流转过程中的音讯体,通常来说:中间件是以链式的形式灌入到 ASP.Net Core 的 pipeline 管道中,这篇文章次要探讨如何应用 Session 中间件。 装置 Session 中间件要想应用 session 中间件,你能够应用 Visual Studio 2019 中的 NuGet package manager 可视化界面进行装置,或者通过 NuGet package manager console 命令行输出如下命令: Install-Package Microsoft.AspNetCore.Session配置 session 中间件当初 Microsoft.AspNetCore.Session 曾经胜利装置到你的我的项目中了,接下来能够将它增加到 ASP.Net Core pipeline 中,请留神:为了可能启动 Session,你必须要应用一个 实现了 IDistributedCache 接口的 cache store 来作为 session 的底层存储,而后你还要在 ConfigureServices 办法下调用 AddSession 办法将其塞入 IOC 容器,最初在 Startup.Configure 办法下应用 UseSession 将其塞入到 request -> response 申请管道中,具体代码如下: ...

January 21, 2021 · 1 min · jiezi

关于.net:在-ASPNET-Core-中使用多种方式给-Action-传参

ASP.NET Core 是一个跨平台,开源的,轻量级,高性能 并且 高度模块化的web框架。 在 ASP.NET Core MVC 中有很多种形式能够给 Action 办法传递参数,比如说:url形式,querystring形式,request header,request body,form 等等。本篇就和大家一起探讨下如何应用这些形式,并且用代码去一一验证。 创立 AuthorRepository 类在这个例子中我会应用一个 Repository 类,而后在 Controller 下的 Action 办法调用这个 Repository 来实现根本的 CURD 操作,首先咱们申明一个 Author 类,代码如下: public class Author { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } }AuthorRepository 类提供了如下三个办法。 GetAuthor 用于从泛型汇合中获取 Author 实体Save 用于将 Author 保留到底层的 泛型汇合中GetAuthors 用于分页获取 泛型汇合中的数据具体代码如下: public class AuthorRepository { List<Author> authors = new List<Author>() { new Author { Id = 1, FirstName = "Joydip", LastName = "Kanjilal" }, new Author { Id = 2, FirstName = "Steve", LastName = "Smith" } }; public Author GetAuthor(int id) { return authors.FirstOrDefault(a => a.Id == id); } public List<Author> GetAuthors(int pageNumber = 1) { int pageSize = 10; int skip = pageSize * (pageNumber - 1); if (authors.Count < pageSize) pageSize = authors.Count; return authors .Skip(skip) .Take(pageSize).ToList(); } public bool Save(Author author) { var result = authors.Where(a => a.Id == author.Id); if (result != null) { if (result.Count() == 0) { authors.Add(author); return true; } } return false; } }通过 url 形式最简略粗犷的给 Action 传参就是通过 url 形式,上面的代码片段展现了如何通过 url 进行传参。 ...

January 21, 2021 · 2 min · jiezi

关于.net:如何使用-RestSharp-调用-WebAPI-接口

REST 是由 Representational State Transfer 这三个单词前缀合成,这种架构格调在前几年特地风行,Restful API 的行为规范能够参考: https://docs.microsoft.com/en... ,通常 RESTful API 返回的格局为常见的 PlianText, JSON , XML 格局。 RestSharp 是一个开源的 Http 客户端类库,十分不便和 RESTful 格局的 Service 进行交互,????????的是,这个类库封装了 request 申请过程中简单的细节,而且 RestSharp 反对同步和异步两种申请模式。 这篇文章将会探讨如何应用 RestSharp 去申请 Asp.NET Core 服务。 实现 DefaultController关上 DefaultController.cs 文件并用上面的代码进行替换。 using Microsoft.AspNetCore.Mvc;using System.Collections.Generic;namespace RESTAPIDemo.Controllers{ [Route("api/[controller]")] [ApiController] public class DefaultController : ControllerBase { private readonly Dictionary<int, string> authors = new Dictionary<int, string>(); public DefaultController() { authors.Add(1, "Joydip Kanjilal"); authors.Add(2, "Steve Smith"); authors.Add(3, "Michele Smith"); } [HttpGet] public List<string> Get() { List<string> lstAuthors = new List<string>(); foreach (KeyValuePair<int,string> keyValuePair in authors) lstAuthors.Add(keyValuePair.Value); return lstAuthors; } [HttpGet("{id}", Name = "Get")] public string Get(int id) { return authors[id]; } [HttpPost] public void Post([FromBody] string value) { authors.Add(4, value); } [HttpPut("{id}")] public void Put(int id, [FromBody] string value) { authors[id] = value; } [HttpDelete("{id}")] public void Delete(int id) { authors.Remove(id); } }}参考下面的 DefaultController 类,能够发现 Action 办法的名字对应着 Http 动词的 GET,POST,PUT 和 DELETE,为了简略起见,我应用了 Dictionary 来存取数据,你能够用 浏览器 或者 Postman 或者 Fiddler 进行测试,请留神,这里为了不便,我在 Post 办法中应用了硬编码,理论场景中你能够用本人的形式生成惟一ID。 ...

January 18, 2021 · 2 min · jiezi

关于.net:如何将日志记录到-Windows事件日志-中

每当呈现一些未捕捉异样时,操作系统都会将异样信息写入到 Windows 事件日志 中,能够通过 Windows 事件查看器 查看,如下图: 这篇文章将会探讨如何应用编程的形式将日志记录到 Windows 事件日志 中。 装置 EventLog要想在 .NET Core 中记录数据到 Windows 事件日志中,能够用 Nuget 装置一下 Microsoft.Extensions.Logging.EventLog 包,用 Visual Studio 中的 NuGet Package Manager 可视化面板 或者 应用 NuGet Package Manager Console 命令行界面都能够,输出命令如下: Install-Package Microsoft.Extensions.Logging.EventLog通过 EventLog 记录日志要想将日志写入 Windows 事件日志中,能够应用如下代码: EventLog eventLog = new EventLog();eventLog.Source = "MyEventLogTarget";eventLog.WriteEntry("This is a test message.", EventLogEntryType.Information); 通过 EventLog 清空日志为了可能实现清空所有 windows 日志,能够应用如下代码: EventLog eventLog = new EventLog();eventLog.Source = "MyEventLogSource";eventLog.Clear();Clear 是清空所有的 windows 事件日志,那如何革除某一个类别的日志呢? 比如说:MyEventLogTarget,批改代码如下: ...

January 18, 2021 · 2 min · jiezi

关于.net:Calling-a-Partial-View

Calling a Partial View由 糊涂的女人 提交于 2020-12-26 16:45:18 问题I've got a View rendering two dropdownlists. The controllers for the dropdownlists work fine. They call methods in a repository class for the DB selections. Below the dropdownlists I'm trying to render a table of data in a partial view, in response to the dropdownlist selections. The dropdowns in the View use a single model: `@model BudgetDemo.Models.BudgetsActualsViewModel` The Partial View displaying the table data uses IEnumerable: ...

December 26, 2020 · 3 min · jiezi

关于.net:支持NET-5最新的设计器功能这款UI控件库已经很强大了

点击获取工具>>Microsoft上周正式公布了.NET 5,小编非常高兴地通知大家,DevExpress WPF控件v20.2曾经正式反对.NET 5了! 装置了WPF控件后,它们将在.NET 5利用的工具箱中可见(即便该利用自身未援用DevExpress程序包)。 全新的WPF XAML DesignerVisual Studio 2019 Preview蕴含一个新的WPF XAML Designer,Microsoft持续改良该设计器,并打算将其用于.NET Core和.NET Framework我的项目,心愿微软可能在短时间内兑现这一承诺。 默认状况下,.NET Core应用程序应用新的WPF XAML Designer,对于.NET Framework应用程序,请在Visual Studio中启用以下选项:Tools > Options > Preview Features > New WPF XAML Designer for .NET Framework (requires restart) 全新的WPF XAML Designer 扩大抉择非可视化元素(数据网格列,工具栏和功能区我的项目)(v20.1) 您能够抉择非可视元素(例如数据网格的列和工具栏/功能区项),并依据须要疾速导航至其标记。 在设计时切换选项卡(v20.2) 您能够在控件中切换选项卡,例如WPF Docking组件、LayoutControl和Ribbon组件。 在Dock和Layout控件(v20.2)中应用Adorners 要理论应用此性能,请关上WPF Dock Windows - Layout Panels demo,请留神,您能够依据须要应用adorners增加新的组和面板。 倡议操作的状态更新 Visual Studio全新的WPF XAML Designer蕴含Suggested Actions,目前仅在Preview builds版本中可用,Suggested Actions相似于DevExpress智能标记,能够轻松拜访与所选控件关联的通用属性。 ...

November 26, 2020 · 1 min · jiezi

关于.net:来不及解释了快上车LRNET开发平台助力企业信息互联

近些年,互联网迷信迈入了高速发展期,各类先进高效的网络技术层出不穷,已逐步成为促成社会运行的重要一环。网络技术的提高,岂但扭转着一般公众的生存,甚至推动了各畛域企业的运行形式,为了跟上时代的步调,各行各业都在以本人的形式进行信息化改革。 不过让人感觉不堪设想的是,长期与计算机和网络设备打交道的软件业却未能站上互联网的风口。毕竟,互联网以大众为本,盈利靠流量与用户群;而软件业专一于产品,一个我的项目即是一个产品,产品之间互相独立,相干资源无奈复制通用。 但有种观点认为,软件行业始终都是这样,以前这么多年倒退下来,如同也没有什么问题。然而,时代变了!现在市场规定正在信息化的浪潮下悄悄产生着扭转,传统运作模式当初曾经开始逐步暴露出问题: 首先,尽管市场够大,但销售利润低,软件业难以通过网络流量获取收益,只能在红海里打价格战来拼市场,行业利润广泛大不如前。 其次,开发效率低,老本高,毕竟这是传统软件开发模式的一大劣势,无奈跟上互联网的快时代节奏。 再次、传统软件产品更新降级简单且低效,跟不上业务需要的变动,在原始的红海市场中将无奈令客户称心。 综上,与互联网产业的飞速发展相比,传统软件业确实是落后了,如果不奋起直追,疾速转型,或者在不远的未来就将被用户摈弃,被时代淘汰。 力软(详情learun.cn)率先迈出了转型的第一步,凭借10余年软件开发教训自主研发了LR低代码开发平台,实现软件的“麻利开发”和“疾速迭代”,帮忙传统软件商在互联网市场中胜利转型,开拓新兴蓝海市场。 想要胜利转型上岸,必须正视暴露出了的问题,逐渐解决。 首要任务便是要提高效率,降低成本。LR平台采纳先进的‘可视化组件’设计,积攒大量成熟高效的利用组件。应用LR平台仅需大量编程即可实现绝大多数的软件开发,开发人员所见即所得,整体开发效率数倍于传统计划。 疾速开发平台之所以高效,是因为这类平台通常采纳低代码开发计划,同时对技术人员的要求也升高了很多。因而,可升高企业对开发团队的配置,仅需对大量人员进行简略培训即可岗操作,相比于传统开发计划,人力老本可忽略不计。 其次要关照到产品的独特性,直面客户需要。LR平台的自定义模板性能,可能随需个性化定制,仅需鼠标操作即可实现个性化性能。且LR平台全程可视化,开发者可依据需要变动随时在线批改,并通过可视化界面实时预览成绩。从客户的角度登程,开发出真正令客户称心的利用零碎。 最初,适应市场潮流,对立开发标准。LR平台履行模块化治理,并遵循对立的开发标准,可及时反馈BUG,帮忙开发人员疾速批改软件系统,提开发准确性,升高保护老本。 对于当代企业来说,可悲的并非没有实力,而是在拼命进取的路上走错方向。其后果就是悄无声息地丢失了竞争力,直至被淘汰出局。 扭转,从观点开始,LR整合平台的优质个性,无论是传统软件企业,还是亟需实现信息化革新的各行各业,或者仅仅是一名开发人员,都能够一下简略包揽下整个我的项目的开发,带来了妙不可言的便捷与变革。

November 18, 2020 · 1 min · jiezi

关于.net:开源-Net-ORM-FreeSql-1101-稳步向前

写在结尾FreeSql 是 .NET 开源生态下的 ORM 轮子,转瞬快两年了,说真的开源不容易(只有经验过才明确)。明天带点干货和湿货给大家,先说下湿货。 意识我的人,晓得 CSRedisCore 是我写的另外一个开源组件,这个我的项目是 2016 年从 ctstone/csredis 我的项目 clone 到本人工作的我的项目中,批改源码通过一年多生产考验,于 2017 年公布开源 https://github.com/2881099/cs... ctstone/csredis 我的项目于 2014 年进行了更新,到我手里欠缺的性能如下: 连接池哨兵高可用集群redis 2.8 以上的版本命令补充,包含 Geo、Stream通信协定 bug 修复临时想到的只有这些,之后可能再补充。FreeSql 文章题目为什么要来说 csredis? 这两年的工夫里 95% 精力都用在了 FreeSql 下面, 5400+ 单元测试、反对十几种数据库适配,渣男辜负了 csredis 这个我的项目。最近一个多月开源圈子的奇葩事接踵而至,竟然有人跑去 ctstone/csredis 原作者的 issues 告我的状,这个告状的人还是 NOPI 原作者,因为当初他本人不保护 NPOI .NET Core 版本了,社区有坏蛋把 .NET Core 版本测试做好了开源(dotnetcore/NPOI),告状的人很真心厉害,曾经胜利把 nuget.org/dotnetcore.npoi 整下架了。 他并没有失去满足,之后开始针对整个 NCC 社区成员,包含我。 他去了 sqlsugar issues 发表,说要找出 FreeSql 剽窃 sqlsugar 的证据他又去 fur issues 发表声援,说我黑他他还去 csredis 原作者 issues 公布内容,希图告我的状并不是人人都像你一样,强制要求上游我的项目“归档”、“制裁”,试问 mysql 能够要求 mariadb 归档?针对 NCC 组织还是针对我自己?CSRedisCore 并不在 NCC 开源组织下!!! ...

October 23, 2020 · 7 min · jiezi

关于.net:学习后端第一天写个接口根据人员id获取数据库里的岗位列表

背景:复宏汉霖我的项目尝试本人写接口.依据人员id获取数据库里的岗位列表. 第一步先增加控制器Controllers(1):鼠标移到WebApiControllers文件夹下,右键抉择增加控制器(2):抉择 Web API 2 控制器 -空 (每家公司用的可能不一样)(3):定义你的控制器名字(4):新建好的控制器默认关上的样子 第二步增加model实体类(1):新增model实体类(2):定义model名字 第三步新建services逻辑层(1):新增services逻辑层(2):定义services名字 第四步 在控制器外面定义好接口地址返回值TestStaffController.cs代码内容: using System;using System.Collections.Generic;using System.Linq;using System.Net;using System.Net.Http;using System.Web.Http;using WebApi.Infrastructure.Filters;using Business.Models;using Business.Services;namespace WebApi.Controllers{ /// <summary> /// 测试获取岗位列表 /// </summary> [Token] [RoutePrefix("api/TestStaff")] public class TestStaffController : ApiController { /// <summary> /// 依据人员id获取岗位列表 /// </summary> /// <param name="OwnerID"></param> /// <returns></returns> [HttpGet] [Route("GetTestStaffList/{OwnerID}")] public IList<staffItem> GetTestStaffList(string OwnerID) { var business = new TestStaff(); return business.GetTestStaffList(OwnerID); } }}解释: using : 援用 (和前端的import用法一样)namespace : 文件夹所在位置/// : 正文[Token] :[RoutePrefix("api/TestStaff")] : 接口前缀[HttpGet] : 定义申请类型[Route("GetTestStaffList/{OwnerID}")] : 申请地址(接口后缀)IList<staffItem> :返回值类型list类型GetTestStaffList :办法名(string OwnerID) :传参类型及参数名var business = new TestStaff() 把services对象实例化 business.GetTestStaffList(OwnerID) 调用services层的办法第五步 在实体类model外面定义所需字段TestStaff.cs代码内容: ...

October 16, 2020 · 2 min · jiezi

关于.net:2020年-NET-ORM-完整比较助力选择

.NET ORM 前言为什么要写这篇文章? 心愿针对 SEO 优化搜索引擎,让更多中国人晓得并且应用。目前百度搜寻 .NET ORM 全是 sqlsugar,我集体是无语的,每每一个人进群第一件事就是拿来比拟,每天要反复答复、反复解答、压服他们。想压服标签是名气大、使用者多的同类型 .NET ORM 十分艰难,最多只能让他们勉强承受。FreeSql 不愿做本人发光的金子,心愿在 2020年 写下这篇残缺一点的 .NET ORM 比拟,为筹备应用 FreeSql 的敌人解惑,能排上百度搜索引擎当然再好不过了。 肯请正在应用 CSRedisCore、FreeSql 的敌人,动一动手指转发本文,并加上原文链接指向本文,谢谢! QQ群:4336577(已满)、8578575(在线)、52508226(在线) 原创文章欢送转载,2020年中文版 .NET ORM 残缺性能比拟 MarkDown:https://files.cnblogs.com/fil... 文章连贯:https://www.cnblogs.com/kelly... .NET ORM 根底信息比拟性能项FreeSqlEFCoreSqlSugar出世工夫2018年12月2015年(约)2014年(约)开源协定MITApache-2.0Apache-2.0所属机构dotnetcore(NCC)dotnetsunkaixuan(集体)单元测试数量5500+很多无github star2.1k+9.5k+3.1k+github issues沉闷沉闷不沉闷反对平台.NET4.0+、.NETCore.NETCore.NET4.5+、.NETCore反对数据库很多,并且行为统一很多SqlServer/MySql/Sqlite/Oracle生命周期SingletonScopedScoped应用形式IFreeSql、RepositoryDbContextSugarClientFreeSql .NET ORM 反对 MySql/SqlServer/PostgreSQL/Oracle/Sqlite/Firebird/达梦/人大金仓/神舟通用/Access。 .NET ORM 各有自已看家本领,本文次要按 FreeSql 提供的性能进行列举比拟,如有触犯请见谅,也欢送向 FreeSql 提出性能倡议。 每个性能实现的深度档次不一样(比方 EFCore 反对 SqlServer 2012,FreeSql 反对 SqlServer 2005),很难彻底比拟,提醒: 本文比拟的性能 FreeSql 每种数据库根本都有提供,不像 EFCore 偏差 SqlServer本文只比拟官网提供的性能(不蕴含第三方扩大) .NET ORM 整体性能比拟性能项FreeSqlEFCoreSqlSugar.NET ORM CodeFirst 依据实体类型,创立表构造✔✔✔.NET ORM CodeFirst 依据实体类型,比照表构造✔✔-.NET ORM CodeFirst 依据实体类型正文,迁徙表构造备注✔--.NET ORM CodeFirst FluentApi✔✔-.NET ORM CodeFirst FluentApi 语法兼容 EFCore✔✔-.NET ORM CodeFirst 实体个性兼容 EFCore✔✔-.NET ORM CodeFirst 自定义实体个性(Aop)✔-✔.NET ORM CodeFirst 类型转换映射(MapType)✔✔-.NET ORM DbFirst 依据数据库,生成实体类✔✔✔.NET ORM 导航属性(OneToOne)✔✔-.NET ORM 导航属性(ManyToOne)✔✔-.NET ORM 导航属性(OneToMany)✔✔-.NET ORM 导航属性(ManyToMany)✔--.NET ORM 导航属性(Parent) 父子关系的实体类✔--.NET ORM 导航属性延时加载、贪心加载、级联保留✔✔-.NET ORM 自定义表达式树解析✔--.NET ORM 全局过滤器✔✔-.NET ORM 事务✔✔✔.NET ORM 读写拆散✔-✔.NET ORM 分表分库✔--.NET ORM 仓储 Repository✔--.NET ORM 工作单元 UnitOfWork✔--.NET ORM 工作单元管理器 UnitOfWorkManager✔--.NET ORM DbContext 状态治理✔✔-.NET ORM CRUD 性能比拟性能项FreeSqlEFCoreSqlSugar.NET ORM CRUD 时,映射动静表名✔-✔.NET ORM CRUD 时,应用参数化 SQL 执行✔✔✔.NET ORM CRUD 时,不应用参数化 SQL 执行(NoneParameter)✔--.NET ORM CRUD 时,获取对应的 SQL(ToSql)✔-✔.NET ORM CRUD 时,对立审计实体属性值(Aop.AuditValue)✔-- .NET ORM 插入(单条)✔✔✔.NET ORM 插入时,疏忽/指定列✔-✔.NET ORM 插入时,返回影响的行数✔-✔.NET ORM 插入时,返回插入后的自增值✔✔✔.NET ORM 插入时,返回插入后的记录✔--.NET ORM 插入时,Insert Ignore Into✔--.NET ORM 插入时,On Duplicate Key Update✔--.NET ORM 插入时,On Conflict Do Update✔--.NET ORM 批量插入 性能测试后果参考文档✔-✔.NET ORM 批量插入时,主动分批 参考文档✔--.NET ORM 批量插入时,应用BulkCopy✔-- .NET ORM 更新(单条)✔✔✔.NET ORM 更新时,动静条件(WhereDynamic)✔-✔.NET ORM 更新时,依据实体对象更新✔-✔.NET ORM 更新时,依据状态治理只更新有变动的属性✔✔-.NET ORM 更新时,疏忽/指定列✔-✔.NET ORM 更新时,原子性 set num=num+1✔-✔.NET ORM 更新时,指定条件✔-✔.NET ORM 更新时,主动附加全局过滤器条件✔--.NET ORM 更新时,不须要先查问✔-✔.NET ORM 更新时,应用乐观行锁✔✔-.NET ORM 更新时,应用乐观锁✔--.NET ORM 更新时,返回影响的行数✔-✔.NET ORM 更新时,返回插入后的记录✔--.NET ORM 批量更新✔-- .NET ORM 删除(单条)✔✔✔.NET ORM 删除时,动静条件(WhereDynamic)✔-✔.NET ORM 删除时,指定条件✔-✔.NET ORM 删除时,主动附加全局过滤器条件✔--.NET ORM 删除时,不须要先查问✔-✔.NET ORM 删除时,返回影响的行数✔-✔.NET ORM 删除时,返回插入后的记录✔--.NET ORM 级联保留✔✔-.NET ORM 增加或更新✔-✔.NET ORM 增加或更新,主动适配 merge into 参考文档✔--.NET ORM 批量编辑保留 参考文档✔✔- .NET ORM 查问(单条)✔✔✔.NET ORM 查问时,分页✔✔✔.NET ORM 查问时,分页反对 SqlServer2008✔-✔.NET ORM 查问时,动静条件(WhereDynamic)✔-✔.NET ORM 查问时,动静过滤条件(WhereDynamicFilter) 参考文档✔-✔.NET ORM 查问时,主动附加全局过滤器条件✔--.NET ORM 查问时,多表条件流传(WhereCascade)✔--.NET ORM 查问时,在 lambda 中应用导航属性✔✔-.NET ORM 查问时,用 Dto 映射只须要查问的字段✔--.NET ORM 查问时,传 Sql 作二次查问(WithSql)✔-✔.NET ORM 查问时,子查问(Exists)✔-✔.NET ORM 查问时,子查问(In)✔-✔.NET ORM 查问时,子查问拼接后果(string.Join) 参考文档✔--.NET ORM 查问时,应用分组聚合(GroupBy/Having)✔✔✔.NET ORM 查问时,应用 Linq To Sql 语法✔✔-.NET ORM 查问时,针对树形构造表 父子关系的实体类✔--.NET ORM 总结.NET ORM FreeSql 功能强大,扩大不便,从 issues 和 qq群 能够看得出社区更新极积有问必应; ...

September 14, 2020 · 2 min · jiezi

aspnet-core-系列15-自定义Identity

0. 前言在之前的文章中简略介绍了一下asp.net core中的Identity,这篇文章将持续针对Identity进行进一步的开展。 1. 给Identity增加额定的信息在《【asp.net core 系列】13 Identity 身份验证入门》一文中,咱们大略理解了如何应用Identity,以及如何保留一些信息以便后续的验证。这里咱们将深刻讨论一下如何给Identity增加更多的信息。 咱们晓得在给Identity增加数据的时候,须要增加一个Claim对象。咱们先回顾一下Claim的信息,Claim的属性大多只提供了公开的get拜访器,所以这个类的重点在于构造方法: public class Claim{ // 根底的 public Claim(string type, string value); public Claim(string type, string value, string valueType); public Claim(string type, string value, string valueType, string issuer); public Claim(string type, string value, string valueType, string issuer, string originalIssuer); // public Claim(BinaryReader reader); public Claim(BinaryReader reader, ClaimsIdentity subject);}暂且看一下几个应用字符类型的结构函数参数: type Claim的类型,反对自定义,但asp.net core 提供了一个根底的类型定义:public static class ClaimTypes{ // 暗藏其余属性 public const string Name = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"; public const string Role = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role";} 这个类里定义了大多数状况下会用到的Claims的类型。 ...

July 9, 2020 · 3 min · jiezi

HandyControl重写原生样式包含-70余款自定义控件的WPF控件库

Gitee 此前为大家介绍过一款优质的 WPF 控件库,受到了很多 C# 开发者的欢迎,由此可见Windows 开发者的基数仍然很高。今天为大家推荐的就是另一款在 Gitee 上很受欢迎的 WPF 控件库。 项目名称:HandyControl 项目作者:HandyOrg 开源许可协议:MIT 项目地址:https://gitee.com/handyorg/HandyControl 项目简介HandyControl 是一套 WPF 控件库,它几乎重写了所有原生样式,同时包含 70 余款自定义控件(正逐步增加)。 项目示例(部分展示) 项目结构介绍整体结构 从Gitee 上克隆好源码后,进入src文件夹,该文件夹结构如下: 这里一共有4个解决方案sln文件。 Net_GE45的意思是.Net版本大于等于4.5 Shared文件夹用于存放共享项目的代码 图中五个文件夹内部各包含两个子文件夹,例如在Shared中还包含两个子文件夹: 它们分别存放控件源码和控件示例源码。 源码结构 我们以HandyControl.sln为示例进行说明,使用VS2019打开该解决方案: 如果要启动示例,查看控件效果,请将HandyControlDemo_[指定的项目类型]作为启动项。 如图,已将HandyControlDemo_Net_GE45作为启动项。 大部分公共的源码都在Shared文件夹中,部分需要为特定项目类型定制的代码则被提出来放到各自的文件夹中。 HandyControl源码(主要在HandyControl_Shared中)主要包含7个文件夹,对它们的描述如下表所示: 编译源码打开HandyControl.sln,在解决方案配置下拉框中选择指定的环境进行编译: 请注意编译前确认你的开发环境是否符合要求,更详细的项目介绍可以点击后面的链接前往项目主页查看:https://gitee.com/handyorg/HandyControl

June 28, 2020 · 1 min · jiezi

开源-Net-使用-ORM-访问-神舟通用数据库神通

前言天津神舟通用数据技术有限公司(简称“神舟通用公司”),隶属于中国航天科技集团(CASC)。是国内从事数据库、大数据解决方案和数据挖掘分析产品研发的专业公司。公司获得了国家核高基科技重大专项重点支持,是核高基专项的牵头承担单位。自1993年在航天科技集团开展数据库研发以来,神通数据库已历经27年的发展历程。公司核心产品主要包括神通关系型数据库、神通KStore海量数据管理系统、神通商业智能套件等系列产品研发和市场销售。基于产品组合,可形成支持交易处理、MPP数据库集群、数据分析与处理等解决方案,可满足多种应用场景需求。产品通过了国家保密局涉密信息系统、公安部等保四级、军B +级等安全评测和认证。 随着华为、中兴事务,国产数据库市场相信是未来是趋势走向,纵观 .net core 整个圈子对国产神舟通用数据库(神通)的支持几乎为 0,今天我们使用 FreeSql ORM 来体验国产神舟通用数据库(神通)。 整体来讲,神舟通用数据库(神通)对 Oracle 语法有着 90% 的兼容性,但还有一些细节需要注意,FreeSql 对此做了优化进行了完美支持。 1、安装环境数据库服务器:ShenTong7.0.8 下载地址:http://www.shentongdata.com/i....NET版本:.net core 3.1 下载地址:https://dotnet.microsoft.com/...开发机器 :windows 10 2、创建项目我们以 console 类型项目试验 插入、删除、更新、查询 等功能,创建控制台项目,使用命令: dotnet new console dotnet add package FreeSql.Provider.ShenTongdotnet add package FreeSql.Repository --version 1.6.0 3、创建实体模型using System;using FreeSql.DataAnnotations;public class User{ [Column(IsIdentity = true)] public long Id { get; set; } public string UserName { get; set; } public string PassWord { get; set; } public DateTime CreateTime { get; set; }}4、初始化 ORMstatic IFreeSql fsql = new FreeSql.FreeSqlBuilder() .UseConnectionString(FreeSql.DataType.ShenTong, "HOST=192.168.164.10;PORT=2003;DATABASE=OSRDB;USERNAME=SYSDBA;PASSWORD=szoscar55;MAXPOOLSIZE=2") .UseMonitorCommand(cmd => Trace.WriteLine($"线程:{cmd.CommandText}\r\n")) .UseAutoSyncStructure(true) //自动创建、迁移实体表结构 .UseNameConvert(NameConvertType.ToUpper) .Build();5、插入数据var repo = fsql.GetRepository<User>();var user = new User { UserName = "shentong1", PassWord = "123" };repo.Insert(user); ...

June 28, 2020 · 1 min · jiezi

aspnet-core-系列14-net-core-中的IOC

0.前言通过前面几篇,我们了解到了如何实现项目的基本架构:数据源、路由设置、加密以及身份验证。那么在实现的时候,我们还会遇到这样的一个问题:当我们业务类和数据源越来越多的时候,我们无法通过普通的构造对象的方法为每个实例进行赋值。同时,传统意义上的赋值遇到底层切换或者其他修改的时候,就需要修改大量的代码,对改变不友好。为了改变这种现状,我们基于面向接口编程,然后使用一些DI功能和IOC框架。 1. IOC和DI先来给大家解释几个概念,IOC全称Inversion of Control,翻译过来就是控制反转,是面向对象编程的一种设计原则,用来降低代码之间的耦合度。所谓的控制反转简单来讲就是将类中属性或者其他参数的初始化交给其他方处理,而不是直接使用构造函数。 public class Demo1{}public class Demo2{ public Demo1 demo;}对于以上简单示例代码中,在Demo2类中持有了一个Demo1的实例。如果按照之前的情况来讲,我们会通过以下方法为demo赋值: // 方法一public Demo1 demo = new Demo1();// 方法二public Demo2(){ demo = new Demo1();}这时候,如果Demo1变成下面的样子: public class Demo1{ public Demo1(Demo3 demo3) { // 隐藏 }}public class Demo3{}那么,如果Demo2 没有持有一个Demo3的实例对象,这时候创建Demo1的时候就需要额外构造一个Demo3。如果Demo3需要持有另外一个类的对象,那么Demo2中就需要多创建一个对象。最后就会发现这样就陷入了一个构造“地狱”(我发明的词,指这种为了一个对象却得构造一大堆其他类型的对象)。 实际上,对于Demo2并不关心Demo1的实例对象是如何获取的,甚至都不关心它是不是Demo1的子类或者接口实现类。我在示例中使用了类,但这里可以同步替换成Interface,替换之后,Demo2在调用Demo1的时候,还需要知道Demo1有实现类,以及实现类的信息。 为了解决这个问题,一些高明的程序员们提出了将对象的创建这一过程交给第三方去操作,而不是调用类来创建。于是乎,上述代码就变成了: public class Demo2{ public Demo1 Demo {get;set;} public Demo2(Demo1 demo) { Demo = demo; }}似乎并没有什么变化?对于Demo2来说,Demo2从此不再负责Demo1的创建,这个步骤交由Demo2的调用方去创建,Demo2从此从负责维护Demo1这个对象的大麻烦中解脱了。 但实际上构造地狱的问题还是没有解决,只不过是通过IOC的设计将这一步后移了。这时候,那些大神们想了想,不如开发一个框架这些实体对象吧。所以就出现了很多IOC框架:AutoFac、Sping.net、Unity等。 说到IOC就不得不提一下DI(Dependency Injection)依赖注入。所谓的依赖注入就是属性对应实例通过构造函数或者使用属性由第三方进行赋值。也就是最后Demo2的示例代码中的写法。 早期IOC和DI是指一种技术,后来开始确定这是不同的描述。IOC描述的是一种设计模式,而DI是一种行为。 2. 使用asp.net core的默认IOC在之前的ASP.NET 框架中,微软并没有提供默认的IOC支持。在最新的asp.net core中微软提供了一套IOC支持,该支持在命名空间: Microsoft.Extensions.DependencyInjection里,在代码中引用即可。 ...

June 28, 2020 · 2 min · jiezi

aspnet-core-系列13-Identity-身份验证入门

0. 前言通过前两篇我们实现了如何在Service层如何访问数据,以及如何运用简单的加密算法对数据加密。这一篇我们将探索如何实现asp.net core的身份验证。 1. 身份验证asp.net core的身份验证有 JwtBearer和Cookie两种常见的模式,在这一篇我们将启用Cookie作为身份信息的保存。那么,我们如何启用呢? 在Startup.cs 的ConfigureServices(IServiceCollection services) 方法里添加如下: services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => { Configuration.Bind("CookieSettings",options); });此时可以启动一个权限验证,当用户访问需要验证的页面或接口时,如果没有登录,则会自动跳转到: https://localhost:5001/Account/Login?ReturnUrl=XXXX其中ReturnUrl指向来源页。 1.1 设置验证当我们在Startup类里设置启用了身份验证后,并不是访问所有接口都会被跳转到登录页面。那么如何设置访问的路径需要身份验证呢?asp.net core为我们提供了一个特性类: [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]public class AuthorizeAttribute : Attribute, IAuthorizeData{ public string Policy { get; set; } public string Roles { get; set; } public string AuthenticationSchemes { get; set; }}可以看的出,这个特性类允许设置在类、方法上,可以设置多个,允许子类继承父类的特性。所以可以在控制器上设置[Authorize],当在控制器上设置以后访问控制器里所有的Action都会要求验证身份;也可以单独设置在Action上,表示该Action需要验证身份,控制器里的其他方法不需要验证。 1.2 设置忽略我们在开发过程中,会遇到这样的一组链接或者页面:请求地址同属于一个控制器下,但其中某个地址可以不用用户登录就可以访问。通常我们为了减少重复代码以及复用性等方面的考虑,会直接在控制器上设置身份验证要求,而不是在控制器里所有的Action上添加验证要求。 那么,我们如何放开其中的某个请求,可以允许它不用身份验证。 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]public class AllowAnonymousAttribute : Attribute, IAllowAnonymous{}仔细观察,可以看得出这个特性可以设置在类、方法上,不允许多次设置,允许子类继承父类的特性。 ...

June 24, 2020 · 3 min · jiezi

aspnet-core-系列12-数据加密算法

0. 前言这一篇我们将介绍一下.net core 的加密和解密。在Web应用程序中,用户的密码会使用MD5值作为密码数据存储起来。而在其他的情况下,也会使用加密和解密的功能。 常见的加密算法分为对称加密和非对称加密。所谓的对称加密是指加密密钥和解密密钥是同一个,非对称加密是值加密密钥和解密迷药不同。而我们常应用在保存用户登录密码这个过程中的MD5本质上并不是加密算法,而是一种信息摘要算法。不过MD5尽量保证了每个字符串最后计算出来的值都不一样,所以在密码保存中常用MD5做为保密值。 1. 常见对称加密算法对称加密算法,简单的说就是加密和解密使用相同的密钥进行运算。对于大多数加密算法,解密和加密是一个互逆的运算。对称加密算法的安全性取决于密钥的长度,密钥越长越安全。当然,不建议使用过长的密钥。 那么,我们来看看常见的对称加密算法有哪些吧,以及C#该如何实现。 1.1 DES 和 DESede 算法DES算法和DESede算法(又称三重DES算法) 统称DES系列算法。DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法。而DESede就是针对同一块数据做三次DES加密。这里就不对原理做过多的介绍了,来看看.net core里如何实现DES加/解密吧。 在Utils项目里,创建目录Security: 在Security目录下,创建DESHelper类: namespace Utils.Security{ public class DesHelper { }}加密解密实现: using System;using System.IO;using System.Security.Cryptography;using System.Text;namespace Utils.Security{ public static class DesHelper { static DesHelper() { DesHandler = DES.Create("DES"); DesHandler.Key = Convert.FromBase64String("L1yzjGB2sI4="); DesHandler.IV = Convert.FromBase64String("uEcGI4JSAuY="); } private static DES DesHandler { get; } /// <summary> /// 加密字符 /// </summary> /// <param name="source"></param> /// <returns></returns> public static string Encrypt(string source) { try { using (var memStream = new MemoryStream()) using (var cryptStream = new CryptoStream(memStream, DesHandler.CreateEncryptor(DesHandler.Key, DesHandler.IV), CryptoStreamMode.Write)) { var bytes = Encoding.UTF8.GetBytes(source); cryptStream.Write(bytes, 0, bytes.Length); cryptStream.FlushFinalBlock(); return Convert.ToBase64String(memStream.ToArray()); } } catch (Exception e) { Console.WriteLine(e); return null; } } /// <summary> /// 解密 /// </summary> /// <param name="source"></param> /// <returns></returns> public static string Decrypt(string source) { try { using (var mStream = new MemoryStream(Convert.FromBase64String(source))) using (var cryptoStream = new CryptoStream(mStream, DesHandler.CreateDecryptor(DesHandler.Key, DesHandler.IV), CryptoStreamMode.Read)) using (var reader = new StreamReader(cryptoStream)) { return reader.ReadToEnd(); } } catch (Exception e) { Console.WriteLine(e); return null; } } }}每次调用DesHandler = DES.Create("DES"); 都会重新获得一个DES算法实现实例,这样每次获取的实例中Key、IV这两个属性的值也会发生变化。如果直接使用会出现这次加密的数据下次就没法解密了,为了减少这种情况,所以代码处手动赋值了Key、IV这两个属性。 ...

June 22, 2020 · 3 min · jiezi

aspnet-core-系列-11-Service层的实现样板

0.前言在《asp.net core 系列》之实战系列中,我们在之前的篇幅中对项目有了一个大概的认知,也搭建了一个基础的项目骨架。那么就让我们继续完善这个骨架,让它更加丰满。这一篇,我将带领小伙伴们一起实现用户管理功能。 1. 数据表一般情况下,我们会把用户表和登录信息表放在两个表里。为什么会这样设计呢?出于以下几种考虑: 使功能分割,用户信息管理是用户管理,登录是登录增加安全,降低无关信息的查询,例如访问登录接口不会连带检索用户的普通信息,当进行用户信息管理的时候,不会把登录信息也带过来等等 废话不多说,直接上代码: namespace Data.Enums{ /// <summary> /// 登录类型 /// </summary> public enum LoginType : byte { /// token登录 Token, /// 用户名密码 Password } /// <summary> /// 性别 /// </summary> public enum SexEnum { /// 男 Male, /// 女 Female, /// 隐私 None }}SysUserAuthEntity.cs using Data.Enums;using Data.Infrastructure;namespace Data.Models{ public class SysUserAuthEntity : BaseEntity<int> { public string UserName { get; set; } public string Password { get; set; } public LoginType LoginType { get; set;} }}SysUserInfoEntity.cs ...

June 21, 2020 · 3 min · jiezi

aspnet-core-系列10-实战之ActionFilter

0.前言在上一篇中,我们提到了如何创建一个UnitOfWork并通过ActionFilter设置启用。这一篇我们将简单介绍一下ActionFilter以及如何利用ActionFilter,顺便补齐一下上一篇的工具类。 1. ActionFilter 介绍ActionFilter全称是ActionFilterAttribute,我们根据微软的命名规范可以看出这是一个特性类,看一下它的声明: [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]public abstract class ActionFilterAttribute : Attribute, IActionFilter, IFilterMetadata, IAsyncActionFilter, IAsyncResultFilter, IOrderedFilter, IResultFilter这是一个允许标注在类和方法上的特性类,允许多个标记,标注之后子类会继承父类的特性。然后,这个类是一个抽象类,所以我们可以通过继承ActionFilterAttribute来编写自己的ActionFilter。 1.1 ActionFilter的四个方法对于一个ActionFilter而言,最重要的是它的四个方法: public virtual void OnActionExecuted(ActionExecutedContext context);public virtual void OnActionExecuting(ActionExecutingContext context);public virtual void OnResultExecuted(ResultExecutedContext context);public virtual void OnResultExecuting(ResultExecutingContext context); 上图是这四个方法在一次请求中执行的顺序。在一次请求真正执行之前,想要拦截这个请求,应该使用OnActionExecuting。 为什么单独说这个呢?因为这个方法的出镜率很高,大多数时候都会使用这个方法进行请求过滤。 1.2 在ActionFilter中我们能做什么我们来简单介绍一下,四个方法中的四种上下文类型,看一看里面有哪些我们可以利用的方法: 1.2.1 ActionExecutingContext这是一个Action执行前的上下文,表示Action并未开始执行,但是已经获取到了控制器实例: public class ActionExecutingContext : FilterContext{ public virtual IDictionary<string, object> ActionArguments { get; } public virtual object Controller { get; } public virtual IActionResult Result { get; set; }}ActionExecutingContext继承自FilterContext,我们暂且不关注它的父类,只看一下它自己的属性。 ...

June 18, 2020 · 2 min · jiezi

aspnet-core-系列9-实战之-UnitOfWork以及自定义代码生成

0. 前言在前一篇中我们创建了一个基于EF的数据查询接口实现基类,这一篇我将带领大家讲一下为这EF补充一些功能,并且提供一个解决避免写大量配置类的方案。 1. SaveChanges的外移在之前介绍EF Core的时候,我们提到过使用EF需要在每次使用之后,调用一次SaveChanges将数据提交给数据库。在实际开发中,我们不能添加一条数据或者做一次修改就调用一次SaveChanges,这完全不现实。因为每次调用SaveChanges是EF向数据库提交变更的时候,所以EF推荐的是每次执行完用户的请求之后统一提交数据给数据库。 这样就会造成一个问题,可能也不是问题:我们需要一个接口来管理EF 的SaveChanges操作。 1.1 创建一个IUnitOfWork接口通常我们会在Domain项目中添加一个IUnitOfWork接口,这个接口有一个方法就是SaveChanges,代码如下: namespace Domain.Insfrastructure{ public interface IUnitOfWork { void SaveChanges(); }}这个方法的意思表示到执行该方法的时候,一个完整的工作流程执行完成了。也就是说,当执行该方法后,当前请求不会再与数据库发生连接。 1.2 实现IUnitOfWork接口在 Domain.Implement中添加IUnitOfWork实现类: using Domain.Insfrastructure;using Microsoft.EntityFrameworkCore;namespace Domain.Implements.Insfrastructure{ public class UnitOfWork: IUnitOfWork { private DbContext DbContext; public UnitOfWork(DbContext context) { DbContext = context; } public void SaveChanges() { DbContext.SaveChanges(); } }}1.3 调用时机到现在我们已经创建了一个UnitOfWork的方法,那么问题来了,我们该在什么时候调用呢,或者说如何调用呢? 我的建议是创建一个ActionFilter,针对所有的控制器进行SaveChanges进行处理。当然了,也可以在控制器中持有一个IUnitOfWork的示例,然后在Action结束的时候,执行SaveChanges。不过这样存在一个问题,可能会存在遗漏的方法。所以我推荐这样操作,这里简单演示一下如何创建拦截器: 在Web的根目录下,创建一个Filters目录,这个目录里用来存储一些过滤器,创建我们需要的过滤器: using Domain.Insfrastructure;using Microsoft.AspNetCore.Mvc.Filters;namespace Web.Filters{ public class UnitOfWorkFilterAttribute : ActionFilterAttribute { public IUnitOfWork UnitOfWork; public override void OnActionExecuted(ActionExecutedContext context) { UnitOfWork.SaveChanges(); } }}使用一个ActionFilter可以很方便的解决一些容易遗漏但又必须执行的代码。这里就先不介绍如何配置Filter的启用和详细介绍了,请允许我卖个关子。当然了,有些小伙伴肯定也能猜到这是一个Attribute类,所以可以按照Attribute给Controller打标记。 ...

June 17, 2020 · 2 min · jiezi

Java-Spring-Cloud-实战之路添加一个SpringBootAdmin监控

0. 前言在之前的几章中,我们先搭建了一个项目骨架,又搭建了一个使用nacos的gateway网关项目,网关项目中并没有配置太多的东西。现在我们就接着搭建在Spring Cloud 微服务中另一个重要的项目 - Spring boot admin. 1. Spring Boot Admin 介绍 Spring Boot Admin 用来监控基于Spring Boot的应用,在Spring Boot Actuator的基础上提供了简洁的可视化Web UI。Spring Boot Admin 提供了以下功能: 显示应用的健康状态显示应用的细节内容: JVM和内存信息,micrometer信息, 数据源信息,缓存信息等显示 编译版本查看和下载日志查看jvm参数和环境变量值查看Spring Boot项目配置显示 thread dump显示 http-traces…… 等一系列内容。 2. 创建一个 Spring Boot Admin项目那么,我们就来创建一个Spring Boot Admin 项目吧。 2.1 创建 Spring Boot Admin 服务端在manager 目录下,创建一个 monitor目录,并在monitor目录下创建一个pom.xml 文件,添加以下内容: <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <artifactId>monitor</artifactId> <version>${revision}</version> <packaging>jar</packaging> <parent> <artifactId>manager</artifactId> <groupId>club.attachie</groupId> <version>${revision}</version> </parent></project>在 manager/pom.xml 注册我们新建的项目模块: <modules> <module>gateway</module> <module>monitor</module></modules>在 monitor 创建如下目录: ...

June 17, 2020 · 1 min · jiezi

aspnet-core-系列8-实战之-利用-EF-Core-完成数据操作层的实现

0. 前言通过前两篇,我们创建了一个项目,并规定了一个基本的数据层访问接口。这一篇,我们将以EF Core为例演示一下数据层访问接口如何实现,以及实现中需要注意的地方。 1. 添加EF Core先在数据层实现层引入 EF Core: cd Domain.Implementsdotnet add package Microsoft.EntityFrameworkCore当前项目以SqlLite为例,所以再添加一个SqlLite数据库驱动: dotnet add package Microsoft.EntityFrameworkCore.SQLite删除 Domain.Implements 里默认的Class1.cs 文件,然后添加Insfrastructure目录,创建一个 DefaultContext: using Microsoft.EntityFrameworkCore;namespace Domain.Implements.Insfrastructure{ public class DefaultContext : DbContext { private string ConnectStr { get; } public DefaultContext(string connectStr) { ConnectStr = connectStr; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlite(ConnectStr);//如果需要别的数据库,在这里进行修改 } }}2. EF Core 批量加载模型通常情况下,在使用ORM的时候,我们不希望过度的使用特性来标注实体类。因为如果后期需要变更ORM或者出现其他变动的时候,使用特性来标注实体类的话,会导致迁移变得复杂。而且大部分ORM框架的特性都依赖于框架本身,并非是统一的特性结构,这样就会造成一个后果:本来应该是对调用方隐藏的实现就会被公开,而且在项目引用关系中容易出现循环引用。 所以,我在开发中会寻找是否支持配置类,如果使用配置类或者在ORM框架中设置映射关系,那么就可以保证数据层的纯净,也能实现对调用方隐藏实现。 EF Core的配置类我们在《C# 数据访问系列》中关于EF的文章中介绍过,这里就不做过多介绍了(没来得及看的小伙伴们不着急,后续会有一个简单版的介绍)。 通常情况下,配置类我也会放在Domain.Implements项目中。现在我给大家介绍一下如何快速批量加载配置类: protected override void OnModelCreating(ModelBuilder modelBuilder){ modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetAssembly(this.GetType()), t => t.GetInterfaces().Any(i => t.Name.Contains("IEntityTypeConfiguration")));}现在版本的EF Core支持通过Assembly加载配置类,可以指定加载当前上下文类所在的Assembly,然后筛选实现接口中包含IEntityTypeConfiguration的类即可。 ...

June 17, 2020 · 3 min · jiezi

aspnet-core-系列6-实战之-一个项目的完整结构

0. 前言在《asp.net core 系列》之前的几篇文章中,我们简单了解了路由、控制器以及视图的关系以及静态资源的引入,让我们对于asp.net core mvc项目有了基本的认识。不过,这些并不是 asp.net core mvc项目的全部内容,剩下的内容我将结合实战项目为大家讲解其中的知识。现在,就让我们开始吧。 1. 项目构建抛开之前的项目,现在跟着我重新创建一个项目,第一步依旧是先创建一个解决方案: dotnet new sln --name Template我先介绍一下这个项目(指整个项目,不是单独的asp.net core 应用),这是一个后台管理的模板应用,提供了常见后台系统(管理员端)的功能,包括员工管理、部门管理、角色管理等功能。 现在回到项目中,通常一个项目需要一个模型层,一个数据提供层以及web展示层。然后,我们依次创建 Data、Domain、Web 三个项目,其中Data和Domain 是 classlib,Web是mvc项目。 # 确保当前目录与 Template.sln 处于相同的目录dotnet new classlib --name Datadotnet new classlib --name Domaindotnet new mvc --name Web添加三个项目到解决方案中: dotnet sln add Datadotnet sln add Domaindotnet sln add Web因为Data 中存放着模型层,所以需要其他项目对它有一个引用: cd Domaindotnet add reference ../Datacd ../Webdotnet add reference ../Data当然,实际开发中我们应当还有一个Service层,这一层用来存放业务代码,减少控制器里不必要的业务代码。那么继续: # 回到项目的根目录cd ..dotnet new classlib --name Servicedotnet sln add Service然后添加Service的引用: ...

June 16, 2020 · 1 min · jiezi

用NET进行客户端Web开发看这个Bootstrap风格的BlazorUI组件库

现在做 Web 开发,很多开发者都会选择用 Java 和 SpringBoot 框架,毕竟已经相对成熟并且可扩展性也非常好,但确实很少看到开发者使用 C# 和 .NET 进行 Web 开发。 今天 Gitee 推荐的开源项目便是一个使用 .NET 生成交互式客户端 Web UI 的框架,如果你想学习学习的话不妨接着往下看。 项目名称:BootstrapBlazor 项目作者:Longbow 开源许可协议:LGPL-3.0 项目地址:https://gitee.com/LongbowEnterprise/BootstrapBlazor 项目简介Blazor 是一个使用 .NET 生成交互式客户端 Web UI 的框架: 使用 C# 代替 JavaScript 来创建丰富的交互式 UI。共享使用 .NET 编写的服务器端和客户端应用逻辑。将 UI 呈现为 HTML 和 CSS,已支持众多浏览器,其中包括移动浏览器。使用 .NET 进行客户端 Web 开发可提供以下优势: 使用 C# 代替 JavaScript 来编写代码。利用现有的 .NET 库生态系统。在服务器和客户端之间共享应用逻辑。受益于 .NET 的性能、可靠性和安全性。始终高效支持 Windows、Linux 和 macOS 上的 Visual Studio。以一组稳定、功能丰富且易用的通用语言、框架和工具为基础来进行生成。本项目是利用 Bootstrap 样式进行封装的 UI 组件库。 ...

June 10, 2020 · 1 min · jiezi

C-数据操作系列-17-Dapper-号称可以与ADONET-同台飙车的ORM

0. 前言之前四篇介绍了一个国内开发者开发的优秀框架SqlSugar,给我们眼前一亮的感觉。这一篇,我们将试试另一个出镜率比较高的ORM框架-Dapper。 Dapper是一个轻量级的ORM框架,其以高速、简单易用为特点。在某些时候,效率甚至可以与ADO.NET 媲美。那么,吹得天花乱坠,就让我们实际看看它的表现吧。 1. 开始使用照例,先创建一个项目:DapperDemo dotnet new console --name DapperDemo然后切换到目录里: cd DapperDemo添加包支持: dotnet add package Dapper如果不出意外的话,目前项目中已经安装好了Dapper。现在就让我们开始愉快的使用吧。 首先,需要注意的一点是,与其他的ORM框架不同的是,Dapper需要我们手动创建一个IConnection。Dapper的所有操作都是依托于IConnection来操作,而且Dapper将其支持的方法封装成了IConnection的扩展方法。 所以,在使用之前我们需要先创建一个IConnection。为了方便演示,我把之前SqlSugar演示用过的测试数据库拿过来了,是一个SQLite,所以我们需要先安装一个SQLite的驱动: dotnet add package Microsoft.Data.SQLite在Program.cs中引入两个包: using Microsoft.Data.Sqlite;using Dapper;在Main方法里创建一个IConnection: using(var connection = new SqliteConnection("Data Source=./demo.db")){ }2. 多数据查询Dapper的查询相当简单: var result = connection.Query("select * from Persion");传入一个SQL语句,返回一个可枚举对象。如果不指定类型,将返回类型为dynamic的列表。我们来看一下Query方法的相关声明: public static IEnumerable<dynamic> Query(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null);public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null);public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string sql, Type[] types, Func<object[], TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null);我们就以最常用的三个为例,给大伙分析一下参数以及调用方式: ...

June 9, 2020 · 3 min · jiezi

C-数据操作系列-16-SqlSugar-完结篇

0. 前言前一篇我们详细的介绍了SqlSugar的增删改查,那些已经满足我们在日常工程开发中的使用了。但是还有一点点在开发中并不常用,但是却非常有用的方法。接下来让我们一起来看看还有哪些有意思的内容。 1. 不同寻常的查询之前介绍了针对单个表的查询,同样也是相对简单的查询模式。虽然开发完全够用,但是难免会遇到一些特殊的情况。而下面这些方法就是为了解决这些意料之外。 1.1 多表查询SqlSugar提供了一种特殊的多表查询方案,使用IQueryable接口 。来看看是怎样操作的吧: ISugarQueryable<T, T2> Queryable<T, T2>(Expression<Func<T, T2, object[]>> joinExpression);ISugarQueryable<T, T2> Queryable<T, T2>(ISugarQueryable<T> joinQueryable1, ISugarQueryable<T2> joinQueryable2, Expression<Func<T, T2, bool>> joinExpression) where T : class, new() where T2 : class, new();ISugarQueryable<T, T2> Queryable<T, T2>(ISugarQueryable<T> joinQueryable1, ISugarQueryable<T2> joinQueryable2, JoinType joinType, Expression<Func<T, T2, bool>> joinExpression) where T : class, new() where T2 : class, new();ISugarQueryable<T, T2> Queryable<T, T2>(Expression<Func<T, T2, bool>> joinExpression) where T : class, new();这些方法是属于SqlSugarClient类的方法,SqlSugar提供了最多12个泛型的方法支持,当然实际上开发中能遇到5个表的联查都很少。除非说是在做报表程序,否则就得审查一下数据表模型是否合理了。就以这四个方法为例,介绍一下多表查询如何使用: ...

June 9, 2020 · 5 min · jiezi

C-数据操作系列-15-SqlSugar-增删改查详解

0. 前言继上一篇,以及上上篇,我们对SqlSugar有了一个大概的认识,但是这并不完美,因为那些都是理论知识,无法描述我们工程开发中实际情况。而这一篇,将带领小伙伴们一起试着写一个能在工程中使用的模板类。 1. 创建一个ClientSqlSugar在操作的时候需要一个Client,用来管理数据库连接,并操作数据库。所以我们写一个DbContext用来创建Client: public class DefaultContext{ public SqlSugarClient Client { get; } public DefaultContext(string connectionString, DbType dbType) { Client = new SqlSugarClient(new ConnectionConfig { ConnectionString = connectionString,//"Data Source=./demo.db", DbType = dbType, IsAutoCloseConnection = true, InitKeyType = InitKeyType.Attribute }); Client.CodeFirst.InitTables(typeof(Dept), typeof(Person), typeof(Employee)); Client.Aop.OnLogExecuting = (sql, paramters) => { Console.WriteLine(sql); }; } public SimpleClient<T> CreateClient<T>() where T : class, new() { return Client.GetSimpleClient<T>(); }}SqlSugar 提供了一个SimpleClient,这里面有很多可以直接拿来用的方法,而且这个是一个泛型类。也就是说我们可以使用它对单个实体类进行操作,这在开发中很重要。 2. 插入数据对于一个程序而言,数据就像是血液一样重要。对于ORM框架,插入是一切来源的基础。所以我们先来看看SqlSugar的插入是怎样的吧: ...

June 9, 2020 · 3 min · jiezi

C-数据操作系列-14-深入探索SqlSugar

0.前言在上一篇中,我们知道了如何使用SqlSugar,但是也只是简单的了解了如何使用,仿佛是套着镣铐行走,这明显不符合一个合格的程序员应有的素养。所以,这一篇我们将对其进行深挖,探究其背后的秘密。 1. 花式映射在实际开发中,程序中的实体类和数据库的表名并不能完全一致,造成的原因有很多,例如说团队对数据库的命名和对程序的命名有着不同的要求,数据库是先建立的而程序是后开发的,又或者是程序只使用了数据库中一部分表等等。 这时候就会与C#约定优于配置相违背,但是这也符合C#的设计哲学,因为配置也是C#的一部分。我们该如何从实际角度来完成表与实体类之间的关系建立呢? 那就让我来带着大家一起看看SqlSugar是否能优雅的完成这一部分: 1.1 Attribute设置SqlSugar预制了一些Attribute,允许我们通过Attribute来为实体表与数据库表之间建立关系: SugarTable:用来定义实体类映射的数据表public SugarTable(string tableName);public SugarTable(string tableName, string tableDescription);这是SugarTable的两个构造函数,允许设置表名和数据表描述 SugarColumn:用来定义属性与数据表中的列的关系public string ColumnDataType { get; set; }// 列的数据类型,填SQL 的数据类型public string OldColumnName { get; set; }// 当做了表更新之后,用来生成数据库用,此处填写原列名public bool IsNullable { get; set; }// 设置列是否允许为NULLpublic int Length { get; set; } // 设置列的数据长度public string ColumnDescription { get; set; }// 设置列的描述名称public bool IsIdentity { get; set; } // 设置该列是否是自增列public bool IsPrimaryKey { get; set; } //设置该列是主键public bool IsIgnore { get; set; } // 不作数据库操作,true将不会进行查询、添加等操作public string ColumnName { get; set; } // 设置对应的列名public string DefaultValue { get; set; } // 设置该列的默认值SqlSugar的Attribute配置非常的简单,只需要针对类与表的映射和属性对列的映射做出配置即可。 ...

June 9, 2020 · 2 min · jiezi

C-数据操作系列-13-SugarSql初探

0. 前言前言,暂时挥别NHibernate(虽然我突然发现这玩意还挺有意思的,不过看得人不多)。大步进入了有很多小伙伴向我安利的SQLSugar,嗯,我一直叫SugarSQL,好像是这个吧? 这是一个由国内开发者开发的ORM框架,是一个轻量级框架(最新版的sqlSugarCore大概只有290kb)。下图是sqlSugar的功能描述: 从图中我们能够大概看出,SqlSugar的使用需要预先创建一个SqlSugarClient对象。SqlSugar在此基础上添加了CRUD、实体信息维护(映射关系)、配置(AOP/过滤器等)、模式(DbFirst、CodeFirst)还有一些工具类等。可以看到这是一个简而全的框架。 同时,SqlSugar也为查询进行了进一步的扩展,以下是它支持的功能,以及在查询上的增强: 好了,废话不多说,先来试一下如何使用吧。 1. 安装本节环境是dotnet + vscode。因为我的Rider过期了,懒得折腾。系统又是Linux,所以选择这种方式。至于Visual Studio和Rider的操作,十分简单,而且之前《C#基础系列16》里有过介绍。 先建一个解决方案,名字为DataProvider: dotnet new sln --name DataProvider然后创建一个SqlSugarDemo的控制台项目: dotnet new console --name SqlSugarDemo将这个项目添加到解决方案里:(这一步为了方便后续管理) dotnet sln add SqlSugarDemo然后准备安装 sqlSugarCore 。SqlSugar有两个版本,这里使用的是sqlSugarCore,这是针对.net core支持的版本。另一个是sqlSugar,是基于.netframework 4.X的。我们的系列是.net core的,所以就使用sqlSugarCore。 因为我们只是给项目SqlSugarDemo添加这个包,而不是给整个解决方案添加,所以我们需要预先切换目录到SqlSugarDemo里: cd SqlSugarDemo/然后使用命令行安装 sqlSugarCore: dotnet add package sqlSugarCore或者使用 NuGet: Install-Package sqlSugarCore过一会就可以在控制台中看到安装成功的消息: log : Restore completed in XX sec for XXXXXX/SqlSugarDemo/SqlSugarDemo.csproj.2. 基本使用示例在上一节中,我们成功在项目中安装了sqlSugarCore,那么在这一节中将带领小伙伴们一起探索SqlSugar。 先创建一个普通的模型: public class Person{ public int Id { get; set; } public string Name { get; set; } public int Age { get; set; }}创建一个操作类,取名为 DefaultContext,根据给出的文档得知,SqlSugar每次操作数据的时候需要持有一个 SqlSugarClient对象。所以,这个类的定义应该如下: ...

June 7, 2020 · 2 min · jiezi

C-数据操作系列-12-NHibernate的增删改查

0. 前言上一篇《C# 数据操作系列 - 11 NHibernate 配置和结构介绍》 介绍了Nhibernate里的配置内容。这一篇将带领大家了解一下如何使用NHIbernate。之前提到NHibernate继承了Hibernate的一些传统:使用XML文件进行配置,这一点也是备受争议。不过,有社区爱好者开发了一个名为《Fluent NHibernate》的项目,用来支持NHibernate的流式配置。当然,NHibernate本身也提供了NHibernate.Mapping.ByCode模式。不过这一篇暂且略过,留待下文。 1. NHibernate映射文件对于NHibernate的映射文件有个约定的名字: <类名>.hbm.xml这里先为大家介绍一下映射文件的格式: 1.1 hibernate-mapping 的说明<hibernate-mappingschema="schemaName" (1)default-cascade="none|save-update" (2)auto-import="true|false" (3)assembly="Eg" (4)namespace="Eg" (5)default-access="field|property|field.camecase..." (6)default-lazy="true|false" (7)/>schema: 数据库schema的名称default-cascade:可选项,默认是none,一种默认的级联风格auto-import:明确是否可以在查询中使用非限定类名。assembly:指定映射对象所在的assembly,一般情况指的是项目名称namespace:所在命名空间default-access:可选的,默认是property,表示NHibernate的读取数据列的策略,默认情况从Property 中读取default-lazy:可选的,默认是true,是否启动延迟加载1.2 class的配置一般情况下,class节点只需要指定name和table就可以了。接下来,让我们探索class如何映射成的。 1.2.1 id任何一个映射都必须声明一个数据表的主键,大多数类也必须有一个唯一标示字段用来区分不同的实例。 这里介绍一下 id 节点的配置: <id name="PropertyName" type="typename" column="column_name"> <generator class="generatorClass"/></id>name : 对应的属性名type:对应的NHibernate类型column:列名generator:主键生成器,如果不需要参数可以直接在 id节点处添加,最常用的是native。1.2.2 property映射一个普通属性就简单多了,只需要进行以下配置即可: <property name="propertyName" column="column_name" type="typename"/>name :类里的属性名column:对应数据表的列名type:数据库中的类型1.2.3 many-to-one在Nhibernate中,多对一的配置是在一的一端,表示该类有一个外键导航。 <many-to-one name="PropertyInOne" class="ManyClass" column="Column" ></many-to-one>1.2.4 one-to-one一对一的关系与多对一的关系比较相似,不同的地方在于一对一需要在双方的映射关系里均要维护,在有外键的表/实体中 添加 constrained=“true”。 示例如下: <one-to-one name="Person" class="Person"/><one-to-one name="Employee" class="Employee" constrained="true"/>2. 增删改查Nhibernate的每次操作都基于一个Session,所以我们在操作数据库的时候最好先持有一个可用的Session。接下来,我们就一个通用数据库操作类为基础,向大家分享一下我的想法。 首先,创建一个泛型模板类,并约束泛型为类: public class Repository<T> where T: class{}添加一个ISession属性,用来后续访问操作,并由构造方法赋值: public Repository(ISession session){ Session = session;}public ISession Session { get; }2.1 新增现在我们写一下新增方法: ...

June 7, 2020 · 2 min · jiezi

C-数据操作系列-11-NHibernate-配置和结构介绍

0. 前言今天是NHibernate的第二篇内容,通过上一篇的内容,我们初步了解了NHibernate的创建和使用。这一篇,我继续探索NHibernate背后的秘密。嗯,就是这样。 1. NHibernate结构先给小伙伴们放个图: 这是NHibernate的整体结构图。NHibernate通过ADO.NET 建立访问数据库的连接,然后封装了一个Transaction(事务)工厂和一个Session工厂。每次操作的时候,通过两个工厂获取对应的Session/Transaction示例操作数据对象。 ISessionFactory - NHibernate.ISessionFactory: 一个基于单数据库的已编译的映射缓存,它是持久不变的且线程安全(额,这句话是从它的文档翻译过来的)。是一个提供ISession的工厂类,同时也是一个 IConnectionProvider的客户端。可以设置一个在事务之间的进程级或集群级的二级缓存。 ISession - NHibernate.ISession: 一个单线程、短生命周期的对象,表示从应用程序和数据持久化之间一个连接。一个ADO.NET连接的封装,用来提供ITransaction的工厂。提供了一个通过主键检索对象和导航链接查询对象时的一级缓存。也就是EF Core中的导航属性。 Persistent Objects and Collections(持久化对象和集合): 一些单线程、短生命周期对象其中包含持久化状态和业务方法。它们可能只是一些普通的POCO,仅仅是与ISession中关联起来了。只要ISession关闭了,这些对象就可以被分离出来然后可以在应用层的任意地方使用。 Transient Objects and Collections(临时对象和集合): 表示临时的未被ISession托管的持久化对象,它们被应用层临时创建但直到ISession关闭都不会被持久化。 ITransaction - NHibernate.ITransaction: 这个是可选的。表示一个单线程、短生命周期的对象,被应用程序用来限制一个原子的工作单元,基于ADO.NET 的Transaction的抽象。一个ISession可能会开启多个事务,Transaction scopes may be used instead(原话是这个,大意是可以改用事务作用域)。 IConnectionProvider - NHibernate.Connection.IConnectionProvider: 也是可选的,是一个用来创建ADO.NET Connection和Command的工厂。基于DbConnection和DbCommand实现,并非直接暴露给应用程序,但是可以由开发者对其进行扩展或实现。 IDriver -NHibernate.Driver.IDriver: 可选的,驱动接口,用来封装隐藏不同ADO.NET 数据提供程序之间的不同。例如:参数化等。 ITransactionFactory - NHibernate.Transaction.ITransactionFactory: 可选的,事务实现工厂,不对应用程序公开,但开发者可以对其进行扩展或实现。 2. 实例状态在NHibernate中,一个可持久化的对象有三种不同的状态,依据与持久化上下文之间的关系不同,其中ISession就是一个持久化上下文。状态分为以下三种: transient 暂存的、临时的 该状态的对象并没有被持久化上下文捕获到,简单来讲就是刚被创建,还没有从数据库/持久化上下文中获取到主键信息。persistent 持久化的 该状态的对象表示已经被上下文正确获取到了,持久化上下文能够监控到对象的变化。持久化上下文中持有一个指向该对象的引用。这种状态通常是从数据库中获取到数据或者新建的数据附加到了上下文中。detached 游离态 该状态的对象是从上下文中分离出来的,有了数据库主键,曾经或现在仍然有一条数据库记录与之对应。造成的原因可能有,上下文关闭了;该对象是在另一个上下文中持久化的,它对于当前上下文是游离态的。3. 配置项介绍在上一篇文章中,我们介绍了一下如何设置NHibernate的基本配置项,但是并未对配置项进行深入。这一节,将带领大家看一下NHibernate中我们常用的配置,因为配置项有很多,但一大部分通常情况都遇不到使用它的时候。 dialect 数据库方言,表示NHibernate连接的数据库是什么,该用哪种格式解析关系映射到数据库SQL语句 default_schema默认的schema,用来设置连接字符串连接的数据库默认的schema。 connection.provider数据库连接的提供程序,默认是NHibernate.Connection.DriverConnectionProvider. 填继承自 IConnectionProvider 的实现类 ...

June 4, 2020 · 1 min · jiezi

C-数据操作系列-10-NHibernate初试

0. 前言在上一篇基本讲完了EF Core的入门级教程。从这一篇开始,我们试着去探索一下 .net core平台上更多的ORM框架。那么,这一篇开始我们就来试试NHibernate。 1. NHibernate 介绍NHibernate是Hibernate的C#版,众所周知Hibernate是Java 里ORM的顶梁柱(至少曾经)。Hibernate可以说开拓了Java的世界,当年SSH三驾马车风靡世界,至今Hibernate都发挥着举足轻重的作用。 不过,与EntityFramework不同的地方是,Hibernate以配置文件为主,通过配置文件规范使用,Object/Relation 映射。而NHibernate这继承了这一点,也是以配置文件优先。下图是 NHibernate的工作原理: 通过读取App.config或者Web.config文件去读NHibernate的基本配置,然后加载映射文件,建立映射关系。在后续使用中,通过映射关系生成SQL语句(这一步跟EF是一致的),进而操作数据或者查询数据。 2. 初探 NHibernate2.1 准备先来个控制台项目,我起名为dataprovider。然后安装NHibernate: NuGet:Install-Package NHibernatedotnet core 命令行:dotnet add package NHibernate这个文章中使用的NHibernate版本是 5.2.7 2.2 配置需要创建一个项目用的配置文件:App.config. C# 项目中,除了Web类型的项目,每个项目的主配置文件的名称都是App.config,这是一个固定名称。 文件内容如下: <?xml version="1.0" encoding="utf-8" ?><configuration></configuration>在 configuration节点之间添加以下内容: <configSections> <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"/> </configSections>这段代码的含义是,在config文件中添加一个 hibernate-configuration结点,结点的解析由类:NHibernate.Cfg.ConfigurationSectionHandler,所在包是NHibernate。 在App.config文件configuration结点中添加以下代码: <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"> <session-factory> <property name="dialect">NHibernate.Dialect.MsSql2012Dialect</property> <property name="connection.connection_string"> Data Source=.;Initial Catalog=Demo;Integrated Security=True </property> <property name="hbm2ddl.auto">create-drop</property> <mapping assembly="dataprovider" /> </session-factory></hibernate-configuration>这是固定格式,其中dialect表示使用的数据库类型,connection.connection_string 表示连接字符串。mapping表示映射关系文件所在项目。 2.3 获取ISessionFactory然后获取一个ISessionFactory: Configuration cfg = new Configuration();var sessionFactory = cfg.BuildSessionFactory();当然,如果直接运行代码的话,会在 BuildSessionFactory这里报错。因为没有为SQL Server安装数据访问驱动: ...

June 4, 2020 · 2 min · jiezi

C-数据操作系列-9-EF-Core-完结篇

0.前言《EF Core》实际上已经可以告一段落了,但是感觉还有一点点意犹未尽。所以决定分享一下,个人在实际开发中使用EF Core的一些经验和使用的扩展包。 1. EF Core的异步操作正如这小节题目所言,EF Core是支持异步操作的,但实际可用集中在SaveChanges和异步查询这两个方法上。 具体方法声明如下: public virtual System.Threading.Tasks.Task<int> SaveChangesAsync (System.Threading.CancellationToken cancellationToken = null);public virtual System.Threading.Tasks.Task<TEntity> FindAsync<TEntity> (params object[] keyValues) where TEntity : class;public virtual System.Threading.Tasks.Task<TEntity> FindAsync<TEntity> (object[] keyValues, System.Threading.CancellationToken cancellationToken) where TEntity : class;public virtual System.Threading.Tasks.Task<object> FindAsync (Type entityType, params object[] keyValues);public virtual System.Threading.Tasks.Task<object> FindAsync (Type entityType, object[] keyValues, System.Threading.CancellationToken cancellationToken);这五个方法分别是SaveChanges的异步版,和Find的异步版。两种方法都支持传入一个取消令牌(这部分内容需要等后期的《C# 异步编程系列》里介绍)。 返回一个Task,然后按照Task进行执行就行。 DbContext 也提供了Add/AddRange的异步方法,但是这组方法的异步版需要数据库的支持,并不是一个通用的方法,所以就没有提。 var context = new DefaultContext("Data Source=./blogging1.db");var task1 = context.FindAsync<SingleModel>(1);var result = task1.Result;var task2 = context.SaveChangesAsync();这两个任务是创建一个热启动任务,也就是不用手动调用 Run方法。 ...

June 4, 2020 · 1 min · jiezi

C-数据操作系列-8-EF-Core的增删改查

0.前言到目前为止,我们看了一下如何声明EF Core的初步使用,也整体的看了下EF Core的映射关系配置以及导航属性的配置。 这一篇,我带大家分享一下,我在工作中需要的EF Core的用法。 1. 初始化在实际开发中,一般都是先设计好数据表再进行开发,所以很少用到EF Core的数据迁移功能。所以EF Core的初始化,一般也指的是EF Core上下文初始化。 1.1 连接字符串我们通过前面的文章知道,EF Core在上下文初始化的时候,都需要一个链接字符串。如果在不考虑后续变更或者上下文的复用性,可以直接在自定义Context里重写OnConfiguring方法中定义。 如果需要后续变更,那么就需要在创建自定义EF Core 上下文类的时候,为之添加一个连接字符串的属性或者字段,以方便初始化的时候指定。实例: public class DefaultContext : DbContext{ private string Connection { get; set; } = "Data Source=./blogging1.db"; public DefaultContext(string connection) { Connection = connection; } protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseSqlite(Connection);}这样一来,我们在后续使用的时候,就可以指定连接字符串了。当然了,如果有小伙伴有更好的方法也可以分享出来呀。 1.2 配置文件的加载或者实体对象的托管如果我们不使用配置文件的话,就必须在EF Core的上下文类里添加一个类型是DbSet<T>的属性。继续延续上面的实例: public class SingleModel{ public int Id { get; set; } public int TargetId { get; set; } public SingleTargetModel SingleTarget { get; set; }}public class SingleTargetModel{ public int Id { get; set; } public SingleModel Single { get; set; }}public class DefaultContext : DbContext{ // 其余代码参见 1.1 DefaultContext public DbSet<SingleModel> Singles { get; set; } public DbSet<SingleTargetModel> Targets { get; set; }}以上也就是这一小节标题中的实体对象的托管。我没找到EF Core官方文档中对于这种方式的称呼,所以我就悄悄的抢注了一下为托管。 ...

June 4, 2020 · 2 min · jiezi

C-数据操作系列-7-EF-Core-导航属性配置

在上一篇,大概介绍了Entity Framework Core关于关系映射的逻辑。在上一篇中留下了EF的外键映射没有说,也就是一对一,一对多,多对一,多对多的关系等。这一篇将为大家细细分析一下,如何设置这些映射。 1. 实体之间的关系从数据表来考虑,两个表之前的关系有一对一,一对多(多对一)和多对多的关系。 其中一对一,指的是表A有一条记录对应着表B最多有一条记录与之对应。反过来也一样,表A也最多有一条记录与表B的某一条记录对应。具体在数据表上表现为,A表和B表各有一个外键指向对方。 一对多和多对一是一个概念,只是参考的方向是相反的。所谓的一对多就是其中多方上有一个属性或者列指向了另一个实体,而那个“一”的那头则没有对应的属性指向多方。 多对多是指两个类的实例各有一个集合属性指向对方,换句话说就是A有0到多个B,B也有0到多个A。这里有一个关于多对多的ER图。 2. 一对一关系先给出两个示例类,为了方便理解,我只保留了主键和导航属性: public class SingleModel{ public int Id { get; set; } public SingleTargetModel SingleTarget { get; set; }}public class SingleTargetModel{ public int Id { get; set; } public SingleModel Single { get; set; }}那么我们开始写配置文件: public class SingleModelConfig : IEntityTypeConfiguration<SingleModel>{ public void Configure(EntityTypeBuilder<SingleModel> builder) { builder.ToTable("SingleModel"); builder.HasKey(p => p.Id); builder.Property(p => p.Id).ValueGeneratedOnAdd(); var relation = builder.HasOne(t => t.SingleTarget).WithOne(r => r.Single); }}public class SingleTargeModelConfig : IEntityTypeConfiguration<SingleTargetModel>{ public void Configure(EntityTypeBuilder<SingleTargetModel> builder) { builder.ToTable("SingleTargetModel"); builder.HasKey(p => p.Id); builder.Property(p => p.Id).ValueGeneratedOnAdd(); }}其中HasOne表示当前实体是关系中“一”,WithOne 表示导航目标类的关系。 ...

June 3, 2020 · 3 min · jiezi

C-数据操作系列-6-EF-Core-配置映射关系

0. 前言在《C# 数据操作系列 - 5. EF Core 入门》篇中,我们简单的通过两个类演示了一下EF增删改查等功能。细心的小伙伴可能看了生成的DDL SQL 语句,在里面发现了些端倪。没看的小伙伴也不急,这就贴出来。 public class ModelA{ public int Id { get; set; } public string Name { get; set; } public List<ModelB> ModelBs { get; } = new List<ModelB>();}public class ModelB{ public int Id { get; set; } public string Name { get; set; } public int ModelAId { get; set; } public ModelA modelA { get; set; }}DDL SQL: ...

June 3, 2020 · 2 min · jiezi

C-数据操作系列-5-EF-Core-入门

0.前言上一章简单介绍了一下ORM框架,并手写了一个类似ORM的工具类。这一章将介绍一个在C#世界里大名鼎鼎的ORM框架——Entity Framework的Core版。 Entity Framework 非Core版目前已经更新到了6代,这是一款经过检验的ORM框架。在这里简单介绍一下Entity Framework(简称EF,额,别拿这个当关键字搜索,要不然你会被忽悠到一个英语培训机构的)的优点。 C#的设计理念是约定优于配置,意思就是通过一定程度的规范性格式化的写法来避免使用配置文件或者配置代码等。而EF可以说是很好的诠释了这个理念。 EF可以在不使用任何配置的前提下,自动解析类与表之间的映射(具体的映射逻辑与我们手写的ORM工具类一致或相近)。自动跟踪更改。在直接使用通过EF获取的元素时,EF会自动跟踪哪些字段发生了变化,当手动调用保存的时候,EF就会把数据回传给数据库。可以延迟加载需要的数据,外键引用属性、查询结果等丰富的映射关系,支持一对一,一对多,多对多,甚至继承、单表多实例等可以使用Linq 进行查询非Core版的可以通过数据库表生成实体类,两种都可以通过实体类生成表基于 ADO.NET 的数据库连接和可用于连接到 SQL Server、Oracle、MySQL、SQLite、PostgreSQL、DB2 等当然,还有一个特点:EF是约定优于配置,所以EF也可以配置。EF可以使用Fluent式配置,也可以使用配置文件进行配置。 说了一大堆Entity Framework的优点,那么就让我们开始使用Entity Framework Core吧。 这里简单介绍一下选择Core的原因,微乳这几年一直在主推跨平台战略。因为EF更多的是基于.NET Framework开发的,所以微软以EF为基础针对.net core做了一定的修改,然后EF Core诞生了。可以说EF Core是专门为.net core开发的。而且.net core有更多更好的发展。1. Entity Framework Core安装现在就让我们一起来试着用一下EntityFramework Core吧。 先新建一个项目: Visual Studio 点下一步,选择Console程序: 点击创建 Visual Studio Code dotnet new console -o ef_democd ef_demo然后用VS Code打开 ef_demo目录。 然后选择数据库: 这次与之前的选择不太一样,这次选择 SQLite这个数据库。这是一个超小型的数据库,可以不用安装任何附加软件,只要有一个文件,然后通过代码就可以访问了。 接下来,添加 EF的SQLite包: 在非Visual Studio环境下,安装一个三方库可以使用: dotnet add package Microsoft.EntityFrameworkCore.Sqlite这个命令进行安装。这是dotnet命令行安装三方包的命令。对于Visual Studio或者Rider都可以通过图形化的NuGet安装三方包。 如果是使用NuGet的命令行界面进行安装的话,可以通过: Install-Package Microsoft.EntityFrameworkCore.Sqlite这行命令来安装NuGet包。 2. 入门级使用方式先创建两个实体类: public class ModelA{ public int Id { get; set; } public string Name { get; set; } public List<ModelB> ModelBs { get; } = new List<ModelB>();}public class ModelB{ public int Id { get; set; } public string Name { get; set; } public int ModelAId { get; set; } public ModelA modelA { get; set; }}然后创建一个继承自 ...

June 2, 2020 · 2 min · jiezi

金蝶云星空之表单插件的开发

前言:学习金蝶软件过程中学习到的东西,做总结,方便日后查阅!新建开发解决方案、调试与值监视\1. 新建解决方案。名称空间:命名要求表达准确,无歧义 \2. 断点调试。 \3. 值监控。 FCustomerID this.View.Model.GetValue("FCustomerID") 表单插件的赋值与取值GetValue和SetValue引用 using Kingdee.BOS.Core.Bill.PlugIn;this.View.Model.SetValue this.View.Model.GetValue --插件说明 [Description("表单插件")] --热启动 [Kingdee.BOS.Util.HotUpdate] 单据体取值和赋值GetValue和SetValue表单插件引用 using Kingdee.BOS.Core.Bill.PlugIn; this.View.Model.SetValue this.View.Model.GetValue --插件说明 [Description("表单插件")] --热启动 [Kingdee.BOS.Util.HotUpdate] --调用值更新事件 this.View.InvokeFieldUpdateService 表单插件的常用方法常用的表单插件属性 this.View.GetFormTitle()------获取单据标题 this.View.Model.DataObject["Id"]---获取表单Fid this.View.Model.GetPKValue---获取表单Fid this.View.GetControl("F_PAEZ_Remarks ").SetFocus()-------设置焦点 this.View.GetControl("F_PAEZ_Remarks").Enabled = false; ----锁定字段 this.View.GetFieldEditor("F_PAEZ_Remarks ", 0).Enabled = false;----单据体行锁定字段 this.View.GetControl("F_PAEZ_Remarks").Visible = false; ----隐藏字段 this.View.GetMainBarItem("tbSave").Enabled = false;----锁定按钮 this.View.GetMainBarItem("tbSave").Visible = false;---- 隐藏按钮 this.View.UpdateView("F_SB_SumOutAmount")前台刷新,不和服务器交互。 this.View.Refresh----整个页面刷新,要和服务器交互,把后台数据库数据刷新过来 this.View.InvokeFormOperation("Save")---调用表单事件 常用的单据体属性插件 this.View.Model.DeleteEntryData("FEntity");--删除单据体信息 this.View.Model.DeleteEntryRow("FEntity",0);--删除单据体信息 this.View.Model.CreateNewEntryRow("FEntity");-创建新行 this.View.Model.CopyEntryRow("FEntity",0,1,false);--复制一行。 this.View.Model.GetEntryPKValue("FEntity", 0);--获取单据体FENTRYID内码 this.View.Model.GetEntryRowCount("FEntity")---获取单据体行数。 表单插件的常用提示框常用的提示信息框\1. this.View.ShowMessage("你好"); ...

June 2, 2020 · 5 min · jiezi

C-数据操作系列-4-自己实现一个ORM

0. 前言在之前的几篇内容中,我们了解了如何通过ADO.NET 访问数据库,如何修改、新增数据。如何通过DataSet和DataAdapter获取数据,我们将在这一篇试试自己实现一个简单的ORM框架或者说ORM工具类。 涉及到的知识点: 反射(初级)ADO.NET 已有知识1. ORM那么,问题来了,什么是ORM?ORM全称 Object Relational Mapping,翻译过来就是对象关系映射。是一种通过描述对象与数据库之间映射关系的数据,将对象保存到数据库中的技术。 在C#中,曾经Entity Framework光芒万丈,遮盖了其他ORM框架的光辉(甚至如今都是如此)。 后来慢慢涌现除了其他的一些ORM框架,进一步丰富了市场。所以现有比较流行的大概有以下几种: Dapper 一个轻量的ORM框架Entity Framework/Entity Framework Core 功能完备的框架Nhibernate Java平台上著名的Hibernate的.net版等等嗯,这是我最近找到的创作组还在更新的几个框架,当然还有其他的很多有趣好用的ORM框架。欢迎各位补充哈。 这一篇的主要目的不是介绍这些框架(这是以后的内容),而是通过我们自己实现一个类ORM框架来了解底层核心。 2. 设计我们先分析一下,如果我们设计一个实体对象与数据库之间转换的工具类应该具有哪些功能? 一个属性与数据库字段的映射关系增删改查的SQL模板查询结果与对象的转换3. 实现首先,声明一个类,因为不能仅支持一种类型,所以这个类的所有与数据库有关的方法都是泛型方法,或者这个类是泛型类,所以定义为泛型类: public class OrmUtil<T>{}我们事先约定类名即表名,属性名即表的列名,所以我们可以快速得到以下内容: /// <summary>/// T的类型实例/// </summary>private Type dType;/// <summary>/// T的属性表/// </summary>private PropertyInfo[] properties;public OrmUtil(){ dType = typeof(T); properties = dType.GetProperties();}声明一个数据库连接: public SqlConnection Connection { get; set; }创建一个私有方法,检查连接是否可用: /// <summary>/// 检查连接是否可用/// </summary>/// <returns></returns>private bool CheckConnection(){ return Connection?.State == ConnectionState.Open;}准备工作完成,然后开始编写具体的业务方法: Insert: public int Insert(T entity){ if (!CheckConnection()) return -1;// 检查状态 var insert = $"insert into {dType.Name}({string.Join(",", properties.Select(t => t.Name))})"; var values = properties.Select(p => p.GetValue(entity)); var commandText = $"{insert} values('{string.Join("','", values)}')"; var command = Connection.CreateCommand(); command.CommandText = commandText; var result = command.ExecuteNonQuery(); return result;}首先按照属性名与列名之间的映射拼接 SQL,然后执行SQL命令。 ...

June 2, 2020 · 2 min · jiezi

C-数据操作系列-3-ADONET-离线查询

0. 前言在上一篇中,我故意留下了查询的示范没讲。虽然说可以通过以下代码获取一个DataReader: IDataReader reader = command.ExecuteReader();然后通过reader一行一行的读取数据,但是我并不推荐这样使用。 在查询这一高频需求上,C#为之做了很多工作,提供了更多的选择。这里介绍一个查询的另一套写法。 1. 离线查询C#在查询上提供了另一种机制,可以一次性从数据库把结果读取到网络缓存区中,直到使用的时候才加载到程序中。 在离线查询里最关键的三个接口或类: IDataAdapter 一种适配器,用来获取数据并填充或更新DataSetDataSet 表示数据在内存中的缓存DataTable 表示内存中一个数据表IDataAdapter用来提供数据,DataSet表示adapter读取的结果集,其中有一个DataTable集合表示执行的SQL查询结果。至于为什么是集合,是因为IDataAdapter允许运行多条查询语句。 好,让我们粗略浏览一下这个三个关键点的属性和方法: IDataAdapter: public int Fill (System.Data.DataSet dataSet);//将查询出来的结果填充到DataSet里在C#内部,其实不允许推荐直接继承该接口,推荐继承DataAdapter类,该类规定了数据库Adapter在初始化的时候,必须提供一个可以访问的数据库连接和要执行的命令文本。 当然其部分实现类允许以属性的形式后赋值这两个关键内容。 DataSet: public DataSet ();public DataSet (string dataSetName);//指定数据集的名称public System.Data.DataTableCollection Tables { get; }//获取包含在 DataSet 中的表的集合DataSet有很多有用的方法,但是在今天我们只用关系这些就可以了。 其中Tables 引入了一个没有提到的类型,DataTableCollection。那么我们可以顺藤摸瓜,来看看里面有什么关键的内容: public System.Data.DataTable this[int index] { get; }// 获取指定下标的DataTablepublic System.Data.DataTable this[string name] { get; }//获取具有指定名称的DataTable可以看到提供了一种我们可以获取到里面的DataTable元素的索引访问方式。 DataTable : public System.Data.DataSet DataSet { get; }//获取此表所属的 DataSet。public System.Data.DataColumnCollection Columns { get; }//获取属于该表的列的集合public System.Data.DataRowCollection Rows { get; }//获取属于该表的行的集合又出现了两个新的类:DataColumnCollection、DataRowCollection。这是一种内部集合的实现类,功能类似于List,但又不等同于List。 ...

June 2, 2020 · 2 min · jiezi

C-数据操作系列-2-ADONET操作

0.前言在上一篇中初略的介绍了一下SQL的基本写法,这一篇开始我们正式步入C#操作数据库的范围。通过这一系列的内容,我想大家能对于数据库交互有了一定的认识和基础。闲话不多说,先给大家介绍一个C#操作数据库的方式。 1. ADO.NET的介绍在ADO.NET出现之前,C#连接数据库有很多种方式,各种框架琳琅满目。用户们饱受困扰,再加上乱七八糟的连接方式对语言的发展也是一种强有力的阻挠。所以微软决定搞一套标准化出来,之后ADO.NET诞生了。 ADO.NET定义了一系列操作数据库的接口和基类,而数据库厂商只需要根据自己的实际情况开发对应的实现类就可以了。 2. 使用ADO.NET 操作需要的步骤使用ADO.NET操作数据库,先需要一个连接也就是 IDbConnection实例,然后使用IDbCommand执行,通过 IDataReader读取数据。 先来简单介绍一下上面提到的接口: a.IDbConnection 表示一个与数据源的开放连接,并由访问关系数据库的.NET 数据提供程序实现,也就是说这只是一个接口,具体的实现得看具体的数据库。 我们先看一下,具体的属性和方法吧: public string ConnectionString { get; set; }// 获取或设置用于打开数据库的连接字符串public string Database { get; }//获取当前连接或即将连接的数据库名称public System.Data.ConnectionState State { get; }//获取当前连接的状态public System.Data.IDbTransaction BeginTransaction ();//开启一项数据库事务public void ChangeDatabase (string databaseName);//修改已打开连接的当前数据库public void Close ();//关闭当前连接public System.Data.IDbCommand CreateCommand ();//创建并获取与该连接关联的命令对象public void Open ();//开启与数据库的连接b. IDbCommand 表示连接到数据源时执行的SQL命令,并由访问关系数据库的.NET数据提供程序实现。与IDbConnection一致,也是一个接口。 这个接口的属性和方法如下: public string CommandText { get; set; } //获取或设置要对数据源运行的文本命令,也就是SQL语句public int CommandTimeout { get; set; } //获取或设置在终止尝试执行命令并生成错误之前的等待时间public System.Data.CommandType CommandType { get; set; }//指定或者获取解释CommandText属性的方式public System.Data.IDbConnection Connection { get; set; }//获取或设置执行该命令的连接public System.Data.IDataParameterCollection Parameters { get; }//获取命令的参数化列表public System.Data.IDbTransaction Transaction { get; set; }//获取或设置该命令关联的事务public void Cancel ();//尝试取消执行命令public System.Data.IDbDataParameter CreateParameter ();//创建一个参数public int ExecuteNonQuery ();//执行一个语句,并返回受影响的行数public System.Data.IDataReader ExecuteReader ();//在Connect上执行CommandText,并返回一个IDataReaderpublic object ExecuteScalar ();//执行查询,并返回第一行第一列,其他数据忽略c. IDataReader ...

June 1, 2020 · 3 min · jiezi

C-数据操作系列-1-SQL基础操作

0.前言前篇介绍了一些数据库的基本概念和以及一些常见的数据库,让我们对数据库有了一个初步的认识。这一篇我们将继续为C#数据操作的基础填上一个空白-SQL语句。 SQL(Structured Query Language,结构化查询语言)是一种特定的编程语言,用于管理数据库系统,操作数据甚至编写一些程序。 当然,一方面因为时间问题,一方面因为各大数据库的区别(当然了,还有就是个人对SQL研究并不是那么深)所以这一篇就从SQL的基本操作入手,带领大家一起看看SQL的世界。 1. SQL的分类在SQL的世界里,被分割为两个部分:DML(Data Manipulation Language 数据操纵语言)、DDL(Database Definition Language 数据定义语言)。当然,也有很多其他的分法,这里参照了机械工业出版社出版的《计算机科学丛书- 数据库系统概念》。 1.1 DML数据操纵语言,用户可以凭此来访问或者操纵那些被结构化存储起来的数据。DML提供了以下功能: 对存储在数据库的数据进行检索(select)在数据库中添加新的数据(insert)修改数据库中的数据(update)删除数据库中的某些数据(delete)简单的概括起来就是增删改查,对于开发而言这是一项枯燥乏味的工作,当然也是每个程序必不可少的工作。如果你见到这个词:crud,不要诧异,这是开发对增删改查的一种缩写(create,read,update,delete)。 在技术的演变过程中,为了更快更好的增删改查,有一些大牛开发出了一系列的ORM框架,比如C#里最出名的EntityFramework、与Hibernate同源的NHibernate等等。 1.2 DDL数据定义语言,用户可以用来创建数据库、修改数据库属性、删除数据库,新建表、视图,修改表、视图,删除表、视图等。与DML不同的是,DDL操作的对象从数据转变成了承载数据的实体或者与操作数据的实体。 还有与DML不同的一点是,DDL更多的会使用 create、alter、drop等关键字(分别用来 创建、修改、销毁)。 1.3 方言如今的城市人们来自五湖四海,有的人用普通话,有的人还是一口流利的家乡话。与之相同的就是在数据库这个江湖里,各大门派都在标准SQL里添加了自己的东西,让SQL成了一个操持着五湖四海的方言的大家族。比如说微软的Transcat-SQL和PL/SQL。 2. 一些简单操作这里先简单介绍一下通用SQL下的操作: 2.1 创建数据库create database test;这是一个简单的创建数据库的SQL语句,这是标准SQL的一部分。效果就是创建一个名字为test的数据库,字符集等属性是系统的默认值。 当然,在SQL Server里可以通过以下方式指定字符集: create database 数据库名 DEFAULT CHARACTER SET gbk COLLATE gbk_chinese_ci; -- 使用gbkCREATE DATABASE 数据库名 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; -- 使用utf8这是在开发过程中最常用的创建数据库方式。 2.2 创建表数据表是数据库里最重要的一个实体,我们大概演示一下如何通过sql语句创建一个表: create table demo( [key] int identity primary key , [name] varchar(20))goSQL 创建表的格式如下: ...

June 1, 2020 · 1 min · jiezi

C-数据操作系列-0-序言

0. 前言在上一个系列中,我们初步浏览了一下C#的基础知识。这句话的意思就是C#基础知识系列完结了,撒花。当然,并不是因为C#已经讲完了。正是因为我们轻轻地叩开了那扇门,才能看到门后面那瑰丽的世界。那么,门后面有什么?就让我在后续的篇幅里,带着大家一起浏览吧。 0.1 C# 能做什么之前在开发工具篇大概为大家介绍了.net 分的方向,.net framework,.net core,mono,UWP 这四个。严格讲这不是技术区分的方向,而是基于SDK的区分。 说起能完成的功能,接下来给大家看一个图: 这是微软官网对.net能做的事情一个整体的描述。当然,其中某些方向暂时只能在Visual Studio上开发,所以需要Windows系统。当然了,并不是一直都只能在Windows下开发。微软正在一步一步的迁移到.net core或者说是.net standard(标准)上。 说到这里,重新介绍一下.net standard和.net framework以及.net core的区别吧。 .net standard也叫 dotnet 标准,是一套正式的.net API规范,进一步提高.net生态的一致性。而.net core正是在.net standard体系下的一个产物。 所以我们大概总结一下C#能做什么吧: 网站桌面应用游戏微服务应用手机APP人工智能物联网嗯,基本是涵盖了互联网绝大多数的项目类别,所以C#的前景还是可以的。 0.2 什么是数据库数据库的英文名字是Database,是指按照数据结构来组织、管理数据的仓库。而我们常说的数据库还有另外一种意思,指数据库管理系统,也就是 Database Management System,用来高效地管理、获取数据。 所以,我们平时在使用数据库的时候,会同时搭配数据库管理系统进行。当然,对于一个开发而言,并不需要精通数据库管理系统,这部分的工作属于DBA(Database Administrator,数据库管理员)的。 1. 常用数据库很多时候说到数据库的时候,其实一般指的都是关系型数据库。近年来,因为高并发和大数据时代的到来,关系型数据库无法很好地满足需求,于是大牛们研究出了非关系型数据库。 1.1 关系型数据库关系型数据库(Relational Database),是指使用关系模型来组织数据的数据库,最大的特征就是以行的形式表示实体,以列的形式表示实体的字段,一张表为一组实体,多张表联合起来就组成了一个数据库。 这里简单介绍一下 关系型数据库的几大巨头: 1. Microsoft SQL Server: 微软开发的数据库,早期版本只支持Windows环境,而且安装简单,性能和维护相对不错,然后被中小企业所接受并使用。在前几年,微软为Linux开发了对应的版本,甚至增强了企业级性能。在SQL Server2019之前的版本,SQL Server对应的管理程序 SQL Server Management Studio 是与数据库安装镜像一起的,可以在安装数据库的时候直接安装。在2019,则取消了SQL Server Management Studio 与安装包的挂钩,用户就可以自行安装SQL Server Management Studio程序。 这是微软给出的宣传亮点。 MS SQL Server是收费的,而且正版的费用不是很便宜,但对于普通开发而言,有科学方式(微软一概在这方面特别大方)来免费试用旗舰版。 ...

June 1, 2020 · 1 min · jiezi

C-基础知识系列-17-小工具优化

0. 前言不知道有没有动手能力强的小伙伴照着上一篇的内容写过程序呢?如果有的话,应该会在使用的时候发现以下几个问题: 每次启动都需要经过漫长的时间去遍历磁盘里的文件目录因为数据是用的字典保存的,所以会消耗大量的内存空间不能多次查询现在我们就针对这些问题,让我们的小工具实用起来。 1. 分析与实现在动手之前,我们先分析一下问题。在实际开发之前,无论是接到什么需求都要先仔细分析一下,确定好方案再动手方为开发的正道。嗯,没毛病。因为开发过程中跟产品对线、跟客户对线要占整个项目的一半左右时间。好了,不废话了。继续: 遍历文件目录的时间过长,那么我们是不是可以用异步并发去遍历呢? 数据用字典保存会消耗内存空间,那么我们是不是可以用其他的方式保存呢? 不能多次查询,是不是可以使用循环,然后设置一个退出条件? 1.1 C#的异步/并发实现在C#里,异步和并发的实现是依据线程、任务来实现的。在之前《C# 基础知识系列- 12 任务和多线程》里大概介绍了一下线程和任务,我们知道线程本身是没法返回数据的,它与主线程进行数据交互的过程十分需要注意线程安全。而任务可以返回数据,不需要像线程一样小心翼翼地与主线程进行数据交互。任务有一个优点,它比线程更轻量,所以在当前环境下我们可以试试任务。 当然,线程也有优点,那就是线程的运行环境相对更封闭一点,它能完成一个长的大型运算。 那么继续上一篇的内容,先引用 : using System.Threading.Tasks;先提取一组根据可枚举目录集合创建任务组并取得结果的方法: public static Dictionary<string,List<string>> OverDirectories(IEnumerable<DirectoryInfo> directories){ var tasks = directories.Select(dir => Task.Run(()=>OverDirectories(dir))).ToArray(); Task.WaitAll(tasks);// 这行的意思是等待所有任务完成 return Concat(tasks.Select(t=>t.Result).ToArray());}然后改造原有的OverDirectories方法: public static Dictionary<string,List<string>> OverDirectories(DirectoryInfo rootDirectory){ Console.WriteLine($"正在遍历目录:{rootDirectory.FullName}"); var dict = new Dictionary<string, List<string>>(); IEnumerable<FileInfo> files = new List<FileInfo>(); try { files = rootDirectory.EnumerateFiles(); } catch(Exception e) { Console.WriteLine($"错误信息:{e}");//打印错误信息 } foreach(var file in files) { var key = Path.GetFileNameWithoutExtension(file.Name); if(!dict.ContainsKey(key)) { dict[key] = new List<string>(); } dict[key].Add(file.FullName); } try { var dirs = rootDirectory.EnumerateDirectories(); return Concat(dict, OverDirectories(dirs));// 采用线程版的方法进行遍历 } catch (System.Exception e) { Console.WriteLine($"错误信息:{e}");//打印错误信息 } return dict;}1.2 数据复用理想状态下,我们的数据应该是保存在数据库的,但因为数据库的操作是在下一系列的教程中,所以目前只能舍弃这个设想。 ...

May 31, 2020 · 2 min · jiezi

C-基础知识系列-17-实战篇-编写一个小工具1

0. 前言这是对C# 基础系列的一个总结,现在我们利用之前学到的知识做一个小小的工具来给我们使用。 如果有看过IO篇的小伙伴,应该有印象。当时我提过一个场景描述,我们在平时使用系统的时候,经常会为了找某个文件的位置而烦恼。那么我们现在尝试写一个控制台程序来帮助我们找文件的具体位置。 1. 分析好,大家应该初步了解了需求内容。然后让我们来做一个简单的需求分析: 简单分析一下需求包括哪些功能点规划各个功能点的实现方式嗯,理论上讲还有一大堆的步骤,但因为是个练手的小项目就不扯那么多没用的了。简单来讲就是,分两步: 抓取系统可以访问的所有文件,并保存其全路径根据输入的参数查询文件的全路径需求分析完了,然后寻找可以实现的技术,我们现有的技术有IO、文件/路径操作、任务模式等技术,那么可以供我们选择的技术一目了然了:通过文件/目录/路径API访问所有的文件目录,使用字典保存,然后使用Linq查询文件所在目录。 OK,需求分析完了,技术也确认了。那么我们现在开始吧,小伙伴们跟紧了哦,车速不快的。 2. 开始这里简单演示一下如何用Rider和VSCode、Visual Studio2019创建项目。 2.1. 创建一个名为 FileFinder的项目a.使用Rider: 点击箭头所指方向: 先在左侧选择Console Application,然后修改 Project name,最后修改 Solution Directory为自己的目录: 然后点击 Create,创建完成结果如下: Rider创建项目的步骤在Windows、Linux、Mac三个系统都是一样的。 b. 使用VS Code创建项目 使用VS Code创建项目与Rider和Visual Studio有所不同,步骤比较繁琐: 先在合适的文件夹下创建一个fileFinder目录,并在fileFinder目录下打开命令行,输入以下命令: dotnet new sln -n fileFinder # 创建一个名为 fileFinder 的解决方案dotnet new console -n fileFinder # 创建一个名为 fileFinder的控制台程序dotnet sln add fileFinder # 把 fileFinder的项目添加到fileFinder的解决方案里最终结果应该是这样的: c.使用 Visual Studio 选择【创建新项目】注意框住地方的选择,选控制台程序,然后点击下一步填写项目名称、路径,点击创建 2.2 开始编写程序现在我们创建完成了一个项目,然后可以开始编写我们的程序了。 首先创建一个遍历所有目录的方法: ...

May 30, 2020 · 2 min · jiezi

C-基础知识系列-16-开发工具篇

0. 前言这是C# 基础知识系列的最后一个内容讲解篇,下一篇是基础知识-实战篇。这一篇主要讲解一下C#程序的结构和主要编程工具。 1. 工具工欲善其事必先利其器,在实际动手之前我们先来看看想要编写一套C#程序需要做哪些准备吧。 1.1 选择C# 的sdk在之前的某个时间点分为了三个方向: .net framework 4.X.net coremonoUWP有人可能问了,.net和C#是什么关系。首先需要明确一个概念,C#是一门编程语言,.net是一个CLR,即公共语言运行库。这部分概念比较抽象,不过我这么说大家可能会理解里面的关系了:C#是.net支持的一门语言,于此同时.net还支持F#,Visual C++等。也就是说,.net是一个平台,而C#是运行在这个平台上的语言。 不过,通常上因为.net支持的其他语言并不如C#出名,所以很多人就忽略了两者之间的区别,有时候也用.net代指C#了。 讲了这么多废话,回到之前。.net分了三个方向,第一个方向是沿用之前版本,继续深耕Windows环境。.net core是微软为了跨平台战略而开发的,目前支持 Windows/Linux/Mac等系统。后续的文章也将基于.net core进行。Mono是早期在Linux环境中支持.net framework的一套SDK,后来微软把这项技术合并到了.net发展战略里了,现在支持Android、Mac应用开发。最后一个是UWP,通用Windows平台,据说是为了物联网研究的。 嗯,因为我的工作方向是 BS,也就是做网站开发的,再加上需要接触一些Linux的系统,所以整体就在.net core这个框架下进行后续开发和工作了。换句话说,整个C# 系列都是在.net core上运行的。 1.2 开发工具在选择了.net core之后,我们就要选择一个适合我们的开发工具了。 1.2.1 Visual Studio先放一张Visual Studio 2019的图。 这是到目前(2020年05月05日)为止,微软开发的最强大的编译器。在编译器界,Visual Studio有着“宇宙第一编译器”的美名。当然最早是因为其安装包十分巨大,动则2~3G的全量安装,再加上其昂贵的正版授权价格,所以被称为第一编译器。后来随着微软更改了安装方式,改为在线安装然后模块化安装,让程序员可以用哪些装哪些,减少了安装包的大小,同时进一步增强了作为编译器的功能,添加了Community版本(社区版,免费的)之后,第一编译器就成了名副其实的美名。 下图是 Visual Studio支持的功能: 具体的安装就不演示了,这部分网上教程也比较多。如果有疑问的话,可以留言或者私信我哦。 当然了,即使是旗舰版,Visual Studio2019在网上也有很多激活码 ,不过对于公司的话,这部分可能会有法律风险。个人学习研究的话,没事。笑XD1.2.2 Visual Studio Code嗯,Code是微软开发的另一个神器,凭借着其轻量、开源和免费这几大特性迅速占领了开发者们的内心。再加上其丰富的插件支持,更是让人欲罢不能。 Code支持跨平台,Windows/Linux/Mac都支持。下图是示意图: 1.2.3 Jetbrains Rider这是捷克一家软件公司开发的编译器,支持跨平台。语言的智能提示比VS好一点,而且也轻一点。这是它功能特定的宣传图: 可以说功能非常强劲,当然了也是收费的。目前市面上没有很稳定的科学方法。咳咳,我啥也没说。 1.2.4 总结如果是初学者,我建议使用Visual Studio ,不愧与第一编译器的美名。如果是在Linux环境的话,初学者建议试试Rider。 当然了,对于极客或者Linux环境但预算不高的小伙伴可以试试VS Code,搭配好插件功能也不比另外的编译器差到哪里去。 注:Rider单个软件的订阅是 139美元一年(首年),不过据说有免费的方式。关于选择编译器的问题,如果是Linux环境,需要事先安装 .net core sdk。这部分内容请参照微软的官方,搜索关键词:net core ...

May 30, 2020 · 1 min · jiezi

C-基础知识系列-14-IO篇-流的使用

0. 前言继续之前的C# IO流,在前几篇小短片中我们大概看了下C# 的基础IO也对文件、目录和路径的操作有了一定的了解。这一篇开始,给大家演示一下流的各种操作。以文件流为例,一起来看看如何操作吧。 注:之前更新了一篇《Spring Cloud 实战日记》,这是一个新的系列,有兴趣的小伙伴可以从我的账号首页进去看看。1. 简单的IO流读写文件先来看一部分代码: class Program{ static void Main(string[] args) { var directory = Directory.GetCurrentDirectory(); var program = File.Open("../../../Program.cs", FileMode.OpenOrCreate); // program = File.Open("Program.cs", FileMode.OpenOrCreate); var buffers = new byte[1024];// 创建一个8k的缓存区 var list = new List<byte>(); while(true) { int length = program.Read(buffers, 0, buffers.Length); if(length <=0) { break; } list.AddRange(buffers.Take(length)); } program.Close(); Console.WriteLine(list.Count); }}到目前为止,打开了一个流读取当前程序源文件,每次读取到一个字节数组里,然后将数据放到list集合里,在读取完成后关闭这个流。虽然以上流并没有太多意义,但是基本演示了一下流的读取操作。 注意到注释的那行代码和上一行代码的区别吗?在编译阶段,Directory.GetCurrentDirectory()表示源文件所在目录;在运行阶段,表示程序编译完成的DLL所在目录。 输出结果: 以上通过文件流演示了如何读取一个文件,那么我们来简单看看如何通过流写文件: class Program{ static void Main(string[] args) { var directory = Directory.GetCurrentDirectory(); var program = File.Open("Program.cs", FileMode.OpenOrCreate); var buffers = new byte[1024];// 创建一个8k的缓存区 var list = new List<byte>(); while(true) { int length = program.Read(buffers, 0, buffers.Length); if(length <=0) { break; } list.AddRange(buffers.Take(length)); } program.Close(); Console.WriteLine($"已读取:{list.Count}"); var tempr = File.Open("Program_01.cs", FileMode.OpenOrCreate); tempr.Write(list.ToArray(), 0, list.Count); tempr.Close(); }}以上方法通过读取当前源码文件,然后将数据写入到另一个文件中:”Program_01.cs“。如果运行无误的话,将会得到一个”Program_01.cs“文件。 ...

May 29, 2020 · 2 min · jiezi

Java-Spring-Cloud-实战之路01-框架选型

0. 前言这是一个新的系列,来源于工作中的一个需求,领导准备新开一个项目线路,要求使用Java,项目符合现有主流技术,并要求对并发量有一定的承受能力 ,支持扩展。我和公司的几个小伙伴一起沟通了一下,这不就是标准的Spring Cloud微服务的系统架构吗。 之前读过小高之前发的文章的小伙伴也清楚我是C#开发,不过想当年我也系统学过Java,多年下来虽然手生,但也好歹没有落下技术。于是就揽下了这个活。毕竟学习是终身的。 不怎么简明的介绍了这个系列成立的原因,让我们言归正传,这个系列是我在搭建该项目过程的一个总结,如果后续开发中对框架有调整,也会在这个系列发布后续的更新。这也是为什么叫实战系列,而不是实战教程的原因。 那么,有兴趣的小伙伴,跟我一起来吧~ 1. 项目结构项目采用maven作为软件包管理工具,Spring boot+Spring Cloud作为项目基础架构,设有配置中心、服务发现中心、网关中心和链路追踪中心以及服务集群,其中服务集群之间添加链路熔断和负载均衡机制。 当然,目前参照了几个系统都按照这种逻辑搭建的框架,所以我们大致上也参考了这个模型。具体如下图: 2. 主要技术组件使用这里大概介绍一下,我在实践中选用的技术组件,选用这些技术没多少原因,很大程度上考虑到团队喜好以及后续维护的方便,还有就是官方团队的维护上考虑。 2.1 MavenMaven 翻译为"专家"、"内行",是 Apache 下的一个纯 Java 开发的开源项目,我主要用来进行包管理。老开发大多都知道如果一个项目使用了大量的三方包,如果没有统一的三方包管理就会出现三个人可能会引用四个版本的同一个包,这对于项目协同来说简直就是噩梦。所以Maven诞生了,从此Javaer有了一个进行包管理的神器。再次声明一下哈,maven不只是用来做包管理的,只是我使用的基本想法。当然还有编译、批量测试等功能。 2.2 Spring BootSpring Boot被誉为是Spring的一个跨时代发明,一度被认为是“不能更好了”的技术。Spring Boot解决了开发一个Web网站必须启动一个Tomcat或者其他的服务器才能进行调试的问题;又解决了Spring之前需要大量xml文件配置;Spring Boot集成了很多常见的Bean组件,在开发过程中只需要设置对应的参数值就可以了。 Spring Boot创建了Spring Boot maven的pom文件,这个文件里设置了大量java三方库的版本,依赖于一个Spring Boot的pom文件就可以统一的使用对应版本的java三方库。 2.3 Spring CloudSpring Cloud,嗯,怎么说呢。Spring Cloud可以说是一系列框架的有序集合,利用Spring Boot简化了基础设施的开发。Spring Cloud是实现微服务的一个有力的武器,我们利用Spring Cloud搭建服务发现注册、配置中心、消息总线、负载均衡、断路器和数据监控等。 总而言之,这是一个很神奇的项目。 2.4 NacosNacos,阿里巴巴又一个“KPI”产品。最开始的时候,很多人都说又是阿里的一个KPI产品。但实际上Nacos现在成长为业内一个很强的技术框架,它集成了服务发现、配置管理等功能。 以下是我从nacos官方扒的图,有兴趣的小伙伴可以看看。 2.5 Feign 服务接口化Feign的英文是“伪装、变形”等意思,是一种HTTP调用框架。它使Http调用变成了一种接口式的调用,而不用写一堆Http请求的代码。在Spring Cloud中,对Feign进行了加强,使得在各个服务之间可以通过定义Interface来调用其他服务的代码。与此同时,Spring Cloud Feign 集成了Ribbon作为负载均衡组件,Hystrix 作为链路熔断组件。 具体为什么要使用负载均衡和链路熔断可以参考该系列的Feign配置篇。 2.6 Zipkin之所以使用链路追踪系统,主要是为了跟踪各服务之间的调用信息。跟踪之后,可以通过链路信息确认各服务之间的调用关系;可以在发生错误的时候,通过链路追踪定位具体的错误;可以根据链路信息确认服务之间的负载是否均衡,是否满负荷是否超负荷等。 而Zipkin正是链路追踪系统中的佼佼者,项目中选型选中了Zipkin,让我们欢呼吧。 2.7 ElasticSearch在使用了链路追踪之后,每次都会启动大量的链路数据,所以就需要一个数据库,为了方便查找然后选中了ElasticSearch。那么什么是ElasticSearch呢? 暂且抛开官网中的Elastic Stack,因为我也不知道它说的是啥。简单来讲,ElasticSearch是一种文档型的数据引擎或者数据库。我们可以通过ElasticSearch实现全文检索功能。 2.8 其他项目还集成了Spring Boot Admin,计划集成ELK、jwt这些框架。不过业务暂时没有其他方面的需求,所以暂时没有加入其他组件。后续如有变更会更新到该系列中。 ...

May 29, 2020 · 1 min · jiezi

开源-Net-ORM-访问-人大金仓数据库

前言京人大金仓信息技术股份有限公司(以下简称“人大金仓”)是具有自主知识产权的国产数据管理软件与服务提供商。人大金仓由中国人民大学一批最早在国内开展数据库教学、科研、开发的专家于1999年发起创立,先后承担了国家“863”、“核高基”等重大专项,研发出了具有国际先进水平的大型通用数据库产品。2018年,人大金仓申报的“数据库管理系统核心技术的创新与金仓数据库产业化”项目荣获2018年度国家科学技术进步二等奖,产学研的融合进一步助力国家信息化建设。 随着华为、中兴事务,国产数据库市场相信是未来是趋势走向,纵观 .net core 整个圈子对国产人大金仓数据库的支持几乎为 0,今天我们使用 FreeSql ORM 来体验国产人大金仓数据库(虽然是拿pgsql源码修改的)。 整体来讲,人大金仓对 Oracle 语法有着 90% 的兼容性,但还有一些细节需要注意,FreeSql 对此做了优化进行了完美支持。 1、安装环境数据库服务器:KingbaseES V8 下载地址:https://www.kingbase.com.cn/i....NET版本:.net core 3.1 下载地址:https://dotnet.microsoft.com/...开发机器 :windows 10 ODBC驱动: 由于人大金仓数据库目前只能使用 ODBC 驱动访问数据库,如果成功安装了 KingbaseES V8,然后我们查看系统 ODBC,正常的话会显示如下: 2、创建项目我们以 console 类型项目试验 插入、删除、更新、查询 等功能,创建控制台项目,使用命令: dotnet new console dotnet add package FreeSql.Provider.Odbc --version 1.6.0-preview0102dotnet add package FreeSql.Repository --version 1.6.0-preview0102 3、创建实体模型using System;using FreeSql.DataAnnotations;public class User{ [Column(IsIdentity = true)] public long Id { get; set; } public string UserName { get; set; } public string PassWord { get; set; } public DateTime CreateTime { get; set; }}4、初始化 ORMstatic IFreeSql fsql = new FreeSql.FreeSqlBuilder() .UseConnectionString(FreeSql.DataType.OdbcKingbaseES, "Driver={KingbaseES 8.2 ODBC Driver ANSI};Server=127.0.0.1;Port=54321;UID=USER2;PWD=123456789;database=TEST") .UseMonitorCommand(cmd => Trace.WriteLine($"线程:{cmd.CommandText}\r\n")) .UseAutoSyncStructure(true) //自动创建、迁移实体表结构 .UseNameConvert(NameConvertType.ToUpper) .Build();5、插入数据var repo = fsql.GetRepository<User>();var user = new User { UserName = "kingbase1", PassWord = "123" };repo.Insert(user); ...

May 28, 2020 · 1 min · jiezi

C-基础知识系列-14-IO篇-文件的操作-3

本篇继续前两篇内容,跟大家介绍一下Path类以及FileSystemInfo这个类的主要方法和属性。上文提到,在《C# 基础知识系列-IO篇》之文件相关的内容完结之后,会带领大家开发一个小工具-快速检索文件所在目录。 1.3. PathPath的中文名称有路径的意思,所以Path类就是路径类,C#把Path设置为工具类,路径的实例被区分为文件和目录了。以下是它的定义: public static class Path路径是描述文件和目录的位置的字符串,路径并不一定指向硬盘上,换句话说就是路径不一定是物理路径也有可能是虚拟路径或者网络路径。在不同的操作系统和平台上,路径有着不同的表现,所以Path类是对不同平台行为的统一抽象。具体的路径表示需要参照具体的系统表示形式。 那么我们先来看看Path为我们提供了哪些内容,让我们一睹为快: 1.3.1 字段public static readonly char AltDirectorySeparatorChar;public static readonly char DirectorySeparatorChar;这两个是特定系统下的目录分隔符,其中AltDirectorySeparatorChar表示正斜线(/),DirectorySeparatorChar 表示反斜线()。为什么说是特定系统下的目录分隔符呢,因为Windows环境对两种分隔符都支持,但是Unix和类Unix系统只支持 / 作为目录分隔符。所以如果系统需要跨平台支持,则最好使用 AltDirectorySeparatorChar作为目录分隔符来使用。 public static readonly char PathSeparator;这个字段返回在环境变量中分隔路径字符串的平台特定的分隔符。Windows中返回一个分号(;),其他平台可能会有不一样的表现。 public static readonly char VolumeSeparatorChar;这个表示卷分隔符,是个很有意思的特定。对于Linux系统来说并没有类似于Windows一样的卷,所以该字段会返回一个/ ,而Windows中例如: D:Temp 这个目录则会返回冒号(:)。 1.3.2 方法介绍完了字段,我们来看看Path给我们提供了哪些方法吧。 先从最常用的说起吧: public static string Combine (params string[] paths);public static string Combine (string path1, string path2);public static string Combine (string path1, string path2, string path3);public static string Combine (string path1, string path2, string path3, string path4);这一组方法用来拼接路径,除第一个参数外,每个参数都应当是相对于之前参数拼接结果路径的相对路径。如果后续出现了绝对路径,那之前计算出的路径信息则会全部抛弃,重新计算。 ...

May 28, 2020 · 2 min · jiezi

C-基础知识系列-14-IO篇-文件的操作

0. 前言本章节是IO篇的第二集,我们在上一篇中介绍了C#中IO的基本概念和一些基本方法,接下来我们介绍一下操作文件的方法。在编程的世界中,操作文件是一个很重要的技能。 1. 文件、目录和路径在开始操作之前,先大概讲解一下基本概念。在计算机系统中,文件是以硬盘为载体存储在计算机上的信息集合。文件通常会有一个后缀名,表示文件格式(当然,通常的另一个含义就是可能没有)。我们最常见到的图片文件,后缀有jpg/png/gif这些常见的;文本文件为txt等。 目录,不严谨的来讲可以用文件夹代替。不过严格来说,目录指的是文件所在的文件夹以及文件夹的位置这些信息的集合。 路径是指文件或文件夹所在的位置的字符串表示,有相对路径和绝对路径,有物理路径和网络路径等一系列这些划分。 相对路径指的是,相对程序所在目录目标文件所在的目录路径绝对路径指的是从系统或者网站的目录起点开始文件所在的位置,也就是说无论程序在哪都能通过绝对路径访问到对应文件物理路径是指文件在磁盘的路径,划分依据与之前的两种并不一致,所以不是并列关系网络路径是指网络或文件是在网络服务上部署的,通过URI访问的路径信息好了,基本概念介绍到这里,让我们来看看如何实现C#操作文件吧。 1.1 File和FileInfoC# 提供了两个访问文件的入口,File和FileInfo这两个类。有人可能要迷惑了,为啥要提供两个呢,这两个又有啥子不一样的呢?别急,让我们来一起看一看吧。 我们先来观察一下两个类的声明方式有什么不一样的: public static class File;public sealed class FileInfo : System.IO.FileSystemInfo;我们忽略突然冒出来的FileSystemInfo,只需要明白它是FileInfo的基类即可。 通过两个类的声明方式,可以看出File是一个工具类,而FileInfo则是文件对象。所以,File更多的用在快速操作文件并不需要长时间多次使用同一个文件的场景,而FileInfo则适合同一个文件的多次使用。 1.1.1 File工具类我们先来看下File支持哪些操作: a.文件读取 public static byte[] ReadAllBytes (string path);public static string[] ReadAllLines (string path);public static string[] ReadAllLines (string path, System.Text.Encoding encoding);public static string ReadAllText (string path);public static string ReadAllText (string path, System.Text.Encoding encoding);public static System.Collections.Generic.IEnumerable<string> ReadLines (string path);先从名称上分析方法应该是什么,应该具有哪些功能? ReadAllBytes以二进制的形式一次性把文件全部读出来ReadAllLines打开文本文件,将文件内容一行一行的全部读出来并返回ReadAllText打开文件,并将文件所有内容一次性读出来ReadLines 这是一个新的方法,根据返回值和方法名称,可以判断它应该与ReadAllLines有着类似的行为ReadLInes和ReadAllLines的区别: ReadAllLines返回的是字符串数组,所以该方法会一次性将文件内容全部读出ReadLines返回的是一个可枚举对象,根据之前在Linq系列和集合系列的知识,我们能判断出,这个方法不会立即返回数据所以我们很轻易的就能得出,ReadAllLines不会过久的持有文件对象,但是不适合操作大文件;ReadLines对于大文件的操作更擅长一些,但是可能会更久的持有文件 b.写入文件 public static void AppendAllLines (string path, System.Collections.Generic.IEnumerable<string> contents);public static void AppendAllLines (string path, System.Collections.Generic.IEnumerable<string> contents, System.Text.Encoding encoding);public static void AppendAllText (string path, string contents);public static void AppendAllText (string path, string contents, System.Text.Encoding encoding);public static void WriteAllBytes (string path, byte[] bytes);public static void WriteAllLines (string path, string[] contents, System.Text.Encoding encoding);public static void WriteAllText (string path, string contents);public static void WriteAllText (string path, string contents, System.Text.Encoding encoding);来,我们简单看一下这几个方法具体作用: ...

May 28, 2020 · 3 min · jiezi

C-基础知识系列-14-IO篇之入门IO

0. 前言在之前的章节中,大致介绍了C#中的一些基本概念。这篇我们将介绍一下C#的I/O操作,这将也是一个小连续剧。这是第一集,我们先来简单了解一下C#中的I/O框架。 1. 什么是I/OI/O 的全称是input/output,翻译过来就是输入/输出。对于一个系统或者计算机来说,键盘、U盘、网络接口、显示器、音响、摄像头等都是IO设备。那么,对于一个程序I/O又是什么呢? 对于程序而言,I/O就是与外界进行数据交换的方式。借用一句广告词,程序不生产数据,只是数据的搬用工。当然,正如XX还需要对水进行过滤、消毒等工序一样,程序也要对数据进行运算,所以也不完全算是搬用工,严格来讲是加工厂。那么,I/O就是工厂的原料提供商和成品销售商。 在C# 中,I/O体系整体分为三个部分,后台存储流、装饰器流、流适配器,具体划分如下图所示: 在流与流之间,都是采用字节数据进行交换,所以可以得到一个简单的结论,I/O在程序中表现为字节流,换句话说I/O就是将各种数据转成字节的工具。 3. Stream 基类C#中,所有流都是继承自Stream类,Stream类定义了流应该具有的行为和属性,使得开发人员可以忽略底层的操作系统和基础设备的具体细节。C#对流的处理忽略了读流和写流的区别,使其更像是一个管道,方便数据通信。流涉及到三个基本操作: 读取 - 将数据从流中传输到数据结构中写入 - 将数据从数据源写入流中查找 - 对流中操作的当前位置进行查找和修改因为流的特性,可能并不是所有的流都支持这三种操作,所以Stream提供了三个属性,以方便确认流是否支持这三种操作: public abstract bool CanRead { get; } // 获取指示当前流是否支持读取的值public abstract bool CanWrite { get; } // 获取指示当前流是否支持写入功能的值public abstract bool CanSeek { get; } // 获取指示当前流是否支持查找功能的值以上这三个属性均由子类根据自身特性确认是否支持读取、写入、查找,可能三个属性不会都为true,但绝对不会都为false。 下面是一些常见的流: FileStream 用来操作文件的流MemoryStream 操作内存的流BufferedStream 缓存流,用来增强其他流的操作性能NetworkStream 使用网络套接字进行操作的流PipeStream 通过匿名和命名管道进行读取和写入CryptoStream 用于将数据流链接到加密转换4. 操作C# 中I/O的操作都属于System.IO这个命名空间,在这个命名空间中C# 定义了文件相关的类、各种流、装饰器流、适配器以及其他一些相关的结构体。在以System.IO开头的命名空间中,C#对IO进一步扩展,并提供了流压缩和解压缩(System.IO.Compression),搜索和枚举文件系统元素(System.IO.Enumeration),提供用于使用内存映射文件的类(System.IO.MemoryMappedFiles)等内容。 我们先略过之后篇幅会介绍的内容不提,先来看一下Stream类里重要的属性和方法: 1. 流里数据的长度 public abstract long Length { get; }当Stream对象的CanSeek为true时,也就是流支持搜索的时候,可以通过这个属性确认流的长度,也就是有多少个字节的数据。 ...

May 27, 2020 · 1 min · jiezi

C-基础知识系列13-常见类库三

0. 前言在《C# 基础知识系列- 13 常见类库(二)》中,我们介绍了一下DateTime和TimeSpan这两个结构体的内容,也就是C#中日期时间的简单操作。本篇将介绍Guid和Nullable这两个内容。 1. Guid 结构Guid(Globally Unique Identifier) 全局唯一标识,是一种由算法生成的二进制长度为128位的字符串,但字符串的长度是36其中32位16进制的数字和四个连接符。其作用是用来表示全局唯一标识,当多个系统或者数据量大的时候,用来做唯一标识,比如说数据库的主键。Guid并不是C#独有的,所以可以放心使用,不用担心跟其他系统交互时遇到对方无法识别的尴尬局面。 Guid应用非常广泛,如果有查看过Windows系统注册表的同学应该见过如下类型的数据:efa4bcc8-b293-48d5-9278-924b9c015b97 ,这就是Guid。Guid甚至被Windows用作组件注册,网络接口标识等。 简单来讲,Guid适合需要不重复标识的场景。 1.1 创建一个GuidGuid的创建非常简单直接通过Guid.NewGuid(),示例: class Program{ static void Main(string[] args) { Guid guid = Guid.NewGuid(); Console.WriteLine(guid); }}多次运行以上代码将会出现不同的结果,这是我的一次运行结果: 66168bfa-8c3b-45ce-a340-da99c668fca8到这里,创建Guid就可以认为达到目的了,但是我们一起来看下Guid有哪些构造函数吧: public Guid (byte[] b); 用长度为16的字节数组初始化一个Guid,其中Guid的值与字节数组相关。(根据定义来理解,C#会将字节数组b转换为128位的二进制数据,再转换为字符串格式)。 示例: class Program{ static void Main(string[] args) { var bytes = new byte[16] { 12,23,59,29,93,22,22,19,45,37,53,38,54,46,33,11 }; Guid guid = new Guid(bytes); Console.WriteLine(guid); }}多次运行,打印结果都是以下内容: 1d3b170c-165d-1316-2d25-3526362e210b以上可以得知,是通过一个字节数组创建一个Guid元素,这个元素的值就是这个字节数组的值。 继续介绍第二个构造方法,通过格式化的字符串创建: public Guid (string g);g表示Guid数据,有以下几种格式: dddddddddddddddddddddddddddddddd 表示32个连续数字dddddddd-dddd-dddd-dddd-dddddddddddd 表示 8、4、4、4 和 12 位数字的分组,可以用小括号和大括号包裹起来{0xdddddddd, 0xdddd, 0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}}8、4 和 4 位数字的分组,和一个 8 组 2 位数字的子集,每组都带有前缀“0x”或“0X”,以逗号分隔该方法接受以上格式的Guid字符串,以下是示例: ...

May 26, 2020 · 2 min · jiezi