-
MVC的Razor语法中链接的一些方法
在Razor中,由HTML.ActionLink和 Url.Action来呈现链接。它们有什么区别呢。能分清了,就知道在什么情况之下使用它们了。 首先来看html.ActionLink,这个方法重载挺多的,最终生成一个<a href=".."></a>标记。如果没有指定controller,则默认为本页面对应的Controller。 2020-09-17
-
C#中DateTime格式转换
在C#中DateTime是一个包含日期、时间的类型,此类型通过ToString()转换为字符串时,可根据传入给Tostring()的参数转换为多种字符串格式。 常用的函数: DateTime.Now.ToString(“yyyyMMdd”)显示为:20160501; DateTime.Now.ToString("yyyyMMddHHmmss")显示为:20160501210635; 目录 分类 制式类型 自定义格式类型 1. 分类DateTime调用ToString()传入的参数可分为制式和自定义两种: 1) 制式:系统自带的,转入特定的单个字符就可转换为系统已设定好的格式。 2) 自定义:自由组合日期代码(y、M、d、h、m、s、f)来展示丰富的日期格式。 2. 制式类型说明:转入特定的单个字符就可转换为系统已设定好的格式。 2.1 格式来源在Windows系统中的区域和语言(位置:控制面板 → 区域和语言)选项中可设置日期和时间的格式。 可设置的分类有:短日期、长日期、短时间、长时间等。 调用ToString()进行转换时,许多转换方式都是通过上面的4个分类进行组合。 2.2 符号对照表2.2.1 环境.net版本:4.0 系统版本:Win7 格式信息: 2.2.2 对照表 符号 语法 示例(2016-05-09 13:09:55:2350) 格式说明 y DateTime.Now.ToString() 2016/5/9 13:09:55 短日期 长时间 d DateTime.Now.ToString(“d”) 2016/5/9 短日期 D DateTime.Now.ToString(“D”) 2016年5月9日 长日期 f DateTime.Now.ToString(“f”) 2016年5月9日 13:09 长日期 短时间 F DateTime.Now.ToString(“F”) 2016年5月9日 13:09:55 长日期 长时间 g DateTime.Now.ToString(“g”) 2016/5/9 13:09 短日期 短时间 G DateTime.Now.ToString(“G”) 2016/5/9 13:09:55 短日期 长时间 t DateTime.Now.ToString(“t”) 13:09 短时间 T DateTime.Now.ToString(“T”) 13:09:55 长时间 u DateTime.Now.ToString(“u”) 2016-05-09 13:09:55Z U DateTime.Now.ToString(“U”) 2016年5月9日 555 本初子午线的长日期和长时间 m DateTime.Now.ToString(“m”) 5月9日 M DateTime.Now.ToString(“M”) 5月9日 r DateTime.Now.ToString(“r”) Mon
转换,格式2020-06-16536
-
.NET Ccore2.2升级.NET Core 3.1发布报错,没有“.NETCoreApp,Version=v3.0”的目标。确保已运行还原,且“netcoreapp3.0”已包含在项目的 TargetFrameworks 中
前言.NET Core 3.1是长期维护版本,所以将老版本的项目从2.2升级至3.1,修改了许多地方后,在发布时遇到 资产文件“\obj\project.assets.json”没有“.NETCoreApp
升级,没有,确保,运行,项目2020-05-264428
-
页面片段缓存(一)
一般,页面上会分为很多部分,而不同的部分更新的频率是不一样的。如果对整个页面采用统一的缓存策略则不太合适, 而且很多系统的页面左上角都有一个该死的“Welcome XXX”。这种特定于用户的信息我们是不能缓存的。对于这些情况我们就需要使用片段缓存了。对页面不同的部分(片段)施加不同的缓存策略,而要使用片段缓存,首先就得对页面进行切分。土一点的办法可以用iframe,用iframe将页面划分为一块块的,不过我总觉得iframe是个邪恶的东西。好点的办法可以用Ajax单独的请求这个片段的内容然后再填充,看起来挺美好的。不过使用Ajax也有一些限制: 1、如果页面上有许多片段,使用太多的这种技术,会有很多请求发送到服务器,HTTP对同一个域名有连接的限制,这样会降低并发连接的效率。 2、如果说第一个不是什么问题,那么还有一点可能对用户体验不友好。比如有一个片段可能响应慢点,造成页面闪烁。不过如果前面两点都可以克服,这个方案还是可以的。可恶的是我们的客户(此处省略500字),说他们的大多数用户处于一个禁用JavaScript的环境里。好吧,这个方案也不能使用了。如是我们进行了一系列其他关于片段缓存的尝试: 我们的系统使用的是Spring+Hibernate+Oracle技术,模板引擎使用的是Apache Velocity。假设下面的片段是我们要缓存的内容: #foreach($book in $books) $book.name---Edit -- Delete #end 显示一个图书列表。对这个页面改动最小的办法是加上一个标签,被这个标签包围的片段就是缓存的:#cache #foreach($book in $books) $book.name---Edit -- Delete #end #end由于一个页面可能有很多片段,不同的片段肯定要用不同的cache key,所以这个标签应该还能传入一个cache key。当呈现这个页面,到解析这个标签的时候我们就用这个cache key去缓存中取,如果取到了我们就直接将缓存的东西输出, 而不再需要解析这个图书列表了。 有了这个想法,我们就需要找到如何让Velocity解析我们的标签的方案。很好,Velocity是支持自定义标签的: Cache extends Directive { @Override String getName() { ; } @Override getType() { BLOCK; } @Override boolean render(InternalContextAdapter context
片段,页面,2018-09-30397
-
页面片段缓存(二)
在上一篇文章中,我介绍了我们用土法炼钢的方法,使用Velocity提供的自定义标签实现片段缓存。这样的方式虽然也解决了我们的问题,但还是引出了一些bug。而且还有点hack的味道(虽然我喜欢hack)。实际上对于片段缓存,业界有成熟的解决方案,还有一个所谓的W3C标准:ESI(Edge Side Include) 。 ESI本身没有什么,只是一个XML的标签集合。ESI和SSI(Server Side Include)很相似,做过ASP开发的都熟悉这么一个标签:<!--#include src="header.inc" --> IIS碰到这么一个标签后,会把header.inc里面的东西合并到当前的页面,这样做的好处是header.inc本身可以复用了,你可以在多个页面include它。 ESI的功能也是类似的,只不过解析和合并它的任务一般落到缓存服务器或代理上: #foreach($book in $books) $book.name #end 比如对于上面这个片段,esi:include标签那里本来是应该显示特定于每个用户的欢迎信息的,就因为这一点整个页面不能缓存太可惜了。这个时候ESI粉墨登场。缓存服务器会将整个页面cache,然后它发现这儿有个ESI标签,它会根据src指定的地址去源服务器请求内容,然后将其合并到缓存的页面中,然后将完整的内容发送到客户端。整个过程类似下图所示: 这样我们就不需要每次都去数据库查询那个图书列表了,因为图书列表可能更新的很缓慢。这样大大的降低了Web服务器的压力。 既然ESI是一个规范,那么肯定有遵循这个规范的实现。比如大名鼎鼎的Squid就有支持ESI的模块。不过本文要介绍的是Varnish。Varnish是一个反向代理,使用缓存对HTTP加速,可以把它放到你的Web服务器的前面,对内容缓存,跟Squid的目的相似。不过因为Squid想干的事儿实在是太多,它已经不再是一个纯粹的用户缓存加速的方向代理了,所以显得太过于臃肿,而比较起来Varnish更专注,更轻便。根据网站上的数据显示,Varnish表现出来的性能比Squid更好,而且占用的资源更少。 下面我就简单的描述一下如何安装Varnish以及配置使用ESI。 安装 我是在Mac上安装Varnish的,从源代码编译过去的。基本上是一路命令下去,在configure的时候碰到缺少libpcre,用port装上pcre就可以了:$wget http://repo.varnish-cache.org/source/varnish-2.1.5.tar.gz $tar zxvf varnish-2.1.5.tar.gz $cd varnish-2.1.5 $sh autogen.sh $sh configure $make $make install 根据环境不同,可能缺少一些依赖,我在安装的过程中就缺少libpcre。 Varnish默认是安装在/usr/local/sbin目录下:varnishd。是daemo。 配置 根据上面那幅图可以看出,Varnish并不自己提供服务,它只是作为一个缓存服务器。那么就必须有一个后端的服务器提供应用程序的服务。那我们就需要让Varnish知道到哪儿去请求后端服务器。这个是通过配置文件设置的,Varnish的默认配置文件在/usr/local/etc/varish/default.vcl。 打开后我们会发现一段被注释的代码,取消注释将其指向你的后端服务器(比如IIS):backend default { .host = "127.0.0.1" .port = "8080"} 配置好后,启动Varnish,然后去看看效果,启动的命令是:sbin yuyi$sudo ./varnishd -a 0.0.0.0:80 -f /usr/local/etc/varnish/default.vcl -s malloc
片段,页面,2018-09-30380
-
.NET简谈观察者模式
摘要:观察者模式想必搞程序开发的都听说过,今天作者将来为大家也来简单的总结一下他在程序开发过程中是怎么使用观察者模式的,希望给大家带来点新的想法。 观察者模式想必搞程序开发的都听说过,今天我也来简单的总结一下本人在程序开发过程中是怎么使用观察者模式的;希望给大家带来点新的想法,如果哪位高手看到了也不要嘲笑啊;呵呵,追求技术的人,始终都是为了技术而学技术,目的只有一个,一起追求技术的最高境界。 观察者模式是设计模式里经常被用到的一种,
观察者,模式,2018-09-30278
-
JAVA与.NET的相互调用——TCP/IP相互调用基本架构
TCP/IP套接字的概念 TCP/IP(传输控制协议/网际协议)是网络互连的通信协议,通过它可以实现各种异构网络或异种机之间的互联通信。TCP/IP是Transmission Control Protocol/Internet Protocol的简写,中文译名为传输控制协议/因特网互联协议,又叫网络通讯协议,这个协议是Internet最基本的协议、Internet国际互联网络的基础,简单地说,就是由网络层的IP协议和传输层的TCP协议组成的。TCP/IP 定义了电子设备(比如计算机)如何连入因特网,以及数据如何在它们之间传输的标准。TCP/IP是一个四层的分层体系结构。高层为传输控制协议,它负责聚集信息或把文件拆分成更小的包。低层是网际协议,它处理每个包的地址部分,使这些包正确的到达目的地。 TCP/IP已成为当今计算机网络最成熟、应用最广的互联协议。Internet采用的就是 TCP/IP协议,网络上各种各样的计算机上只要安装了TCP/IP协议,它们之间就能相互通信。 TCP/IP套接字通讯的开发 在众多的开发语言中,绝大部分的开发语言都支持TCP/IP协议通讯,开发过程也十分相像,先设置好Socket,然后由客户端发送请求信息,服务器连接客户端接收到请求后再返还信息。而在.NET系统当中则稍有不同,系统把Socket对象包装在TcpClient对象内,对Socket对象的生命周期进行管理。在开发过程当中,服务器与客户端的开发语言有所不同的情况经常发生,服务器是在JDK1.6的环境下进行开发的,客户却要求使用.NET开发客户端,这往往会令开发人员感到困惑!下面在下使用JAVA为服务器,.NET为客户端为例子,为大家介绍一下如何使用TCP/IP协议进行JAVA .NET之间的相互调用。像TCP/IP实现聊天室这样的例子很多,开发起来也比较简单,因为通讯双方都是使用String来传送信息。而在真正建立ERP、OA、CRM等系统的时候,通讯双方都必须先建立一套统一的通讯契约,才能实现TCP/IP通讯,下面将为大家介绍一个比较典型的企业信息通讯实例。 信息传送方式 因为.NET与JAVA各有不同的特性,双方不可能直接通过的序列化对象来传输信息,常用的信息交换方式有以下三种: 1. 最 笨拙也是最复杂的一种传息方式,就是直接使用“头文件说明+字段属性”的方式。 这是一个既原始又麻烦的通讯方式,因为每个契约都要以二进制的方式发送一个请求,就算是同一类契约,随着参数的不同,每个请求的长度也会发生改变。这样的 传息方式虽然是麻烦,但在不同开发语言相互调用的时候却经常会看到,这可能是因为开发人员对两种开发语言未能完全熟悉,所以倒置使用这最原始最简单的开发 方式。 2. 使用XML的信息传送方式,这是最常见,使用最广的信息传递方式。在绝大多数的开发平台都会支持XML,所以XML在Web网络传讯过程中最为常见。但XML最大的一个缺点就是过于堪舆,耗费大量的传输流量。 3. 对 于XML的缺点,JSON应运而生而且发展迅速,JSON本是源于Javascript的,多数只用于B/S的页面开发,但随着技术的发展和多个开发语言 的支持,现今到处都可以看JSON的身影。因为JSON既提供一套跨平台的通讯方式,也免去XML复杂特性,受到各类型开发人员的欢迎。 服务器端开发通讯契约 首先建立一套服务器与客户端同时接受通讯契约
相互,调用,架构,基本,2018-09-30251
-
理解.NET程序集的执行过程
摘要:对于一个已编译好的.NET程序集,Windows操作系统是如何启动执行的呢? 对于一个已编译好的.NET程序集,Windows操作系统是如何启动执行的呢?日常使用中我们发现对于托管的和非托管的程序集编译器都会吧程序集编译成以.exe或.dll等为扩展名的文件,可见Windows加载器并没有区分是托管还是非托管的程序集,而且我们也知道对非托管的程序集是在编译器直接编译成了机器码,自然可以由CPU直接执行,而托管的.NET 程序集是
执行,过程,程序,理解,2018-09-30314
-
Visual Studio 2010 中的代码约定设置
软件约定称为代码约定,通过这一约定可以表示代码正常工作所需的正式条件。 如果方法未按预期收到数据或生成的数据不符合预期的后置条件,代码约定将导致代码引发异常。 有关前置条件和后置条件的概述,您可能需要查看我上个月发表的文章 (msdn.microsoft.com/magazine/gg983479)。 代码约定是 .NET Framework 4 的一部分,但同样依赖于 Visual Studio 2010 中的一些功能,例如运行时工具、与 MSBuild 集成以及“项目属性”框中的属性页。 值得注意的是,仅编写前置条件和后置条件是不够的。 您还需要为每个项目启用运行时检查功能才能使用软件约定。 您可以通过 Visual Studio 2010 中的“代码约定”项目属性页来完成上述操作。 在本文中,我将讨论您可以查看或选择的各个选项的预定用途,并深入讨论使用代码约定中的参数验证可以执行的最常见操作的重写程序工具和实践。 代码约定属性页 应在所有版本中还是仅在调试版本中实施代码约定前置条件和后置条件? 实际上,这取决于您对软件约定概念的理解。 它是设计工作的一部分吗? 或者,它仅是一种调试措施? 如果它是设计功能,则没理由剥离发行版中的约定。 如果它仅是一种调试技术,当在发布模式中进行编译时,您不希望显示它。 在 .NET Framework 中,代码约定仅是此框架的一部分并且未融入任何语言。 这样将更容易在项目中按版本配置它们。 因此,通过软件约定的 .NET Framework 实现,您可以决定实现约定的合适时间和地点。 图 1 显示 Visual Studio 2010 中的属性页,通过此页可以设置软件约定为应用程序工作的方式。 请注意,此类设置基于项目应用,因此可以根据需要进行调整。 图 1 Visual Studio 2010 中代码约定的属性页 您可以选择选项配置(调试、发布等)并仅对该配置应用设置。 这样,您可以启用代码约定用于调试但不用于发布,而且更重要的是,您可以随时改变决策。 运行时检查 若要启用代码约定,必须选中“执行运行时约定检查”选项。 如果未选中此选项,则在源代码中显示的任何约定说明将可能不会产生任何效果(定义了 DEBUG 符号的任何版本中的 Contract.Assert 和 Contract.Assume 例外,但这不是很重要)。 复选框控制是否在每个编译步骤结束时触发重写程序工具。 重写程序是一个外部工具,用于对软件约定进行后处理并修改 MSIL 代码,以及在合适的位置执行前置条件、后置条件和固定条件检查。 但是,请注意,如果您具有类似下面这样的前置条件,则在关闭重写程序时会得到运行时断言失败: Contract.Requires<TException>(condition) 图 2 显示了您得到的消息框。图 2 代码需要运行时约定检查 若要详细查看运行时检查的工作方式,请考虑以下代码: Int32 Sum(Int32 x
设置,约定,代码,2018-09-30259
-
ASP.NET MVC 3和Razor中的@helper 语法
ASP.NET MVC 3支持一项名为“Razor”的新视图引擎选项(除了继续支持/加强现有的.aspx视图引擎外)。当编写一个视图模板时,Razor将所需的字符和击键数减少到最小,并保证一个快速、通畅的编码工作流。 与大部分模板的语法不同,在Razor的帮助下,您不需要中断代码编写,仅仅为了在HTML中标注服务器端代码块的开始和结束。代码分析器足够聪明,它能够从你的代码里推断出是否为服务器端代码。这种更加简洁、富有表现力的语法更加干净,输入也更快速,有趣。 今天的博文涵盖了Razor的一项很多人都不知道的功能——利用@helper语法定义可重用的帮助器方法。 简单的 @helper 方法应用场景 Razor中的@helper语法让您能够轻松创建可重用的帮助器方法,此方法可以在您的视图模板中封装输出功能。他们使代码能更好地重用,也使代码更具有可读性。让我们看一个超级简单的应用场景,它展示了@helper语法是怎样被使用的。 在我们定义@helper方法之前的代码 让我们看一个简单的产品列表应用场景。在此场景中,我们列出产品明细并输出产品的价格或是单词“免费!”——如果这个产品不花费任何成本的话: 以上代码非常直截了当,而且Razor的语法使得在HTML里能简单地集成服务器端C#代码。 然而,一个有点混乱的地方是价格的if/else逻辑。我们可能在站点的其他位置输出价格(或者在同一页面上),而复制以上逻辑很容易出错且难以维护。类似的应用场景是使用@helper语法提取和重构成为帮助器方法的首选考虑。 使用@helper语法重构以上样例 让我们提取价格输出逻辑,并将其封装在一个我们将命名为“DisplayPrice”的帮助器方法内。我们可以通过重写以下代码样例来实现此操作: 我们已经使用上述@helper语法来定义名为“DisplayPrice”的可重用帮助器方法。就像标准C#/VB方法一样,它可以包含任意数量的参数(您也可以定义参数为空或可选参数)。不过,与标准C#/VB方法不同的是,@helper方法可以同时包含内容和代码并支持其中的完整Razor语法——这使得定义和封装呈现/格式化帮助器方法变得非常简单。 您可以像调用一个标准的C#或VB方法一样,调用@helper方法: 当调用该方法时,Visual Studio会提供智能感知代码: 在多视图模式中重用@helper 在上面的实例中,我们在相同的视图模板中将@helper方法定义为调用它的代码。或者,我们可以将@helper方法定义在视图模板外,并保证其在项目的所有视图模板中可重复使用。 您可以在.cshtml/.vbhtml保存我们的@helper方法,并把这个文件放在项目根目录下创建的\App_Code目录下例如,我在\App_Code文件夹中创建了一个“ScottGu.cshtml”文件,并且在文件中定义了2个单独的帮助器方法(在每个文件中您可以有任意数量的帮助器方法): 一旦我们的帮助器定义在应用程序级别,我们就可以在应用程序的任何视图模板中使用它们。 在上面的\App_Code文件夹中的ScottGu.cshtml会逻辑编译为一个称为“ScottGu”的类。这个类中包含了“DisplayPrice” 和 “AnotherHelper”的静态成员。我们可以使用以下代码重写前面的示例来调用它: 当像如下方法调用应用程序级别帮助器时,Visual Studio将会提供智能感知代码: 5月15日更新:有一些人指出的一个问题是,当一个@helper保存在\app_code目录中时,默认情况下您不能访问其中的ASP.NET MVC Html帮助器方法。(例如Html.ActionLink()
语法,2018-09-30333
-
JAVA与.NET的相互调用——通过Web服务实现相互调用
JAVA与.NET是现今世界竞争激烈的两大开发媒体,两者语言有很多相似的地方。而在很多大型的开发项目里面,往往需要使用两种语言进行集成开发。而很多的开发人员都会偏向于其中一种语言,在使用集成开发的时候对另一种语言感觉到畏惧。在这里在下向各位介绍一下,JAVA与.NET相互调用的例子。下面的介绍主要包括三方面:一是通过常用Web服务进行相互调用,二是使用TCP/IP套接字进行相互调用,三是使用Remote实现远程对象相互调用。 在这章里面先为大家介绍一下最简单,最常用的Web服务相互调用方式。首先说一下Web服务的来源,Web服务是一种新的Web应用程序分支,可以执行从简单的请求到复杂商务处理等任何功能。一旦部署以后,其他Web服务应用程序可以发现并调用它部署的服务。 Web Service是一种应用程序,它可以使用标准的互联网协议,像超文件传输协议(HTTP)、简单对象访问协议(SOAP)、XML等,将功能纲领性地体现在互联网和企业内部网上,Web服务被视作是Web上的组件编程。Web服务必须提供一套标准的类型系统,用于沟通不同平台、编程语言和组件模型中的不同类型系统。 XML和XSD 可扩展的标记语言XML 是Web Service平台中表示数据的基本格式。除了易于建立和易于分析外,XML主要的优点在于它既与平台无关,又与厂商无关。XML是由万维网协会 (W3C)创建,W3C制定的XML SchemaXSD 定义了一套标准的数据类型,并给出了一种语言来扩展这套数据类型。 Web Service平台是用XSD来作为数据类型系统的。当你用某种语言如JAVA、C#来构造一个Web Service时,为了符合Web Service标准,所有你使用的数据类型都必须被转换为XSD类型。如想让它使用在不同平台和不同软件的不同组织间传递,还需要通过SOAP协议将它包装起来。 SOAP SOAP即简单对象访问协议(Simple Object Access Protocol),它是用于交换XML编码信息的轻量级协议。它有三个主要方面:XML-envelope为描述信息内容和如何处理内容定义了框架,将程序对象编码成为XML对象的规则,执行远程过程调用(RPC)的约定。SOAP可以运行在任何其他传输协议上。例如,你可以使用 SMTP,即因特网电子邮件协议来传递SOAP消息,这可是很有诱惑力的。在传输层之间的头是不同的,但XML有效负载保持相同。Web Service 希望实现不同的系统之间能够用“软件-软件对话”的方式相互调用,打破了软件应用、网站和各种设备之间的格格不入的状态,实现“基于Web无缝集成”的目标。 WSDL Web Service描述语言WSDL 就是用机器能阅读的方式提供的一个正式描述文档而基于XML的语言,用于描述Web Service及其函数、参数和返回值。因为是基于XML的,所以WSDL既是机器可阅读的,又是人可阅读的。 下面分开两个方面讲解一下如果通过Web服务实现JAVA与.NET的相互调用。 一、使用.NET作为服务器端,JAVA作为客户端实现相互调用。 在.NET系统里面,以WCF作为新一代的服务开发工具是微软的一个新卖点,我们就以WCF为例子实现服务器端,首先新建一个网站项目,在网站添加一个WCF服务PersonService。你将看到PersonService.svc、IPersonService、PersonService.cs三个文件,其中IPersonService是对向暴露一个接口,接口的功能由PersonService来实现,客户端则通过PersonalService.svc来寻获服务,并对其添加引用的。<%@ ServiceHost Language= Debug= Service= CodeBehind= %> System; System.Collections.Generic; System.Linq; System.Runtime.Serialization; System.ServiceModel; System.Text; Service { [ServiceContract] IPersonService { [OperationContract] IList<Person> GetList(); } PersonService : IPersonService { IList<Person> GetList() { IList<Person> personList = List<Person>(); Person person1 = Person(); person1.ID = ; person1.Age = ; person1.Name = ; personList.Add(person1); Person person2 = Person(); person2.ID = ; person2.Age = ; person2.Name = ; personList.Add(person2); Person person3 = Person(); person3.ID = ; person3.Age = ; person3.Name = ; personList.Add(person3); personList; } } } 为了使用Person能够实现远程传送,我们必须对Person进行序列化,在WCF中包括服务契约、数据契约、消息契约三部分,而数据契约正是用于对数据进行序列化处理的,如果想对WCF有进一步的了解,可以链接使用WCF实现SOA面向服务编程: System; System.Collections.Generic; System.Linq; System.Web; System.Runtime.Serialization; Service { [DataContract] Person { [DataMember] ID { ; ; } [DataMember] Name { ; ; } [DataMember] Age { ; ; } } } 数据契约里面有多种的序列化方式,包括DataContractSerializer
实现,通过,相互,调用,服务2018-09-30242
-
JAVA与.NET的相互调用——利用JNBridge桥接模式实现远程通讯
分布式开发的历史 利用Remote方式调用远程对象实现服务器与客户端之间通讯是一种常用的网络开发方式,在.NET与JAVA开发当中,对Remote远程对象早已有着足够的支持(对Remote远程对象调用有兴趣的朋友欢迎参考一下利用远程对象实现分布式开发)。 从2003年开始.NET当中就盛传着.NET Remoting远程对象调用的分布式开发,.NET Remoting主要用于管理跨应用程序域的同步和异步RPC 会话。在默认情况下,Remoting可以使用 HTTP 或 TCP 协议进行信息通讯,并使用 XML 编码的 SOAP 或二进制消息格式进行数据交换。.NET Remoting 提供了非常灵活和可扩展的编程框架
实现,通讯,模式,相互,远程2018-09-30289
-
C#技术漫谈之垃圾回收机制(GC)
摘要:今天我们漫谈C#中的垃圾回收机制,本文将从垃圾回收机制的原理讲起,希望对大家有所帮助。 GC的前世与今生 虽然本文是以.NET作为目标来讲述GC,但是GC的概念并非才诞生不久。早在1958年,由鼎鼎大名的图林奖得主John McCarthy所实现的Lisp语言就已经提供了GC的功能,这是GC的第一次出现。Lisp的程序员认为内存管理太重要了,所以不能由程序员自己来管理。 但后来的日子里Lisp却没有成气候,采用内存手动管理的语言占据了上风,以C为代表。出于同样的理由,不同的人却又不同的看法,C程序员认为内存管理太重要了,所以不能由系统来管理,并且讥笑Lisp程序慢如乌龟的运行速度。的确,在那个对每一个Byte都要精心计算的年代GC的速度和对系统资源的大量占用使很多人的无法接受。而后,1984年由Dave Ungar开发的Smalltalk语言第一次采用了Generational garbage collection的技术(这个技术在下文中会谈到),但是Smalltalk也没有得到十分广泛的应用。 直到20世纪90年代中期GC才以主角的身份登上了历史的舞台,这不得不归功于Java的进步,今日的GC已非吴下阿蒙。Java采用VM(Virtual Machine)机制,由VM来管理程序的运行当然也包括对GC管理。90年代末期.NET出现了,.NET采用了和Java类似的方法由CLR(Common Language Runtime)来管理。这两大阵营的出现将人们引入了以虚拟平台为基础的开发时代,GC也在这个时候越来越得到大众的关注。 为什么要使用GC呢?也可以说是为什么要使用内存自动管理?有下面的几个原因: 1、提高了软件开发的抽象度; 2、程序员可以将精力集中在实际的问题上而不用分心来管理内存的问题; 3、可以使模块的接口更加的清晰,减小模块间的偶合; 4、大大减少了内存人为管理不当所带来的Bug; 5、使内存管理更加高效。 总的说来就是GC可以使程序员可以从复杂的内存问题中摆脱出来,从而提高了软件开发的速度、质量和安全性。 什么是GC GC如其名,就是垃圾收集,当然这里仅就内存而言。Garbage Collector(垃圾收集器,在不至于混淆的情况下也成为GC)以应用程序的root为基础,遍历应用程序在Heap上动态分配的所有对象[2],通过识别它们是否被引用来确定哪些对象是已经死亡的、哪些仍需要被使用。已经不再被应用程序的root或者别的对象所引用的对象就是已经死亡的对象,即所谓的垃圾,需要被回收。这就是GC工作的原理。为了实现这个原理,GC有多种算法。比较常见的算法有Reference Counting,Mark Sweep,Copy Collection等等。目前主流的虚拟系统.NET CLR,Java VM和Rotor都是采用的Mark Sweep算法。 一、Mark-Compact 标记压缩算法 简单地把.NET的GC算法看作Mark-Compact算法。阶段1: Mark-Sweep 标记清除阶段,先假设heap中所有对象都可以回收,然后找出不能回收的对象,给这些对象打上标记,最后heap中没有打标记的对象都是可以被回收的;阶段2: Compact 压缩阶段,对象回收之后heap内存空间变得不连续,在heap中移动这些对象,使他们重新从heap基地址开始连续排列,类似于磁盘空间的碎片整理。 Heap内存经过回收、压缩之后,可以继续采用前面的heap内存分配方法,即仅用一个指针记录heap分配的起始地址就可以。主要处理步骤:将线程挂起→确定roots→创建reachable objects graph→对象回收→heap压缩→指针修复。可以这样理解roots:heap中对象的引用关系错综复杂(交叉引用、循环引用),形成复杂的graph,roots是CLR在heap之外可以找到的各种入口点。 GC搜索roots的地方包括全局对象、静态变量、局部对象、函数调用参数、当前CPU寄存器中的对象指针(还有finalization queue)等。主要可以归为2种类型:已经初始化了的静态变量、线程仍在使用的对象(stack+CPU register) 。 Reachable objects:指根据对象引用关系,从roots出发可以到达的对象。例如当前执行函数的局部变量对象A是一个root object,他的成员变量引用了对象B,则B是一个reachable object。从roots出发可以创建reachable objects graph,剩余对象即为unreachable,可以被回收 。 指针修复是因为compact过程移动了heap对象,对象地址发生变化,需要修复所有引用指针,包括stack、CPU register中的指针以及heap中其他对象的引用指针。Debug和release执行模式之间稍有区别,release模式下后续代码没有引用的对象是unreachable的,而debug模式下需要等到当前函数执行完毕,这些对象才会成为unreachable,目的是为了调试时跟踪局部对象的内容。传给了COM+的托管对象也会成为root,并且具有一个引用计数器以兼容COM+的内存管理机制,引用计数器为0时,这些对象才可能成为被回收对象。Pinned objects指分配之后不能移动位置的对象,例如传递给非托管代码的对象(或者使用了fixed关键字),GC在指针修复时无法修改非托管代码中的引用指针,因此将这些对象移动将发生异常。pinned objects会导致heap出现碎片,但大部分情况来说传给非托管代码的对象应当在GC时能够被回收掉。 二、 Generational 分代算法 程序可能使用几百M、几G的内存,对这样的内存区域进行GC操作成本很高,分代算法具备一定统计学基础,对GC的性能改善效果比较明显。将对象按照生命周期分成新的、老的,根据统计分布规律所反映的结果,可以对新、老区域采用不同的回收策略和算法,加强对新区域的回收处理力度,争取在较短时间间隔、较小的内存区域内,以较低成本将执行路径上大量新近抛弃不再使用的局部对象及时回收掉。分代算法的假设前提条件: 1、大量新创建的对象生命周期都比较短,而较老的对象生命周期会更长; 2、对部分内存进行回收比基于全部内存的回收操作要快; 3、新创建的对象之间关联程度通常较强。heap分配的对象是连续的,关联度较强有利于提高CPU cache的命中率,.NET将heap分成3个代龄区域: Gen 0、Gen 1、Gen 2; Heap分为3个代龄区域,相应的GC有3种方式: # Gen 0 collections
技术,机制,垃圾,回收,漫谈2018-09-30204
-
ASP.NET调用存储过程方法新解
摘要:在使用.net的过程中,数据库访问是一个很重要的部分,特别是在b/s系统的构建过程中,数据库操作几乎成为了一个必不可少的操作。 在使用.net的过程中,数据库访问是一个很重要的部分,特别是在b/s系统的构建过程中,数据库操作几乎成为了一个必不可少的操作。调用存储过程实现数据库操作使很多程序员使用的方法,而且大多数的程序员都是能使用存储过程就使用存储过程,很少直接使用sql语句,所以存储过程是很有用而且很重要的。 存储过程简介 简单的说,存储过程是由一些sql语句和控制语句组成的被封装起来的过程,它驻留在数据库中,可以被客户应用程序调用,也可以从另一个过程或触发器调用。它的参数可以被传递和返回。与应用程序中的函数过程类似,存储过程可以通过名字来调用,而且它们同样有输入参数和输出参数。 根据返回值类型的不同,我们可以将存储过程分为三类:返回记录集的存储过程, 返回数值的存储过程(也可以称为标量存储过程),以及行为存储过程。顾名思义,返回记录集的存储过程的执行结果是一个记录集,典型的例子是从数据库中检索出符合某一个或几个条件的记录;返回数值的存储过程执行完以后返回一个值,例如在数据库中执行一个有返回值的函数或命令;最后,行为存储过程仅仅是用来实现数据库的某个功能,而没有返回值,例如在数据库中的更新和删除操作。 使用存储过程的好处 相对于直接使用sql语句,在应用程序中直接调用存储过程有以下好处: (1) 减少网络通信量。调用一个行数不多的存储过程与直接调用sql语句的网络通信量可能不会有很大的差别,可是如果存储过程包含上百行sql语句,那么其性能绝对比一条一条的调用sql语句要高得多。 (2) 执行速度更快。有两个原因:首先,在存储过程创建的时候,数据库已经对其进行了一次解析和优化。其次,存储过程一旦执行,在内存中就会保留一份这个存储过程,这样下次再执行同样的存储过程时,可以从内存中直接调用。 (3) 更强的适应性:由于存储过程对数据库的访问是通过存储过程来进行的,因此数据库开发人员可以在不改动存储过程接口的情况下对数据库进行任何改动,而这些改动不会对应用程序造成影响。 (4) 分布式工作:应用程序和数据库的编码工作可以分别独立进行,而不会相互压制。 由以上的分析可以看到,在应用程序中使用存储过程是很有必要的。 两种不同的存储过程调用方法 为了突出新方法的优点,首先介绍一下在.net中调用存储过程的官方方法。另外,本文的所有示例程序均工作于SQL Server数据库上,其它情况类似,以后不再一一说明。本文所有例子均采用c#语言。 要在应用程序中访问数据库,一般性的步骤是:首先声明一个数据库连接SqlConnection,然后声明一个数据库命令SqlCommand,用来执行SQL语句和存储过程。有了这两个对象后,就可以根据自己的需要采用不同的执行方式达到目的。需要补充的是,不要忘记在页面上添加如下的引用语句:using System.Data.SqlClient。 就执行存储过程来说,如果执行的是第一类存储过程,那么就要用一个DataAdapter将结果填充到一个DataSet中,然后就可以使用数据网格控件将结果呈现在页面上了;如果执行的是第二和第三种存储过程,则不需要此过程,只需要根据特定的返回判定操作是否成功完成即可。 (1) 执行一个没有参数的存储过程的代码如下:SqlConnection conn = 2018-09-30
152
-
C#多线程与异步的区别
随着拥有多个硬线程CPU(超线程、双核)的普及,多线程和异步操作等并发程序设计方法也受到了更多的关注和讨论。本文主要是想与园中各位高手一同探讨一下如何使用并发来最大化程序的性能。 多线程和异步操作的异同 多线程和异步操作两者都可以达到避免调用线程阻塞的目的,从而提高软件的可响应性。甚至有些时候我们就认为多线程和异步操作是等同的概念。但是,多线程和异步操作还是有一些区别的。而这些区别造成了使用多线程和异步操作的时机的区别。 异步操作的本质 所有的程序最终都会由计算机硬件来执行,所以为了更好的理解异步操作的本质,我们有必要了解一下它的硬件基础。 熟悉电脑硬件的朋友肯定对DMA这个词不陌生,硬盘、光驱的技术规格中都有明确DMA的模式指标,其实网卡、声卡、显卡也是有DMA功能的。DMA就是直接内存访问的意思,也就是说,拥有DMA功能的硬件在和内存进行数据交换的时候可以不消耗CPU资源。只要CPU在发起数据传输时发送一个指令,硬件就开始自己和内存交换数据,在传输完成之后硬件会触发一个中断来通知操作完成。这些无须消耗CPU时间的I/O操作正是异步操作的硬件基础。所以即使在DOS这样的单进程(而且无线程概念)系统中也同样可以发起异步的DMA操作。 线程的本质 线程不是一个计算机硬件的功能,而是操作系统提供的一种逻辑功能,线程本质上是进程中一段并发运行的代码,所以线程需要操作系统投入CPU资源来运行和调度。 异步操作的优缺点 因为异步操作无须额外的线程负担,并且使用回调的方式进行处理,在设计良好的情况下,处理函数可以不必使用共享变量(即使无法完全不用,最起码可以减少共享变量的数量),减少了死锁的可能。当然异步操作也并非完美无暇。编写异步操作的复杂程度较高,程序主要使用回调方式进行处理,与普通人的思维方式有些初入,而且难以调试。 多线程的优缺点 多线程的优点很明显,线程中的处理程序依然是顺序执行,符合普通人的思维习惯,所以编程简单。但是多线程的缺点也同样明显,线程的使用(滥用)会给系统带来上下文切换的额外负担。并且线程间的共享变量可能造成死锁的出现。 适用范围 在了解了线程与异步操作各自的优缺点之后,我们可以来探讨一下线程和异步的合理用途。我认为:当需要执行I/O操作时,使用异步操作比使用线程+同步I/O操作更合适。I/O操作不仅包括了直接的文件、网络的读写,还包括数据库操作、Web Service、HttpRequest以及.Net Remoting等跨进程的调用。 而线程的适用范围则是那种需要长时间CPU运算的场合,例如耗时较长的图形处理和算法执行。但是往往由于使用线程编程的简单和符合习惯,所以很多朋友往往会使用线程来执行耗时较长的I/O操作。这样在只有少数几个并发操作的时候还无伤大雅,如果需要处理大量的并发操作时就不合适了。 实例研究 说了那么理论上的东西,可能有些兄弟早就不耐烦了,现在我们来研究几个实际的异步操作例子吧。 实例1:由delegate产生的异步方法到底是怎么回事? 大家可能都知道,使用delegate可以"自动"使一个方法可以进行异步的调用。从直觉上来说,我觉得是由编译器或者CLR使用了另外的线程来执行目标方法。到底是不是这样呢?让我们来用一段代码证明一下吧。 System; System.Threading; AsyncDelegateDemo { AsyncFoo( i); Program { PrintCurrThreadInfo( name) { Console.WriteLine( + name+ + Thread.CurrentThread.ManagedThreadId+ + (Thread.CurrentThread.IsThreadPoolThread ? : ) + ); } Foo( i) { PrintCurrThreadInfo(); Thread.Sleep(i); } PostAsync() { AsyncFoo caller = AsyncFoo(Foo); caller.BeginInvoke(
区别,线程,2018-09-30211
-
探讨.NET中的联合结构
摘要:本文介绍的是.NET中的联合结构,希望对你有帮助,一起来看。 关于.NET中的联合结构,我们也探讨过。下面介绍.NET中的联合结构。 在进行某些算法的C语言编程的时候,需要使几种不同类型的变量存放到同一段内存单元中。也就是使用覆盖技术,几个变量互相覆盖。这种几个不同的变量共同占用一段内存的结构,在C语言中,被称作“共用体”类型结构,简称共用体,也叫联合体。 在C++中有一种类型叫做联合体(也叫共用体),它的关键字为union,在使用上与结构struct非常相似,可以包含任何的结构类型数据,但它又有一个非常独特的特性,那就是所有的数据都指向一个地址。 这个意思你可以理解为:联合体中的所有数据都是引用一个内存块中相同地址的数据,当我们改变这个联合体内任何一种数据的值时,其他的数据的值都会随之改变。 这对于未知类型的数据非常有效,你可以使用联合体装载一个数据,然后分析其数据是否有效,或者可以对某些特殊的类型进行位运算,获取其特殊位置的数值。 但在VB.NET或C#中,根本没有union关键字让我们声名联合体,但该怎么做才能声名联合体呢? 这需要用到结构属性! 让我们看看如何将下面的C++联合体代码转换为一个VB.NET的联合结构吧! 2018-09-30
154
-
探讨:ASP.NET技术的学习顺序问题
摘要:很多人对于ASP.NET的入门和学习顺序比较迷茫,今天让我们一起来跟随作者的思路学习探讨ASP.NET的学习顺序问题,希望有所帮助。 如果你已经有较多的面向对象开发经验,跳过以下这两步: 第一步 掌握一门.NET面向对象语言,C#或VB.NET。 我强烈反对在没系统学过一门面向对象(OO)语言的前提下去学ASP.NET。 ASP.NET是一个全面向对象的技术,不懂OO,那绝对学不下去! 第二步 对.NET Framewor
探讨,顺序,问题,学习,技术2018-09-30165
-
C#初学者对Equals方法的几个常见误解
摘要:很多C#的教材都会强调对象相等的概念。我们都知道,在C#的世界里存在两种等同性。一种是逻辑等同性,另一种是引用等同性。 很多C#的教材都会强调对象相等的概念。我们都知道,在C#的世界里存在两种等同性。一种是逻辑等同性:如果两个对象在逻辑上代表同样的值,则称他们具有逻辑等同性。另一种是引用等同性:如果两个引用指向同一个对象实例,则称他们具有引用等同性。 众所周知,Object类型有一个名为Equals的实例方法可以用来确定两个对象是否相等。Object的Equals的默认实现比较的是两个对象的引用等同性。而Object的派生类ValueTpye重写了Equals方法,它比较的是两个对象的逻辑等同性。也就是说,在C#里,引用类型的默认Equals版本关注的是引用等同性,而值类型关注的是逻辑等同性。当然,这并不总能满足我们的要求。所以每当我们更在意引用类型的逻辑等同性的时候,我们就应该重写Equals方法。 重写引用类型的Equals方法以改变其默认的比较方式的一个著名例子是String类。当我们写出string1.Equals(string2)这样的代码时,我们比较的不是string1和string2这两个引用所指向的是否为同一个实例(引用等同性),而是比较string1与string2所包含的字符序列是否相同(逻辑等同性)。 误解一:Equals方法和operator==具有相同的默认行为。 对于引用类型,如果没有为它重载==操作符,且其父类型也没有重写Equals方法,则这个引用类型Equals方法和operator==具有相同的默认行为,即它们比较的都是对象的引用等同性。然而对于值类型来说,就完全不是这么回事了!因为如果你没有为自定义值类型重载operator==的话,就不能写这样的代码myStruct1 == myStruct2,否则会得到一个编译错误,原因是值类型没有相等操作符重载的默认实现。 误解二:自定义类的Equals的方法默认实现将自动调用operator==方法,或operator==方法的默认实现将自动调用Equals方法。 经常听到有人说某某类型是引用类型,所以它的Equals方法的默认实现将自动调用operator==方法。这种说法完全是没有道理的。正如上文所说的,引用类型Equals方法的默认实现来自Object,而值类型的默认实现来自TypeValue,就算他们会使用==操作符,使用的也是Object或TypeValue的重载版本。原则上来说,只要我们没有重写一个类的Equals方法,那么它就会继承其父类的实现,而父类是没有机会使用子类型的操作符重载的。同样,只要我们没有在一个类的==操作符重载中调用Equals方法,它是不会自动调用的。 误解三:值类型的默认Equals实现是对两个对象进行逐位比较的。 有些人认为值类型的Equals默认实现就是通过比较两个对象在内存中的位表示,即如果所有的二进制位都相等,则说明这两个对象等同。这是不准确的。因为其实值类型的Equals默认实现是对值类型的每个字段都调用该字段类型的Equals方法,如果所有字段的Equals方法都返回true,则他们才可能相等。来看一个例子: 2018-09-30
180
-
[WCF安全系列]消息的保护等级
到目前为止,对于WCF安全传输的三个方面,我们已经对认证进行了详细的介绍,现在我们来关注另外两个话题:消息的一致性和机密性,两者又统称为消息保护(Message Protection)。消息的安全等级指的是对整个消息或者消息的某个部分事实安全保护采用的等级。按照级别的由低到高,WCF支持如下三种不同的安全等级。在WCF的应用编程接口中,消息保护级别通过如下定义的ProtectionLevel枚举表示。None: 不采用任何措施来保护消息的一致性和机密性;Sign: 通过对整个消息或者消息的某个部分进行数字签名以确保消息的一致性;EncryptAndSign: 通过对整个消息或者消息的某个部分同时进行签名和加密确保消息的一致性和机密性。 2018-09-30
179
-
一句话清晰总结协变(covariant)和逆变 (contravariant)
看到过园子里面几篇协变和逆变的文章,但是总觉得写得不够清晰,文章这东西最重要的是要把自己想表达的观点表达出来,这个过程应该是把复杂的东西消化出来从而简单化,清晰化,而不是故弄玄虚,反其道而行之,下面我们言归正传啦。 我们先来看一段MSDN原文给协变,逆变
一句话,清晰,总结,逆变,2018-09-30229