abp(net core)+easyui+efcore仓储系统——ABP总体介绍(一) - DotNet菜园 - 博客园

mikel阅读(2382)

来源: abp(net core)+easyui+efcore仓储系统——ABP总体介绍(一) – DotNet菜园 – 博客园

     在前面我已经介绍了ASP.NET MVC、ASP.NET Razor、WEBAPI等技术。我准备通过一个实践项目来整体应用一下之前介绍的技术。本系列是介绍基于ABP+EasyUI的Web开发框架的形成过程,期间包括一些ABP的介绍,ASP.NET MVC Core技术、EasyUI技术、JQuery技术、WebAPI 技术,以及一些我对整体框架改造的基础性东西,力求更加稳定、通用、高效、简洁,最少的代码做最多的事情。我所使用的ABP版本是4.3,是2019年3月14日的版本。

一、ABP 的由来

“DRY——避免重复代码”是一个优秀的开发者在开发软件时所具备的最重要的思想之一。我们在开发企业WEB应用程序时都有一些类似的需求,例如:都需要登录页面、用户/角色管理、权限验证、数据有效性验证、多语言/本地化等等。一个高品质的大型软件都会运用一些最佳实践,例如分层体系结构、领域驱动设计、依赖注入等。我们也可能会采用ORM、数据库迁移(Database Migrations)、日志记录(Logging)等工具。

从零开始创建一个企业应用程序是一件繁琐的事,因为需要重复做很多常见的基础工作。许多公司都在开发自己的应用程序框架来重用于不同的项目,然后在框架的基础上开发一些新的功能。但并不是每个公司都有这样的实力。假如我们可以分享的更多,也许可以避免每个公司或每个项目的重复编写类似的代码。作者之所以把项目命名为“ASP.NET Boilerplate”,就是希望它能成为开发一般企业WEB应用的新起点,直接把ABP作为项目模板。

二、ABP是什么?

ABP是为新的现代Web应用程序使用最佳实践和使用最流行工具的一个起点。可作为一般用途的应用程序的基础框架或项目模板。它的功能包括:

服务器端:

  • 基于最新的.NET技术 (我使用的是ASP.NET Core MVC、Web API 2、C#
  • 实现领域驱动设计(实体、仓储、领域服务、领域事件、应用服务、数据传输对象,工作单元等等)
  • 实现分层体系结构(领域层,应用层,展现层和基础设施层)
  • 提供了一个基础架构来开发可重用可配置的模块
  • 集成一些最流行的开源框架/库,也许有些是你正在使用的。
  • 提供了一个基础架构让我们很方便地使用依赖注入
  • 提供Repository仓储模式支持不同的ORM(已实现Entity Framework 、NHibernate、MangoDb和内存数据库)
  • 支持并实现数据库迁移(EF 的 Code first)
  • 模块化开发(每个模块有独立的EF DbContext,可单独指定数据库)
  • 包括一个简单的和灵活的多语言/本地化系统
  • 包括一个 EventBus来实现服务器端全局的领域事件
  • 统一的异常处理(应用层几乎不需要处理自己写异常处理代码)
  • 数据有效性验证
  • 通过Application Services自动创建Web Api层
  • 提供基类和帮助类让我们方便地实现一些常见的任务
  • 使用“约定优于配置原则”

客户端:

  • Bootstrap、React、AngularJs、JQuery、Vue和其他JS库: JQuery.validate、jQuery.form、jQuery.blockUI、json2等
  • 为单页面应用程序(AngularJs、Vue 、React)和多页面应用程序(Bootstrap+jQuery)提供了项目模板。
  • 自动创建JavaScript 的代理层来更方便使用Web Api
  • 封装一些JavaScript 函数,更方便地使用ajax、消息框、通知组件、忙状态的遮罩层等等

 除ABP框架项目以外,还开发了名叫“Zero”的模块,实现了以下功能:

  • 身份验证与授权管理(通过ASP.NET Identity实现的)
  • 用户&角色管理
  • 系统设置存取管理(系统级、租户级、用户级,作用范围自动管理)
  • 审计日志(自动记录每一次接口的调用者和参数)

 

三、ABP不是什么?

ABP 提供了一个应用程序开发模型用于最佳实践。它拥有基础类、接口和工具使我们容易建立起可维护的大规模的应用程序。

它不是RAD工具之一,RAD工具的目的是无需编码创建应用程序。相反,ABP提供了一种编码的最佳实践。

它不是一个代码生成工具。在运行时虽然它有一些特性构建动态代码,但它不能生成代码。

它不是一个一体化的框架。相反,它使用流行的工具/库来完成特定的任务(例如用EF做ORM,用Log4Net做日志记录,使得Castle Windsor作为赖注入容器, AngularJs 用于SPA 框架)。

四、进入官网创建项目模板

  1. 在浏览器中输入https://aspnetboilerplate.com/Templates。然后依次按下图选择:
  2. 下载提示,如下图。

五、开发工具

Visual Studio 2017(以上)

SQL Server 2012  以上

六、启动项目

      1.使用Visual Studio  2017打开我们刚才在官网上创建的项目“ABP.TPLMS”,Visual Studio 2017会自动还原Nuget包,如下图。

      2. 设置“ABP.TPLMS.Web.Mvc”为启动项目,如下图。

      3.打开“appsettings.json”文件,修改连接字符串,如下图。(因为我本地装的SQLServer是实例是.\SQLexpress,所以需要手动修改server。)

      4. 在Visual Studio 2017中,选择“菜单>工具>NuGet包管理器>程序包管理器控制台”,打开程序包管理器控制台。 如下图。

      5.在程序包管理器控制台中的“默认项目”选择“ABP.TPLMS.EntityFrameworkCore”项目,并执行Update-Database,以创建数据库。如下图。

 

      6.在Visual Studio 2017中按F5运行应用程序,然后在浏览器中显示的登录页面中使用账号admin/123qwe,登陆即可。如下图。

      7.在正常登录之后,浏览器中显示如下图。

 

      8.默认是英文,可以选择其他语言。如下图1,图2。

 

图1

 

图2

小强开饭店-从单体应用到微服务 - detectiveHLH - 博客园

mikel阅读(1659)

来源: 小强开饭店-从单体应用到微服务 – detectiveHLH – 博客园

本篇博客通过小强开饭店的通俗易懂的故事,带你了解后端服务是如果从单体应用演变到微服务的。如果有说的不对的地方,欢迎各位大佬强势怼。

小强开饭店

有一天,小强为了早日奔赴小康生活,打算开一个饭店来帮他快速的实现这个目标。

饭店开业了

于是他盘下了一个店面,一顿装修之后,雇了一个厨师,便开业了。

饭店生意变好了

刚刚开业那段时间还好,店里的人虽然多,但是都还能应付的过来。

小强请的厨师手艺很好,再加上小强经营得当,宣传的也不错,慢慢的店里的生意越来越好。

慢慢的,顾客越来越多。很多时候厨师都忙不过来,大家只有排队在外面等着。渐渐的有些顾客变得十分不耐烦,等不下去了就走了,然后给了这家店差评。这种情况愈演愈烈,小强看到这不是个办法啊,得做点什么。

招聘厨师

小强下了血本,又另外聘请了几位厨艺很好的厨师。

有了这些厨师的加盟,虽然客人很多,饭店的经营也还是能够勉强的应付的来。口碑也慢慢的由差变好。随着口碑的变好,慕名而来的也随之越来越多。

生意火爆

随着顾客越来越多,即使厨房的厨师已经招聘满了,都还是应付不过来。

于是厨师也变成了暴躁的厨师。有的时候因为太忙了还罢工不干了。还得小强去苦口婆心的劝。小强心想这也不是个办法,再这么下去口碑又得下去。于是小强摇身一变,变成了强老板。

强老板开了分店

强老板拿着开饭店赚的钱,在城里的很多地方开了分店,十分的膨胀。这样一来,客人不用大老远的跑到那一家店去了,可以选择离自己近的店。很快,原来的那家生意也渐渐的恢复正常,各个分店的业绩也有所提高。

但是随着强老板的强势宣传,以及顾客之间的自传播,这个参考被越来越多的人知道了。但是由于顾客分散,每家店的火爆程度都不同。有的店甚至陷入了跟最开始的店一样的境地,大量的顾客排队。但是有的店的生意却又十分冷清。

强老板心想,这肯定不行啊,这样下去早晚得血亏。于是强老板摇身一变,变成了强总。

强总开了个顾客中心

所有想去餐馆用餐的顾客都来这里,由强老板统一安排的大巴再送至各个分店。每辆车轮流的送至每一家分店。这样一来,就不存在某一家分店生意十分火爆而另外的店生意惨淡的情况了。

强总已达成奔赴小康的目标

读后感

其实这个想法是很久以前不知道在哪儿看博客的时候,看到一位大佬的类比,确实是忘了。而最近刚好在准备分享,所以就打算详细的以图文和故事的方式来让没有了解过这方面的人快速的了解一下。

其实我也纠结过要不要将里面类比概念的解释穿插到故事里,但是后面想了一下,这样应该会干扰到大家对故事本身的理解,从而达不到通俗易懂的效果。所以我将解释单独放在了最后面。

单个饭店

最开始的单个饭店其实就是一个App或者一个网站,来给用户提供服务。可以理解为前端,或者客户端。

单个饭店的厨师

而单个饭店中的厨师,其实就是后端,提供数据,提供服务。一个厨师就对应着一个后端服务的实例。

随着App的访问量越来越大,最初的单体应用已经无法扛住这么大的压力了。导致其他的用户进入系统时,系统无法正常的服务。就跟我们现在打开一个网站一样,凡是超过2-3秒没有反应就直接宣告它的死刑了,直接退出-卸载二连。

单个饭店的多个厨师

多个厨师则是相应的后端服务启动了多个实例,每个实例都是完全一样的,只不过是运行在不同的机器上或者不同的端口上。

每次的请求由这些实例来均摊,这样也的确能够暂时解决访问量大的问题。但是维护起来十分的麻烦,部署的流程也很繁琐。每次部署你得更新所有的实例,万一数量多,又在不同的机器上,很有可能因为操作失误引发线上的事故。而且有可能让老版本的服务兼容新版的前端或者客户端,造成不必要的BUG。

再退一万步,就算所有的实例都在同一个服务器上,万一真的访问量到了一定的量级,你得维护多少个实例啊。人工成本巨大。而且一不小心,一觉起来,本身没有问题的服务,因为一晚上发生了事件引发了热点,导致你的应用访问量剧增,增到超过你的所有实例能够承受的极限,服务挂了。

再退一万万步,就算你自己维护没有烦死,前端的兄弟可能早就收拾你了。你没有做请求分发的话,所有的服务器地址得由前端去维护。

分店

这里的分店指微服务中的一个服务的多个实例。与之前人工维护的多个实例不同,这个是由工具帮我们维护。

这里我拿Docker Swarm举个例子。在Portainer中,你新建了一个服务之后可以选择设置Replicas,也就是实例的数量,当然默认是一个。你可以起10个,20个,但是这里得考虑到你的服务是否支持这样做。如果你的服务不是无状态应用,就很难做到可以自动的做横向扩展。

分店的生意火爆

其实也是一样的,即使有很多个实例,你如果不能控制请求打到哪个服务上的话,某些实例承受的压力大了一样的会挂。

强总的顾客中心

顾客中心大家可以理解为网关。更具体点可以理解为Zuul。

你的服务有了网关之后,所有的请求都从网关走。根据以及配置的路由,网关可以判断到你想具体到哪个服务去。

然后就会从自己的服务集群中找到对应的服务,获取到所有的服务实例的服务器IP以及端口。前面说到有可能请求会集中到某几个实例上。而我们可以使用工具来解决这个问题。例如,使用Spring Cloud的核心组件Ribbon。

这个组件的作用是做负载均衡,它可以使所有到某个服务的请求,平均的分发到该服务的每个实例上去。从而避免某几个服务的请求超过其能承受的阙值。当然,Ribbon需要和Spring Cloud的其他核心组件相互协作的。

另外一个版本的故事

小强搞了个新闻App,用Spring Boot搭了一个后端,找人用React Native写了个App,就这样上线了。因为其内容和推广都还不错,所以受到了用户的喜爱。

但是随着访问量越来越大,服务器渐渐扛不住压力。有的用户进App之后甚至要5-6秒才有反应,而且慢的出奇。于是小强开始给服务尽量的无状态化,然后在一个服务器上启动了几个实例。

一段时间之后,访问量又增大了。小强只好硬着头皮,继续加实例数量,你强任你强,加实例我在行。

有一天,小强一觉起来,发现服务炸了…啊不是,是挂了。因为发生了一些事情引发了巨大的社会舆论,App的访问量剧增。导致新加的实例也没能扛住。

就这样,小强老实的开始了重构。使用Spring Cloud搭建了一个微服务集群,把服务拆分之后,给每个服务启动了几个实例。同时使用Eureka和Feign来进行服务之间的通信,使用Ribbon来做负载均衡。

就这样,这个App暂时稳定了下来。不过还有很多事情可以继续去做。

参考:

往期文章:

相关:

  • 个人网站: Lunhao Hu
  • 微信公众号: SH的全栈笔记(或直接在添加公众号界面搜索微信号LunhaoHu)

从搞笑到高效,构建敏捷团队的基础原则 - Worktile - 博客园

mikel阅读(2582)

来源: 从搞笑到高效,构建敏捷团队的基础原则 – Worktile – 博客园

翁云峰 –稿定科技敏捷教练,厦门敏捷社区组织者

在印度有这么一个神奇的团队,他们有5000名左右的员工,每天要运送20多万份餐,一份盒饭要经过3-4个人的手才能抵达目的地,交通工具只有火车,自行车,板车和双腿,没有任何单据,甚至都不需要客户填写地址。

在这样的状况下,每6百万次运送中只有1次错误,准时正确到达率却超过99.99999%,这远超六西格玛的标准。在业界,如果一个企业能达到 六西格玛,就说明它能接近完美地达成顾客要求。在这一点上,达巴瓦拉甚至远远超过了联邦快递等使用现代技术和工具的快递公司。

 

屏幕快照 2019-06-11 上午9.40.08.png
 

大家可能在想,能够把事情做到这么好,他们一定很贵吧?他们团队的管理水平这么高,是不是成员的基础素质很高?

答案却不是如此,这个团队基本上都是半文盲或者文盲,每个月的收入也很低,平均每人400-500人民币。

这个神奇的团队,叫做达巴瓦拉。

 

屏幕快照 2019-06-11 上午10.15.53.png
 

大家有没有注意到,外卖的每一个饭盒上都有编号?没有英文单词或者太复杂的词,只有一串编号而已(因为他们很多人都是半文盲,所以编号信息也力求简单)。这些彩色代码告诉这些外卖小哥饭盒来自何处,输送过程中经过了哪些火车站,最终要投递到哪个建筑物的哪一个办公室。这个代码就是他们的通讯协议,可以保证饭盒并准确无误的送达。如果出错了,是谁出了错可以非常精准被定义到。

他们获得成功的法宝是时间管理,简单的色彩分类体系和团队协作。

我们很多的研发团队,文化程度都很高,我们能不能做到这样的准时交付率?很难。我们的团队可以在发生问题的时候,能不能非常精确的定位问题和处理?也很难。

虽然达巴瓦拉是属于另外一个行业的案例,相信也会对我们软件研发有重要的参考意义。我想通过这个案例的分析提出一个关于团队协作的观点,也是我今天想谈的东西。

1-团队协作的境界

现在我们来看一张图,大家试着想一想,我们团队目前经常沟通的频道是哪一个?

 

屏幕快照 2019-06-11 上午9.46.50.png
 

我们大部分的时候,都是在公开象限里进行协作。而公开象限的大小,反映了团队协作中的“信息披露”和协作水平。

假如我们都在一个团队里,一般大家都很乐意谈隐私象限,因为你需要把你知道的跟别人进行沟通,让他们配合你。你需要贡献一些秘密,一些私人的信息,让别人更加了解你。

当你不太清楚你自己的时候,比如你不知道有哪些东西需要改善,你需要请求反馈。你不知道你的代码写的如何,这时候有个人跟你说你的代码写得还不错,他是在给你反馈,接触你的潜能象限,这样的人是教练。

教练在鼓励你做自我揭示,你在不断请求教练给你反馈,让你知道你的潜能是什么。

 

屏幕快照 2019-06-11 上午9.48.42.png
 

喜欢天文学的人应该都知道“熵增”这个概念。举个例子,大家觉得你家是PPT左边的样子还是右边的样子?如果是左边,那就特别好。如果你是右边的状态,怎么办?你需要整理。

大家有没有意识到,你的团队也可能是右边的这种状态?出了问题不知道原因是什么,效率很低不知道怎么改进,流程无法预估,交付总是看天气。我们需要做的事情是什么?教练除了帮你揭示自我帮你反馈之外,还需要帮你做整理,把过去无序的东西变得有序。梳理流程,梳理团队,梳理产出,暴露问题并推动问题的解决,这个过程是“反熵增”,防止协作系统陷入到混乱和无序中。

增强沟通,反熵增之后,我们希望团队协作达到什么样的境界呢?

 

屏幕快照 2019-06-11 上午9.50.23.png
 

我想要用八个字来总结,叫做“既定规则,无脑执行”。

规则是什么?规则就是做事的方法和标准,比如DoR(就绪的标准), DoD(完成的标准)和很多的working agreement(团队一起制定的工作公约)。

为什么是无脑执行?这里不是真的说在执行的时候,我们只需要找到一堆idiot来按部就班执行就行了。这里的意思是,当我们有了协作的规则和方法的时候,根本不需要占用大脑的带宽,不需要让团队在执行过程中耗费宝贵的计算资源,把有限的精力投入到最需要全神贯注的工作事项中去。

无脑执行的另外一个意思是,事情必须非常流畅,减少在执行过程中的摩擦,减少无谓的人力物力投入。

“以神御刀,不以目视刀。”
《庄子》

为了让协作更加顺畅,我建议大家可以参考这个“协作金字塔”。也就是教练,或者团队管理者,或者有志于改善团队协作的任何一个人,需要关注的一些要点。

 

屏幕快照 2019-06-11 上午9.49.49.png
 

我们需要定义一些规则和方法。

 

屏幕快照 2019-06-11 上午9.51.00.png
 

我们需要不断提高信息饱和度(提高团队的公开象限)。

 

屏幕快照 2019-06-11 上午9.51.39.png
 

让信息流可视化(提高公开象限;无脑执行)

 

屏幕快照 2019-06-11 上午9.52.14.png
 

及时反馈,及时校准。

 

屏幕快照 2019-06-11 上午9.52.41.png
 

2-敏捷教练是什么

这是一个教练在分享会提到的,他说敏捷就是快速迭代,他分享的主题是《敏捷是骗人的》。

 

屏幕快照 2019-06-11 上午9.53.45.png
 

这个事情告诉我们什么?有一些说法认为敏捷是万能的,或者说敏捷可以做很多事情,但真的是这样吗?不一定。

 

屏幕快照 2019-06-11 上午9.54.11.png
 

上面我也提到了一些教练需要做的事情,比如需要不断扩大沟通视窗,制定规则,减少执行摩擦等,我再提出几个观点。

敏捷教练应该是好销售。我们卖什么?卖“概念”。如果你在团队推敏捷方法和敏捷流程,你可以参考以下的销售思路,会让你的整个过程更容易,大家不妨试试。

 

屏幕快照 2019-06-11 上午9.56.30.png
 

敏捷教练应该是防火队员,更侧重于做防火的事情,而不是做救火队员(在问题发生前,提前感知到,提前准备预案,最好提前解决掉。)

 

屏幕快照 2019-06-11 上午9.57.17.png
 

教练应该是算法工程师,为什么?概念只是概念,最终落地的效果好不好,是需要在真实环境下,根据实际情况来做“调参”,通过不同管理算法的引入,通过不同的实践和结果反馈,不断迭代优化的过程。

 

屏幕快照 2019-06-11 上午9.57.46.png
 

 

屏幕快照 2019-06-11 上午9.58.20.png
 

3-管理的算法

敏捷教练是算法工程师,那么,他应该负责什么样的算法?

 

屏幕快照 2019-06-11 上午9.59.51.png
 

比如我们应该要确保团队持续不断的做正确的事情,如何做?

我们可以把敏捷和精益创业、设计思维做链接,形成一套从问题发现,到问题的分解和试验,到敏捷交付用户价值的闭环。

比如我们有各种各样的模式。

包括瀑布流程,PMBOK流程。

 

屏幕快照 2019-06-11 上午10.02.44.png
 

敏捷流程,看板流程。

 

屏幕快照 2019-06-11 上午10.03.15.png
 

敏捷界的网红Scrum流程和精益流程。

 

屏幕快照 2019-06-11 上午10.03.38.png
 

这些都是管理的算法, 都是敏捷教练这个“算法工程师”的“算法库”,或者说“兵器谱”。必须非常熟悉,并且知道在什么样的场景下,该如何使用。

4-极简之道

 

屏幕快照 2019-06-11 上午10.06.54.png
 

我们听过很多道理,依然过不好这一生。

在这么多方法论的基础上,我们如何用于团队?我们如何帮到团队提升效能?

我们要让团队更加高效,而不是让团队搞笑。从搞笑到高效方法很多,比如在个人级别的GTD时间管理,清单方法,个人和团队级别的“番茄工作法”等,都是在你尝试敏捷方法前的有益尝试。在切入敏捷实践后,可以先从kanban方法开始,慢慢转移到scrum方法(如果适用的话),再根据实际情况,转换到SoS(Scrum of Scrum),LeSS,SAFe等大规模敏捷实践上。

在选择某一个具体方法实施之前,以下几个问题值得思考。

首先,我们为什么要提高效率?为什么效率重要,如果没有想清楚为什么,怎么做可能都不对。比如我们为什么要两周交付?如果产品本身的属性,支持边开发,边测试,测试通过后可以直接灰度上线,我们就不一定要选择两周的交付周期,比如可以保持在一周的周期来交付。如果团队的基础设施还没有准备好,比如单元测试,自动化测试,持续集成都还做不到,固定两周交付可能会是一个灾难。

其次,我们需要区分什么行为是高效,什么是低效,什么是无效。我们可以通过对整体流程进行分析(比如使用value stream mapping等方法,来统计流程效率),获得基础数据,制定效率提升的目标。

再次,区分清楚后,我们可以采取措施和策略,来放弃无效的事情,减少低效的部分,提高有效工作的占比。

最后这一点是区分于流程之外的,我们需要提升团队的“沟通带宽”,需要不断扩大团队的社交连接。比如一个小组可能互相都不太认识,或者在平常的工作里还没有形成很好的协作模式,在这样的情况下,应该着力于让团队更多的沟通,加深在项目级别,和在非正式形式的沟通和协作(比如团队建设等),让团队加快融合。这是你无论采用哪种方式方法,都应该考虑的基础的部分。

C#:使用MD5对用户密码加密与解密 - Healer007 - 博客园

mikel阅读(1341)

来源: C#:使用MD5对用户密码加密与解密 – Healer007 – 博客园

C#中常涉及到对用户密码的加密于解密的算法,其中使用MD5加密是最常见的的实现方式。本文总结了通用的算法并结合了自己的一点小经验,分享给大家。

一.使用16位、32位、64位MD5方法对用户名加密

1)16位的MD5加密

复制代码
/// <summary>
/// 16位MD5加密
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
public static string MD5Encrypt16(string password)
{
    var md5 = new MD5CryptoServiceProvider();
    string t2 = BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(password)), 4, 8);
    t2 = t2.Replace("-", "");
    return t2;
}
复制代码

2)32位的MD5加密

复制代码
/// <summary>
/// 32位MD5加密
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
public static string MD5Encrypt32(string password)
{
    string cl = password;
    string pwd = "";
    MD5 md5 = MD5.Create(); //实例化一个md5对像
    // 加密后是一个字节类型的数组,这里要注意编码UTF8/Unicode等的选择 
    byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
    // 通过使用循环,将字节类型的数组转换为字符串,此字符串是常规字符格式化所得
    for (int i = 0; i < s.Length; i++)
    {
        // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母,如果使用大写(X)则格式后的字符是大写字符 
        pwd = pwd + s[i].ToString("X");
    }
    return pwd;
}
复制代码

3)64位的MD5加密

复制代码
public static string MD5Encrypt64(string password)
{
    string cl = password;
    //string pwd = "";
    MD5 md5 = MD5.Create(); //实例化一个md5对像
    // 加密后是一个字节类型的数组,这里要注意编码UTF8/Unicode等的选择 
    byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
    return Convert.ToBase64String(s);
}
复制代码

4)使用MD5为用户密码加密

复制代码
/// <summary>
/// 加密用户密码
/// </summary>
/// <param name="password">密码</param>
/// <param name="codeLength">加密位数</param>
/// <returns>加密密码</returns>
public static string md5(string password, int codeLength)
{
    if (!string.IsNullOrEmpty(password))
    {
        // 16位MD5加密(取32位加密的9~25字符)  
        if (codeLength == 16)
        {
            return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(password, "MD5").ToLower().Substring(8, 16);
        }

        // 32位加密
        if (codeLength == 32)
        {
            return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(password, "MD5").ToLower();
        }
    }
    return string.Empty;
}
复制代码

      由于MD5是不可逆的,所以加密之后就无法解密,取用户名和密码时候,需要再加密一边用户输入的数据与数据库中已加密的数据进行比对。如果比对结果一致,则可以判定登陆成功!代码如下所示:

复制代码
/// <summary>
/// 登陆
/// </summary>
public Model.UserInfo UserLogOn(string USERID, string pwd, out string statusCode)
{
    //假设已经通过用户ID获取到UserInfo的Model对象
    Model.UserInfo model = GetModel(USERID);
    if (model != null)
    {
        if (model.PASSWORD == MD5Encrypt64(pwd))
        {
            statusCode = "登陆成功";
        }
        else {
            statusCode = “密码错误”;
        }
    }
    else
    {
        statusCode = "用户不存在!";
        model = null;
    }   
    return model;
}
复制代码

5)通过DESCryptoServiceProvider对象对字符串进行加密解密

复制代码
/// <summary>
/// DES数据加密
/// </summary>
/// <param name="targetValue">目标值</param>
/// <param name="key">密钥</param>
/// <returns>加密值</returns>
public static string Encrypt(string targetValue, string key)
{
    if (string.IsNullOrEmpty(targetValue))
    {
        return string.Empty;
    }

    var returnValue = new StringBuilder();
    var des = new DESCryptoServiceProvider();
    byte[] inputByteArray = Encoding.Default.GetBytes(targetValue);
    // 通过两次哈希密码设置对称算法的初始化向量   
    des.Key = Encoding.ASCII.GetBytes(FormsAuthentication.HashPasswordForStoringInConfigFile
                                            (FormsAuthentication.HashPasswordForStoringInConfigFile(key, "md5").
                                                Substring(0, 8), "sha1").Substring(0, 8));
    // 通过两次哈希密码设置算法的机密密钥   
    des.IV = Encoding.ASCII.GetBytes(FormsAuthentication.HashPasswordForStoringInConfigFile
                                            (FormsAuthentication.HashPasswordForStoringInConfigFile(key, "md5")
                                                .Substring(0, 8), "md5").Substring(0, 8));
    var ms = new MemoryStream();
    var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
    cs.Write(inputByteArray, 0, inputByteArray.Length);
    cs.FlushFinalBlock();
    foreach (byte b in ms.ToArray())
    {
        returnValue.AppendFormat("{0:X2}", b);
    }
    return returnValue.ToString();
}
复制代码

此种算法可以通过加密密钥进行解密,解密方法如下:

复制代码
/// <summary>
/// DES数据解密
/// </summary>
/// <param name="targetValue"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string Decrypt(string targetValue, string key)
{
    if (string.IsNullOrEmpty(targetValue))
    {
        return string.Empty;
    }
    // 定义DES加密对象
    var des = new DESCryptoServiceProvider();
    int len = targetValue.Length / 2;
    var inputByteArray = new byte[len];
    int x, i;
    for (x = 0; x < len; x++)
    {
        i = Convert.ToInt32(targetValue.Substring(x * 2, 2), 16);
        inputByteArray[x] = (byte)i;
    }
    // 通过两次哈希密码设置对称算法的初始化向量   
    des.Key = Encoding.ASCII.GetBytes(FormsAuthentication.HashPasswordForStoringInConfigFile
                                            (FormsAuthentication.HashPasswordForStoringInConfigFile(key, "md5").
                                                Substring(0, 8), "sha1").Substring(0, 8));
    // 通过两次哈希密码设置算法的机密密钥   
    des.IV = Encoding.ASCII.GetBytes(FormsAuthentication.HashPasswordForStoringInConfigFile
                                            (FormsAuthentication.HashPasswordForStoringInConfigFile(key, "md5")
                                                .Substring(0, 8), "md5").Substring(0, 8));
    // 定义内存流
    var ms = new MemoryStream();
    // 定义加密流
    var cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
    cs.Write(inputByteArray, 0, inputByteArray.Length);
    cs.FlushFinalBlock();
    return Encoding.Default.GetString(ms.ToArray());
}
复制代码

说明:本文章系Healer007原创,署名:小萝卜!部分资料来自互联网,如需转载请注明出处!

C#实现MD5加密 - 聖輝 - CSDN博客

mikel阅读(3826)

来源: C#实现MD5加密 – 聖輝 – CSDN博客

方法一

首先,先简单介绍一下MD5

MD5的全称是message-digest algorithm 5(信息-摘要算法,在90年代初由mit laboratory for computer science和rsa data security inc的ronald l. rivest开发出来, 经md2、md3和md4发展而来。

MD5具有很好的安全性(因为它具有不可逆的特征,加过密的密文经过解密后和加密前的东东相同的可能性极小)

引用
using System.Security.Cryptography;
using System.Text;

具体代码如下(写在按钮的Click事件里):
byte[] result = Encoding.Default.GetBytes(this.tbPass.Text.Trim());    //tbPass为输入密码的文本框
MD5 md5 = new MD5CryptoServiceProvider();
byte[] output = md5.ComputeHash(result);
this.tbMd5pass.Text = BitConverter.ToString(output).Replace(“-“,””);  //tbMd5pass为输出加密文本的文本框

方法二

C# md5加密(上)
string a; //加密前数据
string b; //加密后数据
b=System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(a,”MD5″)

using   System;
using   System.Security.Cryptography;

方法2

public   static   string   GetMD5(string   myString)
{
MD5   md5     =   new   MD5CryptoServiceProvider();
byte[]   fromData   =   System.Text.Encoding.Unicode.GetBytes(myString);
byte[]   targetData   =   md5.ComputeHash(fromData);
string   byte2String   =   null;

for   (int   i=0;   i<targetData.Length;   i++)
{
byte2String   +=   targetData[i].ToString(“x”);
}

return   byte2String;
}

using   System.Security.Cryptography;

///   <summary>
///   给一个字符串进行MD5加密
///   </summary>
///   <param   name=”strText”>待加密字符串</param>
///   <returns>加密后的字符串</returns>
public   static   string   MD5Encrypt(string   strText)
{
MD5   md5   =   new   MD5CryptoServiceProvider();
byte[]   result   =   md5.ComputeHash(System.Text.Encoding.Default.GetBytes(strText));
return   System.Text.Encoding.Default.GetString(result);
}

C# MD5加密
using System.Security.Cryptography;

private void btnOK_Click(object sender, System.EventArgs e)
{
string strConn = “server=192.168.0.51;database=chengheng;User id=sa; password=123″;
if(texName.Text.Trim()==””)
{
this.RegisterStartupScript(“sf”,”<script language=’JavaScript’>alert(‘用户名不能为空’);document.all(‘texName’).focus()</script>”);
return;
}
else if(texPassword.Text.Trim()==””)
{
this.RegisterStartupScript(“sfs”,”<script language=’JavaScript’>alert(‘密码不能为空’);document.all(‘texPassword’).focus()</script>”);
return;
}
else
{
//将获取的密码加密与数据库中加了密的密码相比较
byte[] by = md5.ComputeHash(utf.GetBytes(texPassword.Text.Trim()));
string resultPass = System.Text.UTF8Encoding.Unicode.GetString(by);
conn.ConnectionString=strConn;
SQLCommand comm = new SQLCommand();
string name = texName.Text.Trim().ToString();
comm.CommandText=”select Ruser_pwd,Ruser_nm from Ruser where Accountno = @name”;
comm.Parameters.Add(“@name”,SQLDbType.NVarChar,40);
comm.Parameters[“@name”].Value=name;
try
{
conn.Open();
comm.Connection=conn;
SqlDataReader dr=comm.ExecuteReader();
if(dr.Read())
{
//用户存在,对密码进行检查
if(dr.GetValue(0).Equals(resultPass))
{
string user_name=dr.GetValue(1).ToString();
string user_Accountno=texName.Text.Trim();
Session[“logon_name”]=user_name;
Session[“logon_Accountno”]=user_Accountno;
//登录成功,进行页面导向

}
else
{
this.RegisterStartupScript(“wp”,”<script language=’javascript’>alert(‘密码错误,请检查。’)</script>”);
}

}
else
{
this.RegisterStartupScript(“nu”,”<script language=javascript>alert(‘用户名不存在,请检查。’)</script>”);
}
}
catch(Exception exec)
{
this.RegisterStartupScript(“wc”,”<script language=javascript>alert(‘网络连接有异,请稍后重试。’)</script>”);
}
finally
{
conn.Close();
}
}
}

方法三
C# MD5加密

C#开发笔记   一、C# MD5-16位加密实例,32位加密实例(两种方法)

环境:vs.net2005/sql server2000/xp测试通过
1.MD5 16位加密实例
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;

namespace md5
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(UserMd5(“8”));
Console.WriteLine(GetMd5Str(“8″));
}
/**//// <summary>
/// MD5 16位加密 加密后密码为大写
/// </summary>
/// <param name=”ConvertString”></param>
/// <returns></returns>
public static string GetMd5Str(string ConvertString)
{
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
string t2 = BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(ConvertString)), 4, 8);
t2 = t2.Replace(“-“, “”);
return t2;
}

/**//// <summary>
/// MD5 16位加密 加密后密码为小写
/// </summary>
/// <param name=”ConvertString”></param>
/// <returns></returns>
public static string GetMd5Str(string ConvertString)
{
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
string t2 = BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(ConvertString)), 4, 8);
t2 = t2.Replace(“-“, “”);

t2 = t2.ToLower();

return t2;
}

/**//// <summary>
/// MD5 32位加密
/// </summary>
/// <param name=”str”></param>
/// <returns></returns>
static  string UserMd5(string str)
{
string cl = str;
string pwd = “”;
MD5 md5 = MD5.Create();//实例化一个md5对像
// 加密后是一个字节类型的数组,这里要注意编码UTF8/Unicode等的选择
byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
// 通过使用循环,将字节类型的数组转换为字符串,此字符串是常规字符格式化所得
for (int i = 0; i < s.Length; i++)
{
// 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母,如果使用大写(X)则格式后的字符是大写字符

pwd = pwd + s[i].ToString(“X”);

}
return pwd;
}
}
}

using System.Security.Cryptography;
using System.Text;

public static string StringToMD5Hash(string inputString)
{
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] encryptedBytes = md5.ComputeHash(Encoding.ASCII.GetBytes(inputString));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < encryptedBytes.Length; i++)
{
sb.AppendFormat(“{0:x2}”, encryptedBytes[i]);
}
return sb.ToString();
}

 

 

 

二、首先在界面中引入:using System.Web.Security;

假设密码对话框名字password,对输入的密码加密后存入变量pwd中,语句如下:

string pwd = FormsAuthentication.HashPasswordForStoringInConfigFile(password.Text, “MD5″);

如果要录入则录入pwd,这样数据库实际的密码为202*****等乱码了。

如果登录查询则要:

select username,password from users where username='”+ UserName.Text +”‘ and password='”+ pwd +”‘

因为MD5不能解密,只能把原始密码加密后与数据库中加密的密码比较

 

三、C# MD5 加密方法 16位或32位

public string md5(string str,int code)
{
if(code==16) //16位MD5加密(取32位加密的9~25字符)
{
return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str,”MD5″).ToLower().Substring(8,16) ;
}
else//32位加密
{
return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str,”MD5”).ToLower();
}
}

 

 

四、做一个网站时,必然涉及用户登录,用户登录必然涉及密码,密码必然涉及安全,安全必然涉及加密。
加密现时最流行也是据说最安全的算法是MD5算法,MD5是一种不可逆的算法,也就是 明文经过加密后,根据加密过的密文无法还原出明文来。
目前有好多网站专搞MD5破密,百度上搜一下MD5就搜出一大堆了,今天早上无聊试了几个破密网站,6位以内纯数字密码的MD5密文可以还原出明文,长点的或带字符的就不行了。他们是采用穷举对比的,就是说把收录到的明文和密文放到数据库里,通过密文的对比来确定明文,毕竟收录的数据有限,所以破解的密码很有限。
扯远了,搞破密MD5需要大量的MONEY,因为要一个运算得超快的计算机和一个查找性能超好的数据库和超大的数据库收录。但搞加密就比较简单。以下是我用C#写的一个MD5加密的方法,用到.NET中的方法, 通过MD5_APP.StringToMD5(string str, int i)可以直接调用:

public class MD5_APP
{
public MD5_APP()
{

}

public static string StringToMD5(string str, int i)
{
//获取要加密的字段,并转化为Byte[]数组
byte[] data = System.Text.Encoding.Unicode.GetBytes(str.ToCharArray());
//建立加密服务
System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
//加密Byte[]数组
byte[] result = md5.ComputeHash(data);
//将加密后的数组转化为字段
if (i == 16 && str != string.Empty)
{
return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, “MD5”).ToLower().Substring(8, 16);
}
else if (i == 32 && str != string.Empty)
{
return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, “MD5”).ToLower();
}
else
{
switch (i)
{
case 16: return “000000000000000”;
case 32: return “000000000000000000000000000000”;
default: return “请确保调用函数时第二个参数为16或32”;
}

}
}
———————
作者:shenghui188
来源:CSDN
原文:https://blog.csdn.net/shenghui188/article/details/5423959
版权声明:本文为博主原创文章,转载请附上博文链接!

类型初始值设定项引发异常 - 雪庭 - 博客园

mikel阅读(3143)

来源: 类型初始值设定项引发异常 – 雪庭 – 博客园

类型初始值设定项引发异常

1 引子

今天早上,准备修改已前写的csharp程序,出现TypeInitializationException(类型初 始值设定项引发异常),这个以前没发现,挺奇怪,在网上找到了问题原因。

1.1 问题定位

问题出现在SQLite数据库操作,当打开数据库时,出现:

未处理的“System.TypeInitializationException”类型的异常出现在 TemperApplication.exe 中。
其他信息: “TemperApplication.DataWareHouse.SetupSqlite”的类型初始值设定项引发异常。

原来类的SQLite类静态成员在初始化时如果出现异常,访问类的其它静态成员或对该类进行 初始化都会抛出这个异常。sqlite代码:

  /// <summary>
  /// 访问sqlite数据库底层类
  /// </summary>
  public class SetupSqlite
  {
    /// <summary>
    /// 屏蔽默认构造函数
    /// </summary>
    private SetupSqlite()
    {
    }
...
    private static SQLiteConnection _sql_con = null;
    private static SQLiteCommand _sql_cmd = null;
    private static SQLiteDataReader _dr = null;
    private static SQLiteTransaction _trans = null; 
  }

那么一定是_sql_con,_sql_cmd,_dr,_trans,这四个静态变量初始化出现异常,我将这 四个静态变量的初始化去掉,如下:

  /// <summary>
  /// 访问sqlite数据库底层类
  /// </summary>
  public class SetupSqlite
  {
    /// <summary>
    /// 屏蔽默认构造函数
    /// </summary>
    private SetupSqlite()
    {
    }
...
    /*
    private static SQLiteConnection _sql_con = null;
    private static SQLiteCommand _sql_cmd = null;
    private static SQLiteDataReader _dr = null;
    private static SQLiteTransaction _trans = null; 
    */
    private static SQLiteConnection _sql_con;
    private static SQLiteCommand _sql_cmd;
    private static SQLiteDataReader _dr;
    private static SQLiteTransaction _trans; 
  }

重新运行,TypeInitializationException异常不出现了,但出现新异常:

未处理的“System.BadImageFormatException”类型的异常出现在 TemperApplication.exe 中。
其他信息: 未能加载文件或程序集“System.Data.SQLite, Version=1.0.66.0,
Culture=neutral, PublicKeyToken=db937bc2d44ff139”或它的某一个依赖项。试图加载格式
不正确的程序。

1.2 真正的原因

这说明,的确是四个静态变量的初始化有问题,问题原因出在sqlite.dll加载上,这个dll 以前加载都没有问题,问题一定出在别的地方,网上找到原因,是sqlite.dll分32位和 64位,以前用在32位下,现在开发换到win 7/x64下。

知道原因,修改就容易了,在项目属性中,修改目平台,从Any CPU改为x86,重新运行正 常,再将四个静态变量初始化恢复,运行也正常;明确问题,sqlite.dll是32位的,但目标 平台是x64的,有关sqlite的静态变量初始化异常,引起sqlite类初始化错误,引发 TypeInitializationException异常。

tempdb对SQL Server性能的影响 - changbluesky - 博客园

mikel阅读(1014)

来源: tempdb对SQL Server性能的影响 – changbluesky – 博客园

1.SQL Server系统数据库介绍

SQL Server有四个重要的系统级数据库:master,model,msdb,tempdb.

master:记录SQL Server系统的所有系统级信息,包括实例范围的元数据,端点,链接服务器和系统配置设置,还记录其他数据库是否存在以及这些数据问文件的位置等等.如果master不可用,数据库将不能启动.

model:用在SQL Server 实例上创建的所有数据库的模板。因为每次启动 SQL Server 时都会创建 tempdb,所以 model 数据库必须始终存在于 SQL Server 系统中。

msdb:由SQL Server 代理用来计划警报和作业。

tempdb:是连接到 SQL Server 实例的所有用户都可用的全局资源,它保存所有临时表,临时工作表,临时存储过程,临时存储大的类型,中间结果集,表变量和游标等。另外,它还用来满足所有其他临时存储要求.

 

2.tempdb内在运行原理

与其他SQL Server数据库不同的是,tempdb在SQL Server停掉,重启时会自动的drop,re-create. 根据model数据库会默认建立一个新的8MB(mdf file:8MB;ldf file:1MB, autogtouth设置为10%)大小recovery model为simple的tempdb数据库.

 

tempdb数据库建立之后,DBA可以在其他的数据库中建立数据对象,临时表,临时存储过程,表变量等会加到tempdb中.在tempdb活动很频繁时,能够自动的增长,因为是simple的recovery model,会最小化日志记录,日志也会不断的截断.

 

3.如何合理的优化tempdb以提高SQL Server的性能

如果SQL Server对tempdb访问不频繁,tempdb对数据库不会产生影响;相反如果访问很频繁,loading就会加重,tempdb的性能就会对整个DB产生重要的影响.优化tempdb的性能变的很重要的,尤其对于大型数据库.

注:在优化tempdb之前,请先考虑tempdb对SQL Server性能产生多大的影响,评估遇到的问题以及可行性.

3.1最小化的使用tempdb

SQL Server中很多的活动都活发生在tempdb中,所以在某种情况可以减少多对tempdb的过度使用,以提高SQL Server的整体性能.

如下有几处用到tempdb的地方:

(1)用户建立的临时表.如果能够避免不用,就尽量避免. 如果使用临时表储存大量的数据且频繁访问,考虑添加index以增加查询效率.

(2)Schedule jobs.如DBCC CHECKDB会占用系统较多的资源,较多的使用tempdb.最好在SQL Server loading比较轻的时候做.

(3)Cursors.游标会严重影响性能应当尽量避免使用.

(4)CTE(Common Table Expression).也会在tempdb中执行.

(5)SORT_INT_TEMPDB.建立index时会有此选项.

(6)Index online rebuild.

(7)临时工作表及中间结果集.如JOIN时产生的.

(8)排序的结果.

(9)AFTER and INSTEAD OF triggers.

不可能避免使用tempdb,如果有tempdb的瓶颈或issue,就该返回来考虑这些问题了.

3.2重新分配tempdb的空间大小

在SQL Server重启时会自动建立8MB大小的tempdb,自动增长默认为10%. 对于小型的数据库来说,8MB大小已经足够了.但是对于较大型的数据库来说,8MB远远不能满足SQL Server频繁活动的需要,因此会按照10%的比例增加,比如说需要1GB,则会需要较长的时间,此段时间会严重影响SQL Server的性能. 建议在SQL Server启动时设置tempdb的初始化的大小(如下图片设置为MDF:300MB,LDF:50MB),也可以通过ALTER DATABASE来实现. 这样在SQL Server在重启时tempdb就会有足够多的空间可利用,从而提高效率.

难点在于找到合理的初始化大小,在SQL Server活动频繁且tempdb不在增长时会是一个合适的值,可以设置此时的值为Initial Size;当然还会有更多的考量,此为一例.

3.3不要收缩tempdb(如没有必要)

有时候我们会注意到tempdb占用很大的空间,但是可用的空间会比较低时,会想到shrink数据库来释放磁盘空间, 此时要小心了,可能会影响到性能.

如上图所示:tempdb分配的空间为879.44MB,有45%的空间是空闲的,如果shrink掉,可以释放掉一部分磁盘空闲,但是之后SQL Server如有大量的操作时,tempdb空间不够用,又会按照10%的比例自动增长. 这样子的话,所做的shrink操作是无效的,还会增加系统的loading.

3.4 分派tempdb的文件和其他数据文件到不用的IO上

tempdb对IO的要求比较高,最好分配到高IO的磁盘上且与其他的数据文件分到不用的磁盘上,以提高读写效率.

tempdb也分成多个文件,一般会根据CPU来分,几个CPU就分几个tempdb的数据文件. 多个tempdb文件可以提高读写效率并且减少IO活动的冲突.

 

tempdb是SQL Server重要的一部分,以上只是对tempdb的一些了解总结,还需要进一步学习…

跨浏览器的打印程序的设计 - Web打印 - 博客园

mikel阅读(929)

来源: 跨浏览器的打印程序的设计 – Web打印 – 博客园

我在多年之前设计过一个ActiveX的打印控件,当时在市面上找不到符合自己要求的打印控件,所以就按照自己的思路设计开发了一个打印控件,并共享出来,没想到得到许多同行朋友的认可,大家用起来觉得还挺不错的。

已经过了许多年,浏览器已经由当年的IE或以IE为内核的国产浏览器为主流,转为以Google的Chrome浏览器或以Chrome为内核的国产浏览器为主流了,ActiveX已经成为昨日黄花。我本想这么多年过去了,各种技术都是日新月异的,作为打印应该早就不是什么问题,可到了自己做项目开发时,需要用到比较复杂一点的打印时,去网上找一找,才发现打印这一块的技术还是没有多大的发展,排在百度搜索前几名的所谓轻打印控件,还是和许多年前一样的有以下几个毛病:一是报表设计繁琐,既当爹又当妈的,既要用JavaScript定义报表的格式,又要组织报表的数据,一个操作窗口,需要自己先计算好各显示的坐标,然后再一一的画出来,这样的报表设计用起来使人发狂,一二个报表还可以勉强对应,要是多做几个就累死人了,而且以后维护修改也很麻烦。二是打印的数据量稍大一点,比如一次打印几十页数据,浏览器就卡死在那里,半天都没有反应,打印一个大一点的报表,把用户和公司的技术服务都快逼疯了。三是所谓的HTML打印,因为浏览器页面和纸张,在版面和精度控制方面的差异,导致网页显示和实际打印的效果差很远,而且因为页面一般是前端程序员通过JS、CSS等技术设计出来的,而报表开发这个一般是属于后端程序员的工作,这样硬是把后端开发的工作推给前端,还很难把报表这一块做好。

我想如其用着这些蹩脚的东西,还不如把自己多年前设计的打印控件进行升级,让其支持所有的主流浏览器。Chrome注重安全性、健壮性和用户体验,而打印程序需要管理用户本地的打印机,作为浏览器中渲染执行的网页程序,是无法直接控制打印机,所以这个必须通过应用程序来进行精准打印。所有的浏览器都可以通过URL Protocol协议来调用本地程序。

这个跨浏览的打印控件的总体设计思路是:在服务端把打印模板设计好,把所需要打印的数据组织好,再生成一个临时文件的URL,然后把此URL作为参数通过URL Protocol协议去调用本地的打印控件,打印控件下载此临时文件,再解析出打印模板和打印数据,最后进行直接打印或打印预览。

我按照此思路,编写了服务端的类库和打印控件,服务端的类库是完全开源的,提供所有的源代码,目前的源代码版本有Java、C#、PHP,对于其它语言,我暂时还没有用过,有需要的朋友可以自己完善一下。要集成到自己的项目中,也是比较简单的,我提供了详细的说明文档,一般只需要引用2个源文件就可以直接调用其中的函数了。

对于打印控件,因为涉及HTTP、JSON等技术,这个C#比C++更快开发,所以我采用.net framework 3.5进行开发,这个框架是Win 7系统自带,对于Win 7和Win 10 的电脑无需再次安装,对于古老的XP则需要先安装此框架。

开发了此打印控件之后,除了自己的项目使用之后,我共享给同行朋友使用,他们一致反应,控件稳定好用,兼容Windows系统下的所有浏览器;速度快,打印预览100页,也只需要5秒钟;设计效率高,通过简单的拖放就可以设计一份完美的中国式报表; 还支持用户自主在线设计报表等。

有需要的朋友,请加入QQ群:218392762(一群:135506194、二群:150850837都已满,请加入三群)或者请直接Q我:12988672。

报表预览、编辑和开发包下载的网址:  http://www.lc-simple.com/PirntTest/

理解serverless无服务架构原理(一) - 龙恩0707 - 博客园

mikel阅读(967)

来源: 理解serverless无服务架构原理(一) – 龙恩0707 – 博客园

阅读目录

一:什么是serverless无服务?

serverless中文的含义是 “无服务器”,但是它真正的含义是开发者再也不用过多考虑服务器的问题,但是并不代表完全去除服务器,而是我们依靠第三方资源服务器后端,比如使用 Amazon Web Services(AWS) Lambda. 计算服务来执行代码,那么Serverless架构分为 Backend as a Service(BaaS) 和 Functions as a Service(FaaS) 两种技术,Serverless 它是由开发者实现的服务端逻辑运行在无状态的计算容器中,它是由事件触发,完全被第三方管理的。

什么是BaaS?

Baas 的英文翻译成中文的含义:后端即服务,它的应用架构由大量第三方云服务器和API组成的,使应用中关于服务器的逻辑和状态都由服务提供方来管理的。比如我们的典型的单页应用SPA和移动APP富客户端应用,前后端交互主要是以RestAPI调用为主。只需要调用服务提供方的API即可完成相应的功能,比如常见的身份验证,云端数据/文件存储,消息推送,应用数据分析等。

什么是FaaS?

FaaS可以被叫做:函数即服务。开发者可以直接将服务业务逻辑代码部署,运行在第三方提供的无状态计算容器中,开发者只需要编写业务代码即可,无需关注服务器,并且代码的执行它是由事件触发的。其中AWS Lambda是目前最佳的FaaS实现之一。

Serverless的应用架构是将BaaS和FaaS组合在一起的应用,用户只需要关注应用的业务逻辑代码,编写函数为粒度将其运行在FaaS平台上,并且和BaaS第三方服务整合在一起,最后就搭建了一个完整的系统。整个系统过程中完全无需关注服务器。

二:与传统模式架构区别?

传统的架构模式是使用C/S架构的,在典型的web应用程序中,服务器接收前端的HTTP请求处理,在保存或查询数据库之前,数据可能会经过多个应用层,最终后端会返回一个响应。比如它可以是JSON形式或其他格式等。然后他会将响应返回给客户端,比如如下图所示:

在传统开发模式中,开发流程:设计师设计页面 -> 服务端开发 和 前端分别开发,服务器开发完成后,-> 服务部署 ->服务部署完成后,就是前后端联调 -> 前后端联调 -> 前后端联调完成后就是测试了,-> 测试, 测试完成需要上线,因此 -> 上线,上线完成后,需要运维维护,因此 -> 运维。在传统开发模式中,开发一个应用程序,从开始到上线需要不同的角色来做不同的事情,沟通成本非常大,并且运维过程中需要考虑到 服务器的负载均衡、事务、集群、缓存、
消息传递和数据冗余等等这些事情,在目前传统模式中存在如上问题。可以使用如下示意图来看下如上流程。如下图所示:

在Serverless架构中,应用业务逻辑是基于FaaS架构形成多个相互独立的功能组件的。并且以API服务的形式向外提供服务,在FaaS中,后端的应用被拆分成为一个个函数,我们只需要编写完成函数后部署到serverless服务即可。后续我们也不用关心任何服务器的操作。那么整个流程就只需要我们一个前端工程师的角色来完成所有的开发工作,那么沟通成本降低了。因此我们可以使用如下示意图来表示项目流程,如下所示:

前端工程师是居于serverless去写后端服务的,典型的就是居于 AWS Lambda 中编写代码,AWS中支持不同的语言。
Lambda计算服务它能够以大规模并行的方式执行代码来响应事件。通过使用Lambda以及使用各种功能强大的API和Web服务,开发者可以快速的构建松耦合,可扩展性及高效的架构体系。

注意:Lambda是什么?它是一种计算服务,它在AWS基础上执行用JavaScript、node.js、Python、C#或java编写的代码,源代码将被打包并部署到孤立的容器中,该容器有单独分配的内存、磁盘空间和处理器。代码、配置和依赖项的组合被称作为Lambda函数。

三:serverless优缺点?

优点有如下:

1. 降低创业公司启动成本

当一家创业公司的时候,在开发web的时候,我们需要版本管理服务器、持续集成服务器、测试服务器、应用版本管理仓库等作为基础服务。
线上运行的时候,为了应对大量的请求,我们还需要一个好的数据库服务器。当我们应用面向普通的用户时,我们需要:

1.1 邮件服务,用于发送提醒,注册等服务。
1.2 短信服务,用于注册,登录等用户授权操作。

如上一些对于大公司来讲,都有现成的基础设施。可是对于创业公司来讲。这都需要一些启动成本。但是如果我们使用serverless就可以降低这些成本。

2. 减少运营成本

对于创业公司来讲,他们没有基础设施,没有财力,也可能没有能力去建设基础设施,采用云服务是最好的选择,可以为他们节省大量的资金。
他们只要将精力放在对用户价值的产品之上即可,他们不需要自己去搭建服务器,因此会有更多的时间去开发业务功能。而采用函数计算的serverless与云服务器最大的区别是:云服务器需要一直运行,比如说月费或年费要多少钱租,但是serverless是按需计费的,如果有请求到来的时候,才运行函数,否则的话,是不需要钱的。

3. 降低开发成本

serverless会提供一系列的配套服务,比如 我们只需要在配置文件上写下数据库的表名,那么数据就会存储到对应的数据库里面,并且会提供一系列的函数计算模板,我们只需要写好我们的配置即可,那么这一系列的东西都可以自动,高效的完成任务。

4. 实现快速上线

对于一些传统项目来讲,我们在本地开发需要部署环境,到开发环境或测试环境,我们还是需要部署环境。但是serverless可以在部署上有优势,并且很轻松的实现上线。因为serverless内部相当于有 内建自动化部署功能,并且在该里面都是由供应商提供的功能,每次我们写完业务代码后,我们只需要运行下即可,在AWS Lambda 函数计算里面,函数一般在上传后几秒钟内,就能做好调用准备。

5. 系统安全性更高。

要保持服务器一直运行不是件容易的事情,并且还需要考虑黑客不同类型的攻击,但是有serverless后,我们不需要考虑这些问题了,这些问题第三方供应商已经会帮我解决这些问题的。

6. 能适应微服务架构和扩展性能力强

Serverless 的背后是 诸如 AWS Lambda 这样的 FaaS(Function as a Services)。

对于传统应用来说,要应对更多的请求的方式,就是部署更多的实例。然而,这个时候往往已经来不及了。而对于 FaaS 来说,我们并不需要这么做,FaaS 会自动的扩展。它可以在需要时尽可能多地启动实例副本,而不会发生冗长的部署和配置延迟。

以亚马逊的AWS Lambda为案例,Lambda能让我们不用思考任何服务器,也就是说,不用我们处理服务器上的部署,服务器的容量和服务器的扩展和失败容错,还有服务器上选择什么OS操作系统,语言的更新,日志等等问题。你的应用程序只需要和多个第三方的API或服务打交道,也可以自我创建一个无服务器的
API。

缺点有如下:

1. 不适合长时间运行应用

serverless 在请求到来的时候才运行,当应用不运行的时候会进入 “休眠状态”,下次当请求来临时,应用将会需要一个启动时间,可以叫 冷启动,如果我们的应用需要一直长期不间断的运行,处理大量的请求,那么可能就不适合使用serverless来架构了,如果这种情况下,我们需要使用像EC2这样的云服务器会是一个更好的选择。

EC2相当于我们自己买了一辆车,在Lambda 相当于我们租了一辆车。如果我们长期租车的话,那么肯定比买车更贵,但是租车可以减少一部分车维护成本。

2. 完全会依赖于第三方服务

如果我们所有和应用相关的服务放在第三方服务上的话,就可能会涉及到安全性问题,因此我们可以将不重要的API或服务放在serverless上。
当然如果我们自己有服务设施的话,那肯定使用自己的设施服务的,当我们自己使用serverless架构的时候,那么我们就已经和供应商绑定了。
如果这个时候我们将服务迁到别的云服务商上就没有那么容易了。

3. 缺乏调式和开发工具,排查问题困难。

4. 无法用于高并发运用。

为每个请求启动一个进程开销太高,流量瞬间爆发容易超时。比如淘宝的双十一支付宝高峰期,每秒处理交易笔数8万多笔,也就意味着我们的系统内每秒有8万多个进程创建又被销毁。那么这样就会造成系统开销很大。解释和第一点一样的原理。

四:使用serverless的应用场景有哪些?

Serverless 适合构建比较简单的应用,比如上传一张图片,对一段音频/视频进行编码或解码,对请求返回一小段数据等。

Serverless架构主要有以下特点:

1. 实现了细粒度的计算资源分配。
2. 不需要预分配资源。
3. 具备真正意义上的高度扩容和弹性。
4. 按需使用,按需计费。

因此以下应用将可能使用serverless架构:

1. 静态网站的管理。
2. 替代WordPress(Serverless Blog Project)
3. 个人媒体服务器(less!)
4. 物联网Iot或家庭自动框架或项目 (使用 AWS IoT)

tempdb太大引起磁盘容量不足的处理 - 简书

mikel阅读(2472)

来源: tempdb太大引起磁盘容量不足的处理 – 简书

最近公司项目在用SQLServer2012,因数据量非常大,程序跑起来临时表的数据量高达40多G,严重影响C盘的存量,所以决定将临时表文件迁移到存量比较大的分区。

  • 临时方法:重启MSSQLServer服务可删除缓存,可是不方便,更好的方法是更换缓存分区。

具体方法:

1.在SQLServer中运行以下代码:
SELECT name, physical_name
FROM sys.master_files
WHERE database_id = DB_ID(‘tempdb’);

运行后会返回tempdb.mdf与templog.ldf的路径。

2.在控制面板-管理工具-服务中停止MSSQLSERVER的服务并将以上两个文件移动到其他分区,并记下路径。再执行以下语句:

GO
ALTER DATABASE tempdb 
MODIFY FILE (NAME = tempdev, FILENAME = 'D:\tempdb\tempdb.mdf');
GO
ALTER DATABASE tempdb 
MODIFY FILE (NAME = templog, FILENAME = 'D:\tempdb\templog.ldf');

NAME = tempdev,NAME = templog 是逻辑名,FILENAME 指向的是数据库文件的实际位置
3.重启服务,检查SQLserver是否移动成功:

FROM sys.master_files
WHERE database_id = DB_ID('tempdb'); 
运行后会返回新的tempdb.mdf与templog.ldf的路径。  

坑来了!

第二天重启电脑后发现sqlserver2012不能登录了,MSSQLSERVER 显示[[SQL Server无法连接到服务器]标题: 连接到服务器 ——— 无法连接到 ****],找不到指定文件……并且启动MSSQLSERVER服务时会自动停止,经过查看计算机管理日志后发现错误:

  • 尝试打开或创建物理文件 ‘F:\tempdb\tempdb.mdf’ 时,CREATE FILE 遇到操作系统错误 5(拒绝访问。)。
  • FCB::Open failed: 无法打开文件号 1 的文件 F:\tempdb\tempdb.mdf。操作系统错误: 5(拒绝访问。)。

确定是改变临时表路径引起的权限问题!

解决方法:
分区->属性->安全
把User的权限改为完全控制,重启服务即可。

参考资料:http://www.cnblogs.com/shadow-ccos/p/5304106.html

作者:shakesbears
链接:https://www.jianshu.com/p/f7674b38833f
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。