作者:veryhappy(wx.net)
在Visual Studio 2003下开发网站的都知道ASP.NET 1.1网站生成后都是一个唯一命名的程序集(项目名称.DLL),但是这种情况在Visual Studio 2005的网站开发中不见了。Visual Studio 2005给我们提供了“发布网站”这样方便的功能,不用在像以前一样COPY的部署,但是采用其“发布网站”的功能,会在站点的BIN目录中产生App_Code.compiled,App_Code.dll,App_Web_xxxxxx.dll,项目名称.dll等等这样的程序集,如果不采用预编译的方式那么产生的文件会更加的多,因为很多都是随机命名也没有什么规律可言;这样会给那些想COPY更新的人带来不便,因为原来的文件不能被覆盖,需要先删除再COPY;有很多时候可能就是更新了后台代码,直接生成项目或是WEB的程序集,像以前一样直接覆盖DLL的方式也很简单。
也许很多人不会考虑BIN下存放的东西,只要站点能运行就好了,那么这样的人读到这里也就没有必要再看此文章,要知道时间是宝贵的,浪费在自己不关心的事情上很不值得的。
上面罗嗦了一堆,下面笔者将介绍采用Microsoft Web Deployment Projects在Visual Studio 2005中生成唯一程序集的方法。
关于Microsoft Web Deployment Projects工具可以从微软站点获得详尽的资料,我也没什么好说的了微软写的很清楚了,呵呵。
下载地址:
http://msdn.microsoft.com/asp.net/reference/infrastructure/wdp/default.aspx
详细使用:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/web_deployment_projects.asp
安装后在“生成”和WEB项目的上下文菜单看到“Add Web Deployment Project…”,好了添加一个Web Deployment Project项目,起一个名称,这个名称就是将来编译后生成的程序集名称,默认的名称“当前项目名称_deploy”
双击Web Deployment Project的项目出现属性页面
Compilation中的Output Folder设置项目输出路径
Output Assemblies中的四大选项:
n Merge all outputs to a single assembly-所有输出都编译成一个程序集(参数:程序集名称)
n Treat as library component (remove the App_Code.compiled file)-App_Code视为类库(删除App_Code.compiled文件)
n Merge each individual folder output to its own assembly-WEB项目中单独的目录会编译到一个程序集中(参数:程序集前缀)
n Merge all pages and control outputs to a single assembly-所有页面控件编译到一个程序集中(参数:程序集名称)
n Create a separate assembly for each page and control output-为每一个页面和控件创建程序集
Signing使用key文件建立强命名空间的程序集
Deployment
n Enable Web.config file section replacement-用不同的config文件替换Web.config中的节点
n Create an IIS virtual directory for the output folder-创建IIS虚拟目录(参数:虚拟目录名称)
n Remove the App_Data folder from output location-删除输出目录中的App_Data目录
好了通过简单的设置,就可以生成一个看上去非常“干净利落”的bin目录,每个程序集都很明显,对部分升级工作很有帮助。
2006-6
实际上在我们的一个实际ASP.NET 2.0的解决方案中来应用这种方式出现了问题,下面我就讲一下我的解决过程希望对大家有所帮助。
我们的解决方案包括22个项目(主要是类库),其中的一个WEB项目是负责用户UI的,传统的生成或是发布网站的方式没有任何问题,当使用Web Deployment Projects工具生成唯一程序集时出现了错误信息“Aspnet_merge.exe Exited with Code 1”(Aspnet_merge.exe 退出,错误代码1),这样的信息根本无法让我们办断到底是哪里出了问题。好,下面依次打开VS 2005的工具-选项-项目和解决方案-生成并运行,设置“MSBuild 项目生成输出详细信息”,选择“详细”。再次生成Web Deployment Projects项目,注意“输出”框内的信息现在变得非常丰富了,最后导致无法编译的问题终于出来了“An error occurred when merging assemblies: ILMerge.Merge: ERROR!!: Duplicate type ‘_Default’ found in assembly 'App_Web_k5hhsnh0'”,它的意思是说在程序集中发现了相同的类型_Default,经过我检查确实在我们的WEB项目中存在了两个_Default类(在不同的目录中),这样的问题通过一般的生成完成和发布网站肯定都是检测不出来的,运行也是正常的。VS 2005的WEB项目默认的把命名空间给去掉了,可以手动增加一个命名空间,cs代码中加入namespace的语句块,另外别忘了在aspx文件的<@page>的Inherits中写入对应的[namespace].[类名];经过这样的操作再次编译成一个程序集就没有问题了(备注:这个项目前后一共发现了5对类名称一致的情况,加上命名空间或是改名称就可以解决了)。
上面就是结合我的项目实际解决的问题,暂时还没有发现别的错误出来。使用有问题的朋友也多多交流。
aspnet的内部运行机制:
remote client Request---->IIS---->aspnet_isapi.dll-->aspnet_wp.exe-->HttpRuntime--->
HttpModule--->HttpHandler Factory--->HttpHandler--->HttpHandler.ProcessRequest()-->
Response client Request
最近的一项工作是关于性能提升方面的。要做的第一个事情是要把很多同类型的DataTable合并到一起,查了很多关于DataTable的相关函数以后,我决定用Merge函数来合并这些DataTable。
DataTable[] srcTables = ... ;
foreach( DataTable src in srcTables )
{
dest.Merge( src ) ;
}
但是测试的结果让我很是失望,性能不是一般的不好。经过调查发现性能的瓶颈在Merge函数这里。后来经过测试,发现如果用下面的代码:
DataTable[] srcTables = ... ;
foreach( DataTable src in srcTables )
{
foreach( DataRow row in src.Rows)
{
dest.ImportRow( row ) ;
}
}
结果让人惊奇的是,下面的代面的速度是上面的代码速度的100倍!
还做了一个事情,就是对DataTable进行filter的时候 ,我的一个同事和我说了以下的代码:
DataView dv = dt.DefaultView ;
dv.RowFilter = filter ;
DataTable result = dv.ToTable() ;
上面的代码是能工作的,但是它的性能一点都不好,后来我把上面的代码改成了:
DataRow[] rows = dv.Select( filter ) ;
foreach( DataRow row in rows )
{
result.ImportRow(row) ;
}
也有数十倍的性能提高。
网上搜索的这篇文章都缺少示例和图片,在此补齐,发个完整版。
一、返回多个数据集
检查你的访问数据库的代码,看是否存在着要返回多次的请求。每次往返降低了你的应用程序的每秒能够响应请求的次数。通过在单个数据库请求中返回多个结果集,可以减少与数据库通信的时间,使你的系统具有扩展性,也可以减少数据库服务器响应请求的工作量。
如果你是用动态的SQL语句来返回多个数据集,那我建议你用存储过程来替代动态的SQL语句。是否把业务逻辑写到存储过程中,这个有点争议。但是我认为,把业务逻辑写到存储过程里面可以限制返回结果集的大小,减小网络数据的流量,在逻辑层也不用在过滤数据,这是一个好事情。
用SqlCommand对象的ExecuteReader方法返回一个强类型的业务对象,再调用NextResult方法来移动数据集指针来定位数据集。示例一演示了一个返回多个ArrayList强类型对象的例子。只从数据库中返回你需要的数据可以大大的减小你的服务器所耗用的内存。
// read the first resultset
reader = command.ExecuteReader();
// read the data from that resultset
while (reader.Read()) {
suppliers.Add(PopulateSupplierFromIDataReader( reader ));
}
// read the next resultset
reader.NextResult();
// read the data from that second resultset
while (reader.Read()) {
products.Add(PopulateProductFromIDataReader( reader ));
}
二、对数据进行分页
ASP。NET的DataGrid有一个非常有用的功能:分页。如果DataGrid允许分页,在某一时刻它只下载某一页的数据,另外,它有一个数据分页的济览导航栏,它让你可以选择浏览某一页,而且每次只下载一页的数据。
但是它有一个小小的缺点,就是你必须把所有的数据都绑定到DataGrid中。也就是说,你的数据层必须返回所有的数据,然后DataGrid再根据当前页过滤出当前页所需要的数据显示出来。如果有一个一万条记录的结果集要用DataGrid进行分页,假设DataGrid每页只显示25条数据,那就意味着每次请求都有9975条数据都是要丢弃的。每次请求都要返回这么大的数据集,对应用程序的性能影响是非常大的。
一个好的解决方案是写一个分页的存储过程,例子2是一个用于对Northwind数据库orders表的分页存储过程。你只需要传当前页码,每页显示的条数两个参数进来,存储过程会返回相应的结果。
在服务器端,我专门写了一个分页的控件来处理数据的分页,在这里,我用了第一个方法,在一个存储过程里面返回了两个结果集:数据记录总数和要求的结果集。
返回的记录总数取决于要执行查询,例如,一个where条件可以限制返回的结果集的大小。因为在分页界面中必须要根据数据集记录的大小来计算总的页数,所以必须要返回结果集的记录数。例如,如果一共有1000000条记录,如果用where条件就可以过滤成只返回1000条记录,存储过程的分页逻辑应该知道返回那些需要显示的数据。
--Paging Through the Orders Table
CREATE PROCEDURE northwind_OrdersPaged
(
@PageIndex int,
@PageSize int
)
AS
BEGIN
DECLARE @PageLowerBound int
DECLARE @PageUpperBound int
DECLARE @RowsToReturn int
-- First set the rowcount
SET @RowsToReturn = @PageSize * (@PageIndex + 1)
SET ROWCOUNT @RowsToReturn
-- Set the page bounds
SET @PageLowerBound = @PageSize * @PageIndex
SET @PageUpperBound = @PageLowerBound + @PageSize + 1
-- Create a temp table to store the select results
CREATE TABLE #PageIndex
(
IndexId int IDENTITY (1, 1) NOT NULL,
OrderID int
)
-- Insert into the temp table
INSERT INTO #PageIndex (OrderID)
SELECT
OrderID
FROM
Orders
ORDER BY
OrderID DESC
-- Return total count
SELECT COUNT(OrderID) FROM Orders
-- Return paged results
SELECT
O.*
FROM
Orders O,
#PageIndex PageIndex
WHERE
O.OrderID = PageIndex.OrderID AND
PageIndex.IndexID > @PageLowerBound AND
PageIndex.IndexID < @PageUpperBound
ORDER BY
PageIndex.IndexID
END
三、连接池
用TCP来连接你的应用程序与数据库是一件昂贵的事情(很费时的事情),微软的开发者可以通过用连接池来反复的使用数据库的连接。比起每次请求都用TCP来连一次数据库,连接池只有在不存在有效的连接时才新建一个TCP连接。当关闭一个连接的时候,它会被放到池中,它仍然会保持与数据库的连接,这样就可以减少与数据库的TCP连接次数。
当然,你要注意那些忘记关的连接,你应在每次用完连接后马上关闭它。我要强调的是:无论什么人说.net framework中的GC(垃圾收集器)总会在你用完连接对象后调用连接对象的Close或者Dispose方法显式的关闭你的连接。不要期望CLR会在你想象的时间内关掉连接,虽然CLR最终都要销毁对象和关闭边接,但是我们并不能确定它到底会在什么时候做这些事情。
要用连接池优化,有两条规则,第一,打开连接,处理数据,然后关闭连接。如果你必须在每次请求中多次打开或关闭连接,这好过一直打开一个边接,然后把它传到各个方法中。第二,用相同的连接字符串(或者用相同的用户标识,当你用集成认证的时候)。如果你没有用相同的连接字符串,如你用基于登录用户的连接字符串,这将不能利用连接池的优化功能。如果你用的是集成的论证,因为用户很多,所以你也不能充分利用连接池的优化功能。.NET CLR提供了一个数据性能计数器,它在我们需要跟踪程序性能特性的时候非常有用,当然也包括连接池的跟踪了。
无论你的应用程序什么时候要连在另一台机子的资源,如数据库,你都应该重点优化你连资源所花的时间,接收和发送数据的时间,以及往返回之间的次数。优化你的应用程序中的每一个处理点(process hop),它是提高你的应用的性能的出发点。
应用程序层包含与数据层连接,传送数据到相应的类的实例以及业务处理的逻辑。例如,在Community Server中,要组装一个Forums或者Threads集合,然后应用业务逻辑,如授权,更重要的,这里要完成缓存逻辑。
四、ASP.NET缓存API
在写应用程序之前,你要做的第一件事是让应用程序最大化的利用ASP.NET的缓存功能。
如果你的组件是要在Asp.net应用程序中运行,你只要把System.Web.dll引用到你的项目中就可以了。然后用HttpRuntime.Cache属性就可访问Cache了(也可以通过Page.Cache或HttpContext.Cache访问)。
有以下几条缓存数据的规则。第一,数据可能会被频繁的被使用,这种数据可以缓存。第二,数据的访问频率非常高,或者一个数据的访问频率不高,但是它的生存周期很长,这样的数据最好也缓存起来。第三是一个常常被忽略的问题,有时候我们缓存了太多数据,通常在一台X86的机子上,如果你要缓存的数据超过800M的话,就会出现内存溢出的错误。所以说缓存是有限的。换名话说,你应该估计缓存集的大小,把缓存集的大小限制在10以内,否则它可能会出问题。在Asp.net中,如果缓存过大的话也会报内存溢出错误,特别是如果缓存大的DataSet对象的时候。
这里有几个你必须了解的重要的缓存机制。首先是缓存实现了“最近使用”原则( a least-recently-used algorithm),当缓存少的时候,它会自动的强制清除那些无用的缓存。其次 “条件依赖”强制清除原则(expiration dependencies),条件可以是时间,关键字和文件。以时间作为条件是最常用的。在asp.net2.0中增加一更强的条件,就是数据库条件。当数据库中的数据发生变化时,就会强制清除缓存。要更深入的了解数据库条件依赖请看Dino Esposito 在MSDN杂志2004年七月刊的Cutting Edge专栏文章。Asp.net的缓存架构如下图所示:
五、预请求缓存
在前面,我提到过即使我们只对某些地方作了一个小小的性能改进也可以获得大的性能提升,我非常喜欢用预请求缓存来提升程序的性能。
虽然Cache API设计成用来保存某段时间的数据,而预请求缓存只是保存某个时期的某个请求的内容。如果某个请求的访问频率高,而且这个请求只需要提取,应用,修改或者更新数据一次。那么就可以预缓存该请求。我们举个例子来说明。
在CS的论坛应用程序中,每一个页面的服务器控件都要求得到用于决定它的皮肤(skin)的自定义的数据,以决定用哪个样式表及其它的一些个性化的东西。这里面的某些数据可能要长时间的保存,有些时间则不然,如控件的skin数据,它只需要应用一次,而后就可以一直使用。
要实现预请求缓存,用Asp.net 的HttpContext类,HttpContext类的实例在每一个请求中创建,在请求期间的任何地方都可以通过HttpContext.Current属性访问。HttpContext类有一个Items集合属性,在请求期间所有的对象和数据都被添加到这个集合中缓存起来。和你用Cache缓存访问频率高数据一样,你可以用HttpContext.Items缓存那些每个请求都要用到的基础数据。它背后的逻辑很简单:我们向HttpContext.Items中添加一个数据,然后再从它里面读出数据。
六、后台处理
通过上面的方法你的应用程序应该运行得很快了,是不是?但是在某些时候,程序中的一次请求中可能要执行一个非常耗时的任务。如发送邮件或者是检查提交的数据的正确性等。
当我们把asp.net Forums 1.0集成在CS中的时侯,发现提交一个新的帖子的时候会非常的慢。每次新增一个帖子的时侯,应用程序首先要检查这个帖子是不是重复提的,然后用“badword”过滤器来过滤,检查图片附加码,作帖子的索引,把它添加到合适的队列中,验证它的附件,最后,发邮件到它的订阅者邮件箱中。显然,这个工作量很大。
结果是它把大量的时间都花在做索引和发送邮件中了。做帖子的索引是一项很耗时的操作,而发邮件给订阅都需要连接到SMTP服务,然后给每一个订阅者都发一封邮件,随着订阅用户的增加,发送邮件的时间会更长。
索引和发邮件并不需要在每次请求时触发,理想状态下,我们想要批量的处理这些操作,每次只发25封邮件或者每隔5分钟把所有的要发的新邮件发一次。我们决定使用与数据库原型缓存一样的代码,但是失败了,所以又不得不回到VS.NET 2005。
我们在System.Threading命名空间下找到了Timer类,这个类非常有用,但却很少有人知道,Web开发人员则更少有人知道了。一旦他建了该类的实例,每隔一个指定的时间,Timer类就会从线程池中的一个线程中调用指定的回调函数。这意味着你的asp.net应用程序可以在没有请求的时候也可以运行。这就是后以处理的解决方案。你就可以让做索引和发邮件工作在后台运行,而不是在每次请求的时候必须执行。
后台运行的技术有两个问题,第一是,当你的应用程序域卸载后,Timer类实例就会停止运行了。也就是不会调用回调方法了。另外,因为CLR的每个进程中都有许多的线程在运行,你将很难让Timer获得一个线程来执行它,或者能执行它,但会延时。Asp.net层要尽量少的使用这种技术,以减少进程中线程的数量,或者只让请求用一小部分的线程。当然如果你有大量的异步工作的话,那就只能用它了。
你可以从http://www.rob-howard.net/中下载示例程序,请下载Blackbelt TechEd 2004的示例程序。
七、页面输出缓存和代理服务
Asp.net是你的界面层(或者说应该是),它包含页面,用户控件,服务器控件(HttpHandlers 和HttpModules)以及它们生成的内容。如果你有一个Asp.net页面用来输出html,xml,imgae或者是其它的数据,对每一个请求你都用代码来生成相同的输出内容,你就很有必要考虑用页面输出缓存了。
你只要简单的把下面的这一行代码复制到你的页面中就可以实现了:<%@ PageOutputCache VaryByParams=”none” Duration=”60” %> 你就可以有效的利用第一次请求里生成的页面输出缓存内容,60秒后重新生成一道页面内容。这种技术其实也是运用一些低层的Cache API来实现。用页面输出缓存有几个参数可以配置,如上面所说的VaryByParams参数,该参数表示什么时候触发重输出的条件,也可以指定在Http Get或Http Post 请求模式下缓存输出。例如当我们设置该参数为VaryByParams=”Report”的时候,default.aspx?Report=1或者default.aspx?Report=2请求的输出都会被缓存起来。参数的值可以是多个用分号隔开参数。
许多人都没有意识到当用页面输出缓存的时候,asp.net也会生成HTTP头集(HTTP Header)保存在下游的缓存服务器中,这些信息可以用于Microsoft Internet安全性中以及加速服务器的响应速度。当HTTP缓存的头被重置时,请求的内容会被缓在网络资源中,当客户端再次请求该内容时,就不会再从源服务器上获得内容了,而直接从缓存中获得内容。
虽然用页面输出缓存不提高你的应用程序性能,但是它能减少了从的服务器中加载已缓存页面内容的次数。当然,这仅限于缓存匿名用户可以访问的页面。因为一旦页面被缓存后,就不能再执行授权操作了。
八、 用IIS6.0的Kernel Caching
如果你的应用程序没用运行在IIS6.0(windows server 2003)中,那么你就失去了一些很好的提高应用程序性能的方法。在第七个方法中,我讲了用页面输出缓存提高应用程序的性能的方法。在IIS5.0中,当一个请求到来到IIS后,IIS会把它转给asp.net,当应用了页面输出缓存时,ASP.NET中的HttpHandler会接到该请求,HttpHandler从缓存中把内容取出来并返回。
如果你用的是IIS6.0,它有一个非常好的功能就是Kernel Caching,而且你不必修改asp.net程序中任何代码。当asp.net接到一个已缓存的请求,IIS的Kernel Cache会从缓存中得到它的一份拷贝。当从网络中传来一个请求的时,Kernel层会得到该请求,如果该请求被缓存起来了,就直接把缓存的数据返回,这样就完工了。这就意味着当你用IIS的Kernel Caching来缓存页面输出时,你将获得不可置信的性能提升。在开发VS.NET 2005的 asp.net时有一点,我是专门负asp.net性能的程序经理,我的程序员用了这个方法,我看了所有日报表数据,发现用kernel model caching的结果总是最快的。它们的一个共同的特征就是网络的请求和响应量很大,但IIS只占用了5%的CPU资源。这是令人惊奇的。有许多让你使用用IIS6.0的理由,但kernel cashing是最好的一个。
九、 用Gzip压缩数据
除非你的CPU占用率太高了,才有必要用提升服务器性能的技巧。用gzip压缩数据的方法可以减少你发送到服务端的数据量,也可以提高页面的运行速度,同时也减少了网络的流量。怎么样更好的压缩数据取决于你要发送的数据,还有就是客户端的浏览器支不支持(IIS把用gzip压缩后的数据发送到客户端,客户端要支持gzip才能解析,IE6.0和Firefox都支持)。这样你的服务器每秒能多响应一些请求,同样,你也减少了发送响应的数据量,也就能多发送一些请求了。
好消息,gzip压缩已经被集成在IIS6.0中了,它比IIS5.0中gzip更好。不幸的是,在IIS6.0中启用gzip压缩,你不能在IIS6.0的属性对话中设置。IIS开发团队把gzip压缩功能开发出来了,但他们却忘了在管理员窗口中让管理员能很方便的启用它。要启用gzip压缩,你只能深入IIS6.0的xml配置文件中修改它的配置。
除了阅读本文以外,只好再看看Brad Wilson写的 IIS6 压缩一文:http://www.dotnetdevs.com/articles/IIS6compression.aspx;另外还有一篇介绍aspx压缩基础知识的文章,Enable ASPX Compression in IIS。但是要注意,在IIS6中动态压缩和kernel cashing是互斥的。
十、 服务器控件的ViewState
ViewState是asp.net中的一个特性,它用于把生成页面要用的一状态值保存在一个隐藏域中。当页面被回传到服务器时,服务器要解析,校验和应用ViewState中的数据以还原页面的控件树。ViewState是一个非常有用的特性,它能持久化客户端的状态而不用cookie或者服务器的内存。大部分的服务器控件都是用ViewState来持久化那些在页面中与用户交互的元素的状态值。例如,用以保存用于分页的当前页的页码。
用ViewState会带来一些负面的影响。首先,它加大的服务器的响应和请求的时间。其次,每次回传时都增加了序列化和反序列化数据的时间。最后,它还消耗了服务器更多的内存。
许多的服务器控件很趋于使用ViewState,如众所周知的DataGrid,而有时候是没有必须使用的。默认情况下是允许使用ViewState的,如果你不想使用ViewState的话,你可以在控件或页面级别把关闭它。在控件中,你只要把EnableViewState属性设为False就可以了;你也可以在页面中设置,使它的范围扩展到整个页面中: <%@ Page EnableViewState=”false” %> 如果页面无需回传或者每次请求页面只是呈现控件。你就应该在页面级别中把ViewState关掉。
原文:http://msdn.microsoft.com/msdnmag/issues/05/01/ASPNETPerformance/default.aspx (英文)
如题,如果发现网站访问速度突然变慢。可以试着加大Sql server最大内存的值,可以显著提高访问速度。
当然,最好的解决方法还是优化网站程序。
PS:大网站要记得禁止IIS写入网站日志,禁止后重启IIS。
1 System.IO.Stream iStream = null;
2
3 // Buffer to read 10K bytes in chunk:
4 byte[] buffer = new Byte[10240];
5
6 // Length of the file:
7 int length;
8
9 // Total bytes to read:
10 long dataToRead;
11
12 // Identify the file to download including its path.
13 string filepath = @"E:\software\SQL Server 2000 Personal Edition.ISO";
14
15 // Identify the file name.
16 string filename = System.IO.Path.GetFileName(filepath);
17
18 try
19 {
20 // Open the file.
21 iStream = new System.IO.FileStream(filepath, System.IO.FileMode.Open,
22 System.IO.FileAccess.Read,System.IO.FileShare.Read);
23 Response.Clear();
24
25 // Total bytes to read:
26 dataToRead = iStream.Length;
27
28 long p = 0;
29 if(Request.Headers["Range"]!=null)
30 {
31 Response.StatusCode = 206;
32 p = long.Parse( Request.Headers["Range"].Replace("bytes=","").Replace("-",""));
33 }
34 if(p != 0)
35 {
36 Response.AddHeader("Content-Range","bytes " + p.ToString() + "-" + ((long)(dataToRead - 1)).ToString() + "/" + dataToRead.ToString());
37 }
38 Response.AddHeader("Content-Length",((long)(dataToRead-p)).ToString());
39 Response.ContentType = "application/octet-stream";
40 Response.AddHeader("Content-Disposition", "attachment; filename=" + System.Web.HttpUtility.UrlEncode(Request.ContentEncoding.GetBytes(filename)));
41
42 iStream.Position = p;
43 dataToRead = dataToRead - p;
44 // Read the bytes.
45 while (dataToRead > 0)
46 {
47 // Verify that the client is connected.
48 if (Response.IsClientConnected)
49 {
50 // Read the data in buffer.
51 length = iStream.Read(buffer, 0, 10240);
52
53 // Write the data to the current output stream.
54 Response.OutputStream.Write(buffer, 0, length);
55
56 // Flush the data to the HTML output.
57 Response.Flush();
58
59 buffer= new Byte[10240];
60 dataToRead = dataToRead - length;
61 }
62 else
63 {
64 //prevent infinite loop if user disconnects
65 dataToRead = -1;
66 }
67 }
68 }
69 catch (Exception ex)
70 {
71 // Trap the error, if any.
72 Response.Write("Error : " + ex.Message);
73 }
74 finally
75 {
76 if (iStream != null)
77 {
78 //Close the file.
79 iStream.Close();
80 }
81 Response.End();
82 }
83
概要
SQL Server 身份验证(标准安全性)和 Windows NT 身份验证(集成安全性)都是用来从 Active Server Page (ASP) 访问 SQL Server 数据库的 SQL Server 身份验证方法。
注意:本文不适用于 Microsoft Windows 2000 Active Directory 域。本文所讨论的 Microsoft Windows NT 身份验证模式仅适用于 Windows NT 域。
回到顶端
更多信息
SQL Server 身份验证
SQL Server 身份验证依赖于 SQL Server 计算机维护的内部用户列表。该列表不包含 Windows NT 用户并且是特定于 SQL Server 计算机的。可以使用 SQL Server 企业管理器创建和配置用户。要使用此身份验证方法,请执行下列步骤:
• |
如果通过开放式数据库连接 (ODBC) 进行连接,在 ODBC 管理器中配置数据源时,请选择 SQL Server 身份验证。 |
• |
在 ActiveX 数据对象 (ADO) 连接字符串中,使用 ODBC 时应包括参数“UID”和“PWD”;使用 SQLOLEDB 提供程序时应包括参数“User ID”和“Password”。 |
Windows NT 身份验证
运行 SQL Server 的计算机允许通过 Windows NT 帐户访问其数据。要启用 Windows NT 身份验证,必须通过 Internet Information Server (IIS) 计算机为 Web 应用程序启用基本身份验证。为此,请执行下列步骤:
1. |
启动 Internet 服务管理器。 |
2. |
浏览到网站,右键单击该网站,然后单击属性。 |
3. |
单击目录安全性选项卡,单击“匿名访问和身份验证控制”下的编辑,然后选择基本身份验证(密码以明文形式发送)选项。 |
要配置 IIS 以实现 Windows NT 身份验证,您不能使用 Windows NT 质询/响应 (NTLM) 身份验证。必须使用下面两种 IIS 身份验证方法中的一种:
• |
仅为 Web 应用程序启用基本身份验证。 |
• |
如果允许用户进行匿名访问,请验证以下内容:
• |
如果在 IIS 中将用户配置为匿名用户,则还必须在运行 SQL Server 的计算机上的 Windows NT 帐户中配置它们。 |
• |
如果 SQL Server 和 IIS 不在同一台计算机上,则应将用户创建为可访问这两台计算机的域帐户,或者使用同一密码在 SQL Server 计算机和 IIS 计算机上本地创建用户。如果在这两台计算机上本地创建用户,则必须在 SQL Server 计算机上授予该用户本地登录的权限。如果用户是一个域帐户,则必须在 SQL Server 计算机上授予该用户“从网络访问此计算机”的权限。 |
• |
如果 SQL Server 和 IIS 不在同一台计算机上,则应启动 Internet 服务管理器(位于 Web 应用程序的“目录安全性”属性页上),打开匿名用户帐户对话框,禁用启用自动密码同步选项,然后手动输入帐户密码。 |
• |
IIS 计算机需要使用该用户密码生成一个在另一台服务器上仍然有效的安全令牌。启用启用自动密码同步选项时,则只能为本地计算机生成令牌。 |
• |
如果 IIS 和 SQL Server 位于同一台计算机上,则连接字符串和 ODBC 配置数据源(如果适用)中 SQL Server 数据源的名称将是本地名称。 |
|
此外,还应执行下列步骤以便在 ASP 中使用 Windows NT 身份验证连接到 SQL Server 计算机:
1. |
如果通过 ODBC 进行连接,在 ODBC 管理器中配置数据源时,请选择 Windows NT 身份验证。 |
2. |
在 ActiveX 数据对象 (ADO) 连接字符串中,使用 ODBC 时应省略参数“UID”和“PWD”,使用 SQLOLEDB 提供程序时应省略参数“User ID”和“Password”。 |
3. |
如果使用用于 SQL Server 的 OLEDB 提供程序 (Provider=SQLOLEDB) 进行连接,则连接字符串必须包括“Integrated Security=SSPI”。 |
4. |
在 SQL Server 企业管理器中,将需要通过集成安全性访问的所有 Windows NT 帐户和组添加到登录中,并将它们定义为使用 Windows NT 身份验证。为了简化管理,Microsoft 建议您添加 Windows NT 组而不是单个帐户。在定义帐户时,将权限配置到所有必需的数据库、表和存储过程中。 |
下列错误消息表明用于 Windows NT 身份验证的 SQL Server 配置存在问题:
Microsoft OLE DB Provider for ODBC Drivers (0x80040E4D)
[Microsoft][ODBC SQL Server Driver][SQL Server]Login failed for user '\'.
Microsoft OLE DB Provider for ODBC Drivers error '80040e4d'
[Microsoft][ODBC SQL Server Driver][SQL Server]Login failed for user 'NT AUTHORITY\ANONYMOUS LOGON'.
来源:
http://support.microsoft.com/kb/247931/zh-cn?spid=2852&sid=global
摘要: 以下是本人对
.Net
平台开发实践的一些点滴总结。这里的技术规范主要是开发过程的代码规范、数据库设计规范、
Com
和
.Net
互操作规范;实践精华是对技术实践过程中的部分总结。
一、代码规范
...
阅读全文
asp.net:
Data Source=.;Integrated Security=SSPI;Initial Catalog=MaxpcNew
asp:
Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=pubs;Data Source=.
用正则匹配的方式:
Javascript:1 function getQueryString(name)
2 {
3 var reg = new RegExp("(^|\\?|&)"+ name +"=([^&]*)(\\s|&|$)", "i");
4 if (reg.test(location.href)) return unescape(RegExp.$2.replace(/\+/g, " "));
5 return "";
6 }
分解链接的方式:
Javascript:
<script type="text/javascript">
<!--
function getQueryString(name)
{
// 如果链接没有参数,或者链接中不存在我们要获取的参数,直接返回空
if(location.href.indexOf("?")==-1 || location.href.indexOf(name+'=')==-1)
{
return'';
}
// 获取链接中参数部分
var queryString = location.href.substring(location.href.indexOf("?")+1);
// 分离参数对 ?key=value&key2=value2
var parameters = queryString.split("&");
var pos, paraName, paraValue;
for(var i=0; i<parameters.length; i++)
{
// 获取等号位置
pos = parameters[i].indexOf('=');
if(pos == -1){continue; }
// 获取name 和 value
paraName = parameters[i].substring(0, pos);
paraValue = parameters[i].substring(pos + 1);
// 如果查询的name等于当前name,就返回当前值,同时,将链接中的+号还原成空格
if(paraName == name)
{
return unescape(paraValue.replace(/\+/g, " "));
}
}
return'';
};
//http://localhost/test.html?aa=bb&test=cc+dd&ee=ff
alert(getQueryString('test'));
//-->
</script>