[ADO]SQL Server连接池

mikel阅读(744)

SQL Server 连接池 (ADO.NET)

连接到数据库服务器通常由几个需要很长时间的步骤组成。必须建立物理通道(例如套接字或命名管道),必须与服务器进行初次握手,必须分析连接字符串信息,必须由服务器对连接进行身份验证,必须运行检查以便在当前事务中登记,等等。

实际上,大多数应用程序仅使用一个或几个不同的连接配置。这意味着在执行应用程序期间,许多相同的连接将反复地打开和关闭。为了使打开连接花费的系统开销最小,ADO.NET 使用称为连接池的优化方法。

连接池使新连接必须打开的次数得以减少。池进程保持物理连接的所有权。通过为每个给定的连接配置保留一组活动连接来管理连接。每当用户在连接上调用 Open 时,池进程就会查找池中可用的连接。如果某个池连接可用,会将该连接返回给调用者,而不是打开新连接。应用程序在该连接上调用 Close 时,池进程会将连接返回到活动连接池集中,而不是关闭连接。连接返回到池中之后,即可在下一个 Open 调用中重复使用。

只有配置相同的连接可以建立池连接。ADO.NET 同时保留多个池,每种配置各一个。在使用集成的安全性时,连接按照连接字符串以及 Windows 标识分到多个池中。还根据连接是否已在事务中登记来建立池连接。

池 连接可以显著提高应用程序的性能和可缩放性。默认情况下,在 ADO.NET 中启用连接池。除非显式禁用,否则,在应用程序中打开和关闭连接时,池进程会对连接进行优化。还可以提供几个连接字符串修饰符来控制连接池的行为。有关更 多信息,请参见本主题后面的“使用连接字符串关键字控制连接池”。

在 初次打开连接时,将根据完全匹配算法创建连接池,该算法将池与连接中的连接字符串关联。每个连接池都与一个不同的连接字符串相关联。打开新连接时,如果连 接字符串并非与现有池完全匹配,将创建一个新池。按进程、应用程序域、连接字符串以及 Windows 标识(在使用集成的安全性时)来建立池连接。连接字符串还必须是完全匹配的;按不同顺序为同一连接提供的关键字将分到单独的池中。

在以下 C# 示例中创建了三个新的 SqlConnection 对象,但是管理时只需要两个连接池。注意,根据为 Initial Catalog 分配的值,第一个和第二个连接字符串有所不同。

using (SqlConnection connection = new SqlConnection(
"Integrated Security=SSPI;Initial Catalog=Northwind"))
{
connection.Open();
// Pool A is created.
}
using (SqlConnection connection = new SqlConnection(
"Integrated Security=SSPI;Initial Catalog=pubs"))
{
connection.Open();
// Pool B is created because the connection strings differ.
}
using (SqlConnection connection = new SqlConnection(
"Integrated Security=SSPI;Initial Catalog=Northwind"))
{
connection.Open();
// The connection string matches pool A.
}

如果 MinPoolSize 在连接字符串中未指定或指定为零,池中的连接将在一段时间不活动后关闭。但是,如果指定的 MinPoolSize 大于零,在 AppDomain 被卸载并且进程结束之前,连接池不会被破坏。非活动或空池的维护只需要最少的系统开销。

说明:

当出现故障转移等错误时,会自动清除池。

连接池是为每个唯一的连接字符串创建的。当创建一个池后,将创建多个连接对象并将其添加到该池中,以满足最小池大小的要求。连接根据需要添加到池中,但是不能超过指定的最大池大小(默认值为 100)。连接在关闭或断开时释放回池中。

在请求 SqlConnection 对象时,如果存在可用的连接,将从池中获取该对象。连接要可用,必须未使用,具有匹配的事务上下文或未与任何事务上下文关联,并且具有与服务器的有效链接。

连接池进程通过在连接释放回池中时重新分配连接,来满足这些连接请求。如果已达到最大池大小且不存在可用的连接,则该请求将会排队。然后,池进程尝试重新建立任何连接,直到到达超时时间(默认值为 15 秒)。如果池进程在连接超时之前无法满足请求,将引发异常。

警告:

我们强烈建议您在使用完连接时一定要关闭连接,以便连接可以返回池。要关闭连接,可以使用 Connection 对象的 CloseDispose 方法,也可以通过在 C#using 语句中或 Visual Basic 的 Using 语句中打开所有连接。不是显式关闭的连接可能不会添加或返回到池中。有关更多信息,请参见using 语句(C# 参考)或 Visual Basic 的如何:释放系统资源

说明:

不要在类的 Finalize 方法中对 ConnectionDataReader 或任何其他托管对象调用 CloseDispose。在终结器中,仅释放类直接拥有的非托管资源。如果类不拥有任何非托管资源,则不要在类定义中包含 Finalize 方法。有关更多信息,请参见垃圾回收

如果连接长时间空闲,或池进程检测到与服务器的连接已断开,连接池进程会将该连接从池中移除。注意,只有在尝试与服务器进行通信之后才能检测到断开的连接。如果发现某连接不再连接到服务器,则会将其标记为无效。无效连接只有在关闭或重新建立后,才会从连接池中移除。

如 果存在一个与已消失的服务器的连接,即使连接池进程尚未检测到断开的连接,也可以从池中取出此连接并将连接标记为无效。这种情况是因为检查连接是否仍有效 的系统开销将造成与服务器的另一次往返,从而抵消了池进程的优势。发生此情况时,初次尝试使用该连接将检测连接是否曾断开,并引发异常。

ADO.NET 2.0 引入了两种新的方法来清除池:ClearAllPoolsClearPoolClearAllPools 清除指定提供程序的连接池,ClearPool 清除与特定连接关联的连接池。如果在调用时连接正在使用,将对它们进行相应的标记。连接关闭时,将被丢弃,而不是返回池中。

连接是根据事务上下文来从池中取出并进行分配的。除非在连接字符串中指定了 Enlist=false,否则连接池将确保连接在 Current 上下文中登记。如果连接使用登记的 System.Transactions 事务关闭并返回到池中,连接将保留在池中,以便使用相同 System.Transactions 事务对该连接池的下一次请求将返回相同的连接(如果可用)。如果发出这样的请求,而没有可用的池连接,则会从池的非事务性部分取出一个连接并登记。如果在池的每个区域都没有可用的连接,则会创建一个新的连接并登记。

当连接关闭时,它将被释放回池中,并根据其事务上下文放入相应的子部分。因此,即使分布式事务仍然挂起,仍可以关闭该连接而不会生成错误。这样,您就可以在之后提交或中止分布式事务。

SqlConnection 对象的 ConnectionString 属性支持连接字符串键/值对,可以用于调整连接池逻辑的行为。有关更多信息,请参见 ConnectionString

池碎片是许多 Web 应用程序中的一个常见问题,应用程序可能会创建大量在进程退出后才会释放的池。这样,将打开大量的连接,占用许多内存,从而导致性能降低。

因为集成安全性产生的池碎片

连 接根据连接字符串以及用户标识来建立池连接。因此,如果使用网站上的基本身份验证或 Windows 身份验证以及集成的安全登录,每个用户将获得一个池。尽管这样可以提高单个用户的后续数据库请求的性能,但是该用户无法利用其他用户建立的连接。这样还使 每个用户至少产生一个与数据库服务器的连接。这对特定 Web 应用程序结构会产生副作用,因为开发人员必须衡量安全性和审计要求。

因为许多数据库产生的池碎片

许 多 Internet 服务提供商在一台服务器上托管多个网站。他们可能使用单个数据库确认窗体身份验证登录,然后为该用户或用户组打开与特定数据库的连接。与身份验证数据库的 连接将建立池连接,供每个用户使用。但是,每个数据库的连接存在一个独立的池,这会增加与服务器的连接数。

这也会对应用程序设计产生副作 用。但是,可以通过一个相对简单的方式避免此副作用,而又不会影响连接 SQL Server 时的安全性。不是为每个用户或组连接独立的数据库,而是连接到服务器上的相同数据库,然后执行 Transact-SQL USE 语句来切换为所需的数据库。以下代码段演示如何创建与 master 数据库的初始连接,然后切换到 databaseName 字符串变量中指定的所需数据库。

Visual Basic
' Assumes that command is a valid SqlCommand object and that
' connectionString connects to master.
command.Text = "USE DatabaseName"
Using connection As New SqlConnection(connectionString)
connection.Open()
command.ExecuteNonQuery()
End Using
// Assumes that command is a SqlCommand object and that
// connectionString connects to master.
command.Text = "USE DatabaseName";
using (SqlConnection connection = new SqlConnection(
connectionString))
{
connection.Open();
command.ExecuteNonQuery();
}

通过调用 sp_setapprole 系统存储过程激活了 SQL Server 应用程序角色之后,该连接的安全上下文无法重置。但是,如果启用了池,连接将返回池,在重复使用池连接时会出错。有关更多信息,请参见知识库文章“SQL application role errors with OLE DB resource pooling”(OLE DB 资源池出现 SQL 应用程序角色错误)。

应用程序角色替代项

如果您使用的是 SQL Server 2005,建议您使用可以替代应用程序角色的新安全机制。有关更多信息,请参见在 SQL Server 中创建应用程序角色 (ADO.NET)

[C#]超时时间已到,但是尚未从池中获取连接

mikel阅读(1006)

“/ASP.Web”应用程序中的服务器错误。
——————————————————————————–

超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。
说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。

异常详细信息: System.InvalidOperationException: 超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。

这是个老问题了!你就查两点: 
  一、看所有open的连接是否都close了。 
  二、如果访问量很大,加上Max   Pool   Size=512这一句,当然这是要以损失系统性能为代价的! 
  这样以后一定可以解决你的问题!

  解决方案一

我 想原因可能是并发操作。DataReader是独占连接的,就是说你的程序可能设计上有问题。比如说最大连接设100,假设有100个人同时使用 DataReader正在读取数据库内容,那么当第101人读取的时候,连接池中的连接已经没有了,就会出现上面的错误。DataReader是独占连接 的,每个DataReader都要占用一个连接。当然这个情况是偶尔出现的,所以会很长时间出现一次,因为只有同时有超过连接池最大连接数量的并发操作才 会发生。而且你加大并发数量只能暂时缓解问题,如果你加大到200个并发连接,如果有201 人同时操作怎么办?你说了你使用Connection对象的Close()方法,这是不行的,因为Close()方法仅仅是关闭连接,但这个连接没有释 放,还是被这个对象占用,要释放必须使用Connection的Dispose()方法显式释放连接才可以,否则这个对象占用的连接只能等到垃圾收集的情 况下才能被释放。这种情况肯定会出现“超时时间已到”的错误。

解决方法:
         1 修改几个关键页面或访问比较频繁的数据库访问操作,使用DataAdapter和DataSet来获取数据库数据,不要使用DataReader。
         2 在访问数据库的页面上使用数据缓存,如果页面的数据不是经常更新(几分钟更新一次)的话,使用Cache对象可以不用访问数据库而使用缓存中的内容,那么可以大大减少连接数量。
         3 修改代码,把使用Connection对象的地方都在Close()后面加上Dispose()调用。
         4 建议对数据库操作进行大的修改,建立自己的数据库操作代理类,继承System.IDisposable接口,强迫释放资源,这样就不会出现连接数量不够的问题了。

解决方案二

解决方法(*):WEB.config 里面:在数据库连接加 Max Pool Size = 512;server=local;uid=;pwd=;database=2004;Max Pool Size = 512;">一劳永逸。

解决方案三

估计是连接(Connection)对象没有Close。倒是不必Dispose,而DataReader用完后应该关闭,但不关闭也没问题,只是不关闭的话此连接对象就一直不能用,只要你最终关闭了连接对象就不会出问题。  
   
   连接对象在Open后的操作都放在try块中,后面跟一个finally块:conn.Close();

错误:   3154一般是由于恢复数据库备份时指定的数据库名和原有数据库中数据库相同引起的 
  你指定一个不易重复的名字, 
  或者在恢复时指定选项:覆盖现存数据库 
  
   本人在将SQL2000数据库导入SQL2005出错,错误信息如下:

还原 对于 服务器“EDWARD\\TRACY”失败。 (Microsoft.SQLServer.Smo)

有关帮助信息,请单击: http://go.microsoft.com/fwlink?Prod…er&LinkId=20476

——————————
其他信息:

执行 Transact-SQL 语句或批处理时发生了异常。 (Microsoft.SQLServer.ConnectionInfo)

——————————

备份集中的数据库备份与现有的 \'foodgood\' 数据库不同。
RESTORE DATABASE 正在异常终止。 (Microsoft SQL Server,错误: 3154)

今天我准备把sql2000 的备份数据库 sp.bak 还原在sql2005 上 (因为课堂上用的是sql2000 而我自己电脑里装的是sql2005 )遇到了点麻烦。就是象sql2000 一样操作还原时出现了点问题。说不能还原,最后找到了点方法终于搞定。

1,在sql2005上新建一个数据库比如:商品

2,选择要还原的 sql2000备份文件

3,这里很重要,选中“覆…”看图

sql2000 备份的数据库还原到sql2005后,选择“数据库关系图”提示:此数据库没有有效所有者,因此无法安装数据库关系图支持对象。若要继续,请首先使用“数 据库属性”对话框的“文件”页或  Alter  AUTHORIZATION  语句将数据库所有者设置为有效登录名,然后再添加数据库关系图支持对象。 
    
解决方法如下:
1、设置兼容级别为90(2005为90)
USE  [master]
GO
EXEC  dbo.sp_dbcmptlevel  at dbname='数据库名',  @new_cmptlevel=90
GO  

或是选责你还原的数据库,点右键,选属性->选项->兼容级别,选择SQLServer2005(90) 然后确定,

      这时,你在该数据库下展开“数据库关系图”节点时会有个提示,"此数据库缺少一个或多个使用数据库关系图所需的支持对象,是否创建",选择“是”即可。

2、通过以上的方法操作,如果问题依然存在的话,按下列方法继续

选择你的数据库,然后选择"安全性"->"用户",选择dbo,打开属性页,如登录名为空的话,新建查询,然后

use [你的数据库名]
EXEC   sp_changedbowner   'sa'

执行成功后,你再选择"数据库关系图"节点,时提示 “此数据库缺少一个或多个使用数据库关系图所需的支持对象,是否创建",选择“是”即可。 就可以看到原先建的关系图了。

1、 对Table中的详细内容,以不同的颜色间隔开相邻的两行。

A:选择Table的Detail行,选择属性中的BackgroundColor,值选择表达式,输入:=iif(RowNumber(Nothing) Mod 2, "White", "Beige")。

2、设置每面显示Table表头或表尾

A:选择Table Header或Table Footer,将属性中的RepeatOnNewpage设为True dot

3、在每页都显示放入的图片或标题头等信息。

A:只须在Table Header中加行数,把你要显示的内容放到单元格中,然后再按第二条方式设置后就可以了。

 

程序功能是一次性生成要求数量的主条码,然后打印出来
我的做法是一次性把生成的代码全部放到一个arraylist里面,让后打印的时候再通过循环一个一个的从arraylist里面取出来打印,然后就导致了以下的错误.
错误如下:
有关调用实时(JIT)调试而不是此对话框的详细信息,
请参见此消息的结尾。
************** 异常文本 **************
System.InvalidOperationException: 超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。
在 System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
在 System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
在 System.Data.SqlClient.SqlConnection.Open()
在 UseDB.myDB.ExecuteStoreProcedure(String ProcedureName, SqlParameter[] Parameter)
在 Barcode_Print.DataManipulate.UpdateTwoTable(String Dy_codeTail)
在 Barcode_Print.DataManipulate.MakeBarcode(String quantity)
在 Barcode_Print.FrmBarcode.button1_Click(Object sender, EventArgs e)

字串9

在 System.Windows.Forms.Control.OnClick(EventArgs e)
在 System.Windows.Forms.Button.OnClick(EventArgs e)
在 System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
在 System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
在 System.Windows.Forms.Control.WndProc(Message& m)
在 System.Windows.Forms.ButtonBase.WndProc(Message& m)
在 System.Windows.Forms.Button.WndProc(Message& m)
在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
在 System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
连接对象没有及时关闭
我都检查过了,好像没有这样的错误阿
注意每次与数据库交换数据前再定义并打开连接,完后立即关闭.Close()(不要调用Dispose),把连接释放到连接池
不要定义全局型(比如类成员)连接变量
注意用try catch块而且连接关闭一定要放在finally块里面

字串1

和你的条码打印队列没什么关系,和其间或其外使用的数据库连接获取与释放有关系,因为很显然,连接耗尽了。连接应该准备工作完成马上就要提交数据或请求了再申请,用完了立即释放,越早越好。
为什么不能调用dispose?我都是close和dispose一起用的,like this:
conn.close();
conn.dispose();
这个是国外的一个re,但是好像持的是相反的观点
This can lead to heated debate, hopefully I'll answer first and then you can
ignore everyone else
Seriously though, this is what Dispose does (actual code):
switch (this._objectState)
{
case ConnectionState.Open:
{
this.Close();
break;
}
}
this._constr = null;
as you can see, all it does it call Close(). So you might be tempted to say
"i should just call close and save some stack". However, there is a dipose
pattern which you should follow. while you can call one, or the other or
both to achieve the same result, this behaviour could change with future
release. One day (for example 2.0) Dispose might do more…and then you'd

字串8

have to go through all your code and make sure you had called Dispose.
Additionally, languages like C# are dispose-aware thanks to the using
keyword.
As far as i'm concerned, those two points are enough to make sure I always
call Dipose on classes which inherit IDisposable.
As for close, my personal feeling is that it doesn't need to be called if
you are calling Dispose. And, since it's better to be consistent, I'd say
never call it. Why? well, none of the .net language are close-aware, and by
definition of what Dispose does, it would be a mistake from the class
designer (ie, microsoft) to implement cleanup functionality in close which
Dispose also woudlnt' do (possibly simply by running close, as it currently
does).
Karl
另外这一句怎么解释呢?
"注意用try catch块而且连接关闭一定要放在finally块里面"
正如viena(维也纳nn)所说的每次完成都要调用Close(), SqlConnection连接对象会回到连接池中,SqlClient使用的是内部连接机制,类似COM 对象池.这里需要注意的是连接池的参数配置,涉及到连接池的设计. 字串2
Connection Lifetime 设置连接的销毁时间
Max Pool Size 最大连接数
Min Pool Size 最小连接数
如果涉及到事务性处理,连接池的设计也不同.
我刚才查了一下关于connection pool的资料(虽然大部分都是java的)
知道为什么上面有朋友说不要用dispose了
因为close()只是释放连接让这个sqlconnection回到pool中,但是如果是dispose()的话可能pool都被释放掉了么??
Dispose不是释放pool,是释放连接
/*
另外这一句怎么解释呢?
"注意用try catch块而且连接关闭一定要放在finally块里面
*/
考虑数据库操作发生异常的情况:
1 没有异常处理,直接弹出错误对话框,程序终止,连接没有关闭
2 有异常处理,必须在程序运行的每个可能分支最后加连接关闭,否则连接可能没有关闭
如果放在finally块里面,不论是否发生异常,都会执行~

[教程]Javascript拖拽系列文章2之offsetLeft、offsetTop、offsetW

mikel阅读(1342)

在阅读本文之前,请先看一看第一篇文章Javascript拖拽系列文章1之offsetParent属性,因为循序渐进是一个很好的习惯,值得提倡。

好了,看看我们今天的内容吧。

 

首先让我们先看一看element.offsetLeft属性。

支持的浏览器:Internet Explorer 4.0+,Mozilla 1.0+,Netscape 6.0+,Opera 7.0+,Safari 1.0+

定义:返回一个像素数值,它表示当前元素的左边缘到它的offsetParent属性返回的对象左边缘的偏移量。

句法:

leftDis = element.offsetLeft

 

offsetLeft属性在Internet Explorer中的实现存在Bug,无论当前元素的 offsetParent属性取值如何,它总是以Body元素为参照物来计算offsetLeft。幸运的是,这个Bug在 Intern Explorer 8 Beta 1中已经修复。仍然需要注意,IE会从Body元素的Left-Border为标准开始计算 OffsetLeft,而其他的浏览器将从Left-Margin开始计算。

测试代码1:

 

Code
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Untitled Document</title>
<style type="text/css">
body{
border:1px solid red;
margin-left:0px;
}
#parent{
position:relative;
left:25px;
top:0px;
border:1px solid black;
}
</style>
<script type="text/javascript" language="JavaScript">
function offset_init(){
var pElement = document.getElementById("sonObj");
parentObj = pElement.offsetParent;
var ioffsetLeft=pElement.offsetLeft;
alert(parentObj.tagName);
alert(ioffsetLeft);
}
</script>
</head>
<body onload="offset_init()">
<div id="parent">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
<span id="sonObj">测试OffsetParent属性</span>
</div>
</body>
</html>

 

 

 

在IE中,运行这段代码后,会依次弹出两个窗口,分别显示“DIV”、“437”,分别表示 offsetParent和offsetLeft。在下图中,红色边框代表Body元素,黑色边框代表Div元素。从而证明即使在IE 中,offsetParent不是Body元素,offsetLeft的计算也以Body元素为标准。

图一:在IE7中的结果

在IE 8 Beta 1中这Bug已经被修复,将分别返回“DIV”,“411”。已经和其他浏览器一样符合了标准。

图二:在IETester中对IE 8 Beta 1的测试结果

注:IETester是一款非常不错的免费网页测试工具,可以代表IE的各个版本来渲染网页。最新版本0.2.3可以在其官方网站http://www.my-Debugbar.com/wiki/IETester/HomePage 下载。个人认为每一个WEB开发者都应该拥有一个。

 

仍然需要注意的是,如果在一个行内标签(作为offsetParent)内嵌入一个标签(作为当前元素),类此如下代码:

 

Code
<span id="parent">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
<div id="sonObj">测试OffsetParent属性</div>
</span>

 

 

 

将引起混乱,因为各个浏览器的渲染各不相同(WebKit内核浏览器将会把OffsetParent属性指向 Body元素,而且IE对OffsetLeft取值不同),在行内标签内嵌入行内标签这种情况下,问题尤为明显(各个浏览器对OffsetLeft属性的 取值就都有差异了,无理可循)。

好了,offsetLeft就讲完了,我们继续看offsetTop属性。

支持的浏览器:Internet Explorer 4.0+,Mozilla 1.0+,Netscape 6.0+,Opera 7.0+,Safari 1.0+

定义:

返回一个数值,指明了当前元素的上边缘到其offsetTop属性返回的对象的上边缘的距离。

句法:

topDis = element.offsetTop

 

前面对于offsetLeft的Bug也存在于offsetTop属性中,同样,这个Bug在IE 8 Beta 1中也已经修复。

图三:在IE7及以下版本中,offsetsetTop属性的Bug。

当然也不要在内联标签内嵌入标签,因为WebKit内核浏览器会错误解释offsetParent属性。

offsetWidth属性

支持的浏览器:Internet Explorer 4.0+,Mozilla 1.0+,Netscape 6.0+,Opera 7.0+,Safari 1.0+

定义:

当前元素的宽度。

句法:

elementWidth = element.offsetWidth

需要指出的是,offsetWidth属性所指的宽度是当前元素的width+padding+border+margin的总和。

offsetHeight属性

支持的浏览器:Internet Explorer 4.0+,Mozilla 1.0+,Netscape 6.0+,Opera 7.0+,Safari 1.0+

定义:

当前元素的高度。

句法:

elementHeight = element.offsetHeight

同样,offsetWidth属性所指的高度是当前元素的Height+padding+border+margin的总和。

以上所说的四个属性再加上上一篇文章的offsetParent属性其实都不是Dom规范的一部分,但是目前的浏览器都实现了它们,这几个属性也是实现JavaScript拖拽功能的核心元素。因此一定要深入理解它们。

下一篇将讲讲事件中的相关属性。

[ORM]某人的ORM框架

mikel阅读(804)

  很多开源的ORM框架都需要配置,那实在是件很烦人的事情。我以前曾打算学NHibernate,开始还以为.NET的Hibernate应该 没JAVA的Hibernate用起来麻烦,结果在网上看了些教材,发觉那是一样的麻烦。说实话,只要是要配置的,我都没心情去做。一般的开源ORM框架 都比较重量级的,虽然能满足我的需要,但功能实在是太多太复杂了,我压根儿很难用得上,而且用起来也麻烦,我还不如自己直接写代码来得快呢。我总结了一下 平时做的项目,大部分的时候我只需要增、删、改、查这几个基本的功能就行了,其它的什么关联啊什么的,用得很少很少。想来想去,还是自己写个简单易用的 orM框架吧,满足一般的需求就够了。

  许多ORM框架把许多代码都用在了配置和其它一些无用功的方面,这样做虽然更加的具有通用性,但同时也给使用者带来了许多麻烦的工作和性能上的 损耗,而且体积也变得很大,代码复杂,难以维护。其实这部分的功能根本就没多大的用处,程序员又不是傻子,何必搞那么多的配置来纠错呢。根据约定优于配置 的原则,制定一个规范,只要大家都按照约定的规则来使用就OK了,对于程序员来说,要做到这一点一点也不难。

  我的ORM框架的约定是:

  1,实体类名和数据表名相同。

  2,主键是"表名ID",并且主键是自增的整数。

  3,数据表的字段名和属性名相同。

  4,正确使用。

  只要遵循以上的约定,就可以正确的使用我的ORM框架了。

  创建表的ORM管理:


//创建UserInfo表的管理者,DbConnectionString是数据库连接字符串名,在配置文件中设置
IORMManager<UserInfo> manager = orMBuilder<UserInfo>.GetORMManager("DbConnectionString");

有了IORMManager,就可以执行数据操作了。

 

要进行条件查询也很简单,通过IORMManager创建过滤器就行了

Code
///创建过滤器
        IFilter filter = manager.CreateFilter("UserName", userName, Operator.Equal);
UserInfo userInfo = manager.LoadOne(filter);

复合查询可以通过创建BooleanFilter对多个IFilter进行逻辑合并

Code
IFilter bFilter=manager.CreateBooleanFilter(leftFilter,rightFilter,LogicOperator.And);

经常会用到的一个比较复杂的查询应该就是分页功能了吧,我的ORM框架对分页也有很好的支持

Code

为数据表写实体类是件很麻烦的事情,尤其是字段特别多的时候,这种苦力活不应该由我们来做啊,太浪费了,所以我写了一个自动生成实体类的小软件,偷懒一下。

EntityBuilder.rar 数据表实体类生成工具。

WebSite1.rar 这个是ORM框架的Demo,不小心把罗斯文数据库也打包进去了。

喜欢的朋友看一下吧。

[JQuery]JQuery选择器

mikel阅读(809)

基本选择器

#myid 返回: <JQuery对象>
匹配一个id为myid的元素。
element 返回: <JQuery对象> 数组
匹配所有的element元素
.myclass 返回: <JQuery对象> 数组
匹配所有class为myclass的元素
* 返回: <jQuery对象> 数组
匹配所有元素。该选择器会选择文档中所有的元素,包括html,head,body
selector1,selector2,selectorN 返回: <jQuery对象> 数组
匹配所有满足selector1或selector2或selectorN的元素

层次选择

elementParent elementChild 返回: <jQuery对象> 数组
匹配elementParent下的所有子元素elementChild。例如:$("div p") 选择所有div下的p元素
elementParent > elementChild 返回: <jQuery对象> 数组
匹配elementParent下的子元素elementChild。例如:$("div>p") 选择所有上级元素为div的p元素
prev+next 返回: <jQuery对象> 数组
匹配prev同级之后紧邻的元素next。例如:$("h1+div") 选择所有div同级之前为h1的元素(<h1 /><div />)
prev ~ siblings 返回: <jQuery对象> 数组
匹配prev同级之后的元素siblings。例如:$("h1~div") 可以匹配(<h1 /><div /><div />)

基本滤镜

:first 返回: <jQuery对象>
匹配第一个元素
:last 返回: <jQuery对象>
匹配最后一个元素
:not(selector) 返回: <jQuery对象> 数组
匹配不满足selector的元素
:has(selector) 返回: <jQuery对象> 数组
匹配包含满足selector的元素。此选择器为1.2新增
:even 返回: <jQuery对象> 数组
从匹配的元素集中取序数为偶数的元素。
:odd 返回: <jQuery对象> 数组
从匹配的元素集中取序数为奇数的元素。
:eq(index) 返回: <jQuery对象> 数组
从匹配的元素集中取第index个元素
:gt(index) 返回: <jQuery对象> 数组
从匹配的元素中取序数大于index的元素
:lt(index) 返回: <jQuery对象> 数组
从匹配的元素中取序数小于index的元素
:header 返回: <jQuery对象> 数组
匹配所有的标题元素,例如h1,h2,h3……hN。此选择器为1.2新增
:animated 返回: <jQuery对象> 数组
匹配正在执行动画的元素。此选择器为1.2新增
:empty 返回: <jQuery对象> 数组
匹配所有没有子元素(包括文本内容)的元素
:parent 返回: <jQuery对象> 数组
匹配包含子元素(包含文本内容)的所有元素
:contains(text) 返回: <jQuery对象> 数组
匹配所有含有text的元素
:hidden 返回: <jQuery对象> 数组
匹配所有隐藏的元素,包含属性type值为hidden的元素
:visible 返回: <jQuery对象> 数组
匹配所有非隐藏的元素

子元素滤镜

E:nth-child(index/even/odd/equation) 返回: <jQuery对象> 数组
匹配所有E在其父元素下满足(index/even/odd/equation)条件的集合。注:下标从1开始
E:first-child 返回: <jQuery对象> 数组
匹配所有E在其父元素下是第一个子元素的集合。例 如:HTML(<div><p id="p1"></p></div><div><p id="p2"></p><p id="p3"></p></div>"),使用$("p:first-child"),选取:<p id="p1"></p><p id="p2"></p>
E:last-child 返回: <jQuery对象> 数组
匹配所有E在其父元素下是最后一个子元素的集合。例如:同上的HTML,使用$("p:last-child"),选取:<p id="p1"></p><p id="p3"></p>
E:only-child 返回: <jQuery对象> 数组
匹配所有E是其父元素的唯一子元素的集合。例如:同上的HTML,使用$("p:only-child"),选取:<p id="p1"></p>

表单滤镜

:input 返回: <jQuery对象> 数组
匹配所有的input、textarea、select、button
:text 返回: <jQuery对象> 数组
匹配文本域。注:在IE浏览器下,选择的对象是所有type属性为text的元素,在非IE浏览器下,选择的对象是input元素type属性为text的元素
:password 返回: <jQuery对象> 数组
匹配密码域。注:在IE浏览器下,选择的对象是所有type属性为password的元素,在非IE浏览器下,选择的对象是input元素type属性为password的元素
:radio 返回: <jQuery对象> 数组
匹配单选按钮。注:在IE浏览器下,选择的对象是所有type属性为radio的元素,在非IE浏览器下,选择的对象是input元素type属性为radio的元素
:checkbox 返回: <jQuery对象> 数组
匹配复选框。注:在IE浏览器下,选择的对象是所有type属性为checkbox的元素,在非IE浏览器下,选择的对象是input元素type属性为checkbox的元素
:submit 返回: <jQuery对象> 数组
匹配提交按钮。注:在IE浏览器下,选择的对象是所有type属性为submit的元素,在非IE浏览器下,选择的对象是input元素type属性为submit的元素和button元素type属性为空或为submit的元素
:image 返回: <jQuery对象> 数组
匹配图像域。注:在IE浏览器下,选择的对象是所有type属性为image的元素,在非IE浏览器下,选择的对象是input元素type属性为image的元素
:reset 返回: <jQuery对象> 数组
匹配重置按钮。注:在IE浏览器下,选择的对象是所有type属性为reset的元素,在非IE浏览器下,选择的对象是input或button元素type属性为reset的元素
:button 返回: <jQuery对象> 数组
匹配按钮。注:在IE浏览器下,选择的对象是所有type属性为button的元素和元素名为button的元素,在非IE浏览器下,选择的对象是input元素type属性为button的元素和元素名为button的元素
:file 返回: <jQuery对象> 数组
匹配文件域。注:在IE浏览器下,选择的对象是所有type属性为file的元素,在非IE浏览器下,选择的对象是input元素type属性为file的元素
:enabled 返回: <jQuery对象> 数组
匹配所有可用的元素。注:即:not(:disabled),参考:disabled的注释
:disabled 返回: <jQuery对象> 数组
匹配所有禁用的元素。注:在非IE浏览器下,选择的对象是禁用的表单元素
:checked 返回: <jQuery对象> 数组
匹配所有被选中的表单。注:在IE浏览器下,选择的对象是含有checked属性的所有元素
:selected 返回: <jQuery对象> 数组
匹配所有选择的表单。注:在IE浏览器下,选择的对象是含有selected属性的所有元素

属性滤镜

[attribute] 返回: <jQuery对象> 数组
匹配拥有attribute属性的元素
[attribute=value] 返回: <jQuery对象> 数组
匹配属性attribute为value的元素
[attribute!=value] 返回: <jQuery对象> 数组
匹配属性attribute不为value的元素
[attribute^=value] 返回: <jQuery对象> 数组
匹配属性attribute的值以value开始的元素
[attribute$=value] 返回: <jQuery对象> 数组
匹配属性attribute的值以value结尾的元素
[attribute*=value] 返回: <jQuery对象> 数组
匹配属性attribute的值包含value的元素
[selector1][selector2][selectorN] 返回: <jQuery对象> 数组
匹配满足属性选择器selector1、selector2、selectorN的元素

[CSS]点这个链接后只执行Js函数页面不作任何跳转和刷新的改变

mikel阅读(626)

最近用Ajax发现个问题,异步执行链接的onclick事件后,如果href=“#”总是刷新页面,结果总是定位不到当前点击的链接,也就是:“点这个链接后只执行Js函数页面不作任何跳转和刷新的改变.”
影响用户体验,于是搜了一下,如下代码
代码的意思就是,只是将鼠标的样式改为手型,但是根本就没有链到任何页面包括本身,其实很简单,如果不想链接到什么页面,不写href属性就行了,去掉style=”cursor:hand”也可以

<a style="cursor:hand" value=&#39;"&rs("iId")&"&#39; onClick=&#39;Smart("&rs("iId")&");&#39;>"&rs("sDescription")&"</a>  "

[MVC]ASP.NET MVC: 用db4o来做TempDataProvider(另附一个泛型的R

mikel阅读(843)

本文地址:http://www.cnblogs.com/QLeelulu/archive/2008/09/19/1294469.html
本文作者:Q.Lee.lulu
本文首发博客园 ,4MVC同步更新。本文示例基于ASP.NET MVC framework (Codeplex Preview 5) 。

关于db4o:

db4o是一种纯对象数据库,相对于传统的关系数据库+ORM,db4o具有以下好处:
1)以存对象的方式存取数据(废话~~,不过你考虑一下完全以对象的方式去考虑数据的存取对传统的数据库设计思维来说是多么大的颠覆);
2)无需数据库服务器,只需要一个数据文件,且dll大小仅为300多k,非常适合作为嵌入式数据库;
3)提供Query By Sample, Native Query和Simple Object DataBase Access(SODA)三种方式进行数据查询,操作简便且功能强大,和SQL说byebye。

以上为引用别人的介绍,目前最新的版本为7.5,支持LINQ语法。要使用db4o只需要在项目中引入db4o的DLL就可以,并不需要安装服务器端(类似于Access的文件型数据库)。

 

ASP.NET MVC的TempData用于在各个控制器Action间传输一些临时的数据,相信大家都看过“在ASP.NET页面间传值的方法有哪几种”这个面试 题,TempData的作用差不多就是这样。TempData默认是使用Session来存储临时数据的,虽然TempData中存放的数据只一次访问中有效,一次访问完后就会删除了的。但很多朋友还是对于将数据存放在Session表示担心,毕竟Session的资源宝贵啊。

使用db4o来存储TempData中的数据是一个不错的选择。之前看到有说用db4o来做中间层数据缓存,当时不是很明白,现在放到这里来想一想,就阔然开朗了。

ASP.NET MVC提供了一个ITempDataProvider的接口:

image

只要实现这两个方法,就可以实现我们的TempDataProvider了。ASP.NET MVC Preview 5 默认还提供了一个CookieTempDataProvider,在Microsoft.Web.Mvc命名空间下。

在这里我们先建一个TempObject的类来表示临时数据,因为TempData是跟用户对应的(想想Session),所以在这个对象中需要一个标识符标识当然用户。在这里我们就使用SessionId来标识吧。TempObject类的代码如下:

 

TempObject

 

 然后我们实现ITempDataProvider的两个方法,代码有注释,就不说了。代码如下:

public class db4oTempDataProvider : ITempDataProvider
{
    
/// <summary>
    
/// 实现接口的获取TempData方法
    
/// </summary>
    
/// <param name="controllerContext"></param>
    
/// <returns></returns>

    public virtual IDictionary<stringobject> LoadTempData(ControllerContext controllerContext)
    
{
        HttpContextBase httpContext 
= controllerContext.HttpContext;
        
if (httpContext.Session == null)
        
{
            
throw new InvalidOperationException("db4oTempDataProvider: SessionStateDisabled");
        }

        
//如果用户的Session没有任何数据,则每次请求的SessionId都是一个新的ID。
        
//只好出此下策,在Session附加一点数据。
        httpContext.Session["db4oTempDataProvider"= 1

        
//使用SessionId来标识当前用户
        string sessionId = httpContext.Session.SessionID; 

        
//从db4o数据库中取出对象
        TempObject temp = Db4oHelper.GetTempObject(sessionId); 

        
// 清理垃圾数据。想想你就会明白为什么会有垃圾数据了.
        
// 当前时间的30分钟以前创建的数据都认为是垃圾数据。
        
// 我也不知道多少时间合适,反正Session的默认过期时间是30分钟。
        Db4oHelper.CleanUp(); 

        
if (temp != null && temp.TempObjects != null)
        
{
            
//取出临时数据后,将数据删除,即TempData数据只被访问一次即删除
            Db4oHelper.DelTempObject(sessionId); 

            
return temp.TempObjects as Dictionary<stringobject>;
        }
 

        
return new Dictionary<stringobject>(StringComparer.OrdinalIgnoreCase);
    }

    
/// <summary>
    
/// 实现接口的保存TempData方法
    
/// </summary>
    
/// <param name="controllerContext"></param>
    
/// <param name="values"></param>

    public virtual void SaveTempData(ControllerContext controllerContext, IDictionary<stringobject> values)
    
{
        HttpContextBase httpContext 
= controllerContext.HttpContext;
        
if (httpContext.Session == null)
        
{
            
throw new InvalidOperationException("db4oTempDataProvider: SessionStateDisabled");
        }
 

        TempObject temp 
= new TempObject(httpContext.Session.SessionID);
        temp.TempObjects 
= values; 

        
//将TempData保存到数据库
        Db4oHelper.SaveTempObject(temp);
    }

}
 

 

附Db4oHelper的代码:

Db4oHelper

到这里我们已经实现了自己的TempDataProvider,但是怎么替换掉系统默认的SessionStateTempDataProvider呢?我们可以在Controller中进行替换,Controller提供了一个TempDataProvider的属性。我们写一个BaseController,在这里进行替换,然后让所后的Controller都继承自这个Controller就可以了。

public class BaseController : Controller
{
    
public BaseController()
    {
        
//将当前的TempDataProvider 修改为 db4oTempDataProvider。
        this.TempDataProvider = new db4oTempDataProvider();
    }
}

 

或许还有其他的更好的方法可以对全局进行替换?可以在Application_Start中进行这个操作?如果你知道,麻烦告诉我。 ^_^

 

完了测试了一下,貌似性能不咋的。也罢,大家当作是学习一下怎样实现一个TempDataProvider。不知是否我的数据库操作部分有问题?还是文件数据库本身读写慢?

对于db4o,有几个问题想请教一下:
1、不知道并发处理能力如何?
2、在这里用的单实例打开连接,并且操作完了都关闭连接,不知道这样处理是否合适?或者该怎样才能更好的管理这个数据库连接,才能更好的处理并发状况?

 

泛型的RedirectToAction方法

写过ASP.NET MVC代码的朋友应该发现,在Action中如果想要Redirect到另一个Action去,则我们或许会写如下的代码:

//跳转到HomeController中的Index Action
return RedirectToAction("Index""Home"); 

或者

//跳转到HomeController中的Index Action
return RedirectToRoute(new { controller = "Home", action = "Index" }); 

(或者你有其他好的办法我不知道?)

可以看到这里Controller和Action的名称都是用字符串来写的,对于代码维护和重构,这是不可想象的。所以反射了一下M$的代码,写了一个泛型的RedirectToAction方法,我们可以把这个方法写到前面提到的BaseController中去:

 

/// <summary>
/// 重定向到指定的Controller中的Action
/// </summary>

public RedirectToRouteResult RedirectToAction<T>(Expression<Action<T>> action) where T : Controller
{
    MethodCallExpression body 
= action.Body as MethodCallExpression;
    
if (body == null)
    
{
        
throw new InvalidOperationException("Expression must be a method call");
    }

    
if (body.Object != action.Parameters[0])
    
{
        
throw new InvalidOperationException("Method call must target lambda argument");
    }

    
string name = body.Method.Name;
    
string str2 = typeof(T).Name;
    
if (str2.EndsWith("Controller", StringComparison.OrdinalIgnoreCase))
    
{
        str2 
= str2.Remove(str2.Length  1010);
    }

    RouteValueDictionary values 
= LinkBuilder.BuildParameterValuesFromExpression(body) ?? new RouteValueDictionary();
    values.Add(
"controller", str2);
    values.Add(
"action", name); 

    
return new RedirectToRouteResult(values);
}

 

使用示例:

return RedirectToAction<HomeController>(h => h.Index());

这个返回的是一个RedirectToRouteResult,跟我们平时WebForm中的Redirect()一样是重定向到另一个URL,产生一个新的请求的。所以如果你有一个Action为:

public ActionResult Cpu(CPU cpu)
{
    ViewData[
"Cpu"= cpu;
    
return View();
}

那么你不可以如下这样调用:

return RedirectToAction<HomeController>(h => h.Cpu(cpu));

如果你需要这样做,你应该写一个ModelBinder,并重写你要传递的参数对象(在这里是CPU)的ToString()方法。具体请参见leven(神鱼)重典的Blog。

完。Enjoy!最后附上DEMO代码:TempDataProviderDemo.rar

[Json]MVC JSON - JsonResult and jQuery

mikel阅读(930)

The latest release of the MVC framework provides the JsonResult for Controller actions.  I was surprised that I did not find a weatlh of examples for usage so I figured it shouldn't be too hard to get a decent example going.  It turns out, it was even easier than I anticipated.  I wanted to create an example where I would invoke an AJAX call to dynamically populate a dropdown list. 

jQuery has recently received a huge surge of interest of the ASP.NET MVC community so I've been getting up to speed on it myself.  I am quickly turning into a true believer and I've been impressed not only with how few lines of JavaScript it takes me to get things done but also how (relatively) easy it was to learn.  In addition to numerous examples on the jQuery web site I also recommend jQuery In Action.

Getting an AJAX request with JQuery and JSON in MVC is actually pretty simple.  The first step is to have a Controller action that returns a JsonResult:

   1:  public JsonResult GetStateList()
   2:  {
   3:      List<ListItem> list = new List<ListItem>() {
   4:          new ListItem() { Value = "1", Text = "VA" },
   5:          new ListItem() { Value = "2", Text = "MD" },
   6:          new ListItem() { Value = "3", Text = "DC" }
   7:      };
   8:      return this.Json(list);
   9:  }

Here I'm using the System.Web.Mvc.ListItem class (which is used as items in the SelectList) to simply return a contrived list of US states to populate a dropdown list.  All I have to do is call the Json() method passing in my object and it will automatically be serialized to JSON.  When the request is made the AJAX call can be seen in the Web Development Helper which is an invaluable tool to any AJAX development:

Notice the "application/json" in the request header and the textual representation of the JSON that is being returned from my JSON controller action.

The JQuery to make this happen is quite succinct:

   1:  <script type="text/javascript">
   2:  $(function() {
   3:      $('#btnFillList').click(function() {
   4:          $.getJSON("/Home/GetStateList", null, function(data) {
   5:              $("#stateList").fillSelect(data);
   6:          });
   7:       });
   8:       
   9:       $('#btnClearList').click(function() {
  10:          $("#stateList").clearSelect();
  11:       });
  12:  });
  13:  </script>

Notice on line #4 the use of the $.getJSON() JQuery method.  Then I've simply written a re-usable jQuery method called fillSelect() which will work on the JSON format returned by the ListItem class returned by my controller action:

   1:  $.fn.clearSelect = function() {
   2:      return this.each(function() {
   3:          if (this.tagName == 'Select')
   4:              this.options.length = 0;
   5:      });
   6:   } 
   7:   
   8:  $.fn.fillSelect = function(data) {
   9:      return this.clearSelect().each(function() {
  10:          if (this.tagName == 'Select') {
  11:              var dropdownList = this;
  12:              $.each(data, function(index, optionData) {
  13:                  var option = new Option(optionData.Text, optionData.Value);
  14:                  
  15:                  if ($.browser.msie) {
  16:                      dropdownList.add(option);
  17:                  }
  18:                  else {
  19:                      dropdownList.add(option, null);
  20:                  }
  21:              });
  22:          }
  23:      });
  24:   }

On line #13 above you'll see the strongly-typed "Text" and "Value" properties that I have the luxury of using because of the native JSON serialization into objects.

The complete code sample can be downloaded here.  It's barely 50 lines of code in all.

[Jquery]使用Jquery应用到Asp.net ajax中时3个误区应该避免

mikel阅读(694)

Ajax中使用json这个轻量级数据类型通信的好处相信大家已经很清楚,考虑到安全问题,ASP.NET Ajax的webService使用json,应该防止Json Hijacking。因此通常我们的做法是在使用Post请求式,并将请求的content-type设置成application/json; charset=utf-8。但客户端如果你使用的是JQuery,有三个细节问题是我们应该注意的:
      1 :如果我们Post时没有任何数据传给服务端,请指定Data:{} 如:
   
Code
1 $.ajax({
2  type: "POST",
3  url: "PageMethod.aspx/PageMethodName",
4  data: "{}",//注意这里不可省。
5  contentType: "application/json; charset=utf-8",
6  dataType: "json"
7 });
  这是因为在IIS中post请求时Content —Length是必须提供的,即使没用任何Post Data.Content-Length也应该设为0,但这样的话JQuery不会自动设置Header,除非请求中包含post Data。而ASP.NET Ajax的json传输,又要求post方式,因此我们不能改变他的请求方式。简便的解决法案就是在请求中给定一个空的json 对象。以符合IIS的要求,此时Content-Length为2。这时在服务端我可以完全忽略这个为空的参数,并处理相应的请求。
    2:当post data 不为空时。我们应该避免在beforeSend事件里设置RequestHeader。
    如一点所述的范例post data 为空时,既然JQuery不能自动设置Header,我们能否手工帮他设置呢?答案时是
肯定的。这时我们是在beforeSend事件中设置的。如代码所示(请注意:必须设置为application/json否则webservice
时不会返回json。这也是出于安全的考虑)。
Code
1 $.ajax({
2  type: "POST",
3  url: "WebService.asmx/WebMethodName",
4  beforeSend: function(xhr) {
5    xhr.setRequestHeader("Content-type",
6                          "application/json; charset=utf-8");
7  },
8  dataType: "json"
9 });
    但时此时问题又来了,在IE中XmlHttpRequst的setRequestHeader不时直接完全的设置RequstHeader。而是
在已有的基础上附加setRequestHeader参数所指定的以形成新的header。这样的话,在jQuery会在包含Post Data请求
的header中自动设置content-type为默认的application/x-www-form-urlencoded ,而在beforeSend又会被重新追
加一个application/json; charset=utf-8。此时Content-Type变成了 application/x-www-form-urlencoded,
application/json; charset=utf-8(在ff会重新设置)。很显然这个content-type不为ASP.NET Ajax所接受。webservice
不会返回任何json。因此包含post data时建议使用下列方式保证返回的为json
Code
$.ajax({
  type: "POST",
  url: "WebService.asmx/WebMethodName",
  data: "{'fname':'dave', 'lname':'ward'}",
  contentType: "application/json; charset=utf-8",
  dataType: "json"
});
  3:注意区分json对象和json形式的字符串。
  看看下面代码:
Code
$.ajax({
  type: "POST",
  url: "WebService.asmx/WebMethodName",
  data: {'fname':'dave', 'lname':'ward'},
  contentType: "application/json; charset=utf-8",
  dataType: "json"
});
咋一看没什么问题,想当然的认为data会乖乖的post给服务端。但实际上这是不正确的。请仔细看此时data时json
表示的对象。此时Json表示的对象会被jQuery序列化。如上述例子data将是fname=dave&lname=ward。再看如下:
Code
1 $.ajax({
2  type: "POST",
3  url: "WebService.asmx/WebMethodName",
4  data: "{'fname':'dave', 'lname':'ward'}",
5  contentType: "application/json; charset=utf-8",
6  dataType: "json"
7 });
这时data才是我们期望的。其形式:{'fname':'dave', 'lname':'ward'}。小小语义的改变就可以造成如此大的不同。
因此,我们在编程过程中应该特别注意。以免浪费时间。
注:有关细节可以参看3 mistakes to avoid when using jQuery with ASP.NET AJAX ,有更详细的说明。我只是
重新用中文简要的重述一下其中讲到的问题。
原文出处:http://www.cnblogs.com/mingxuan

[Json]Jquery解析Asp.net MVC的JsonResult格式数据

mikel阅读(1030)

As I was looking around for ways to enable Ajax in the current ASP.NET MVC release I found a couple of things that I found pretty useful and thought I should share.

The J in Ajax (JQuery)

The muscle behind the actual asynchronous calls comes from JavaScript. I looked around at a bunch of existing JavaScript libraries and settled on JQuery because of the way it leverages existing CSS knowledge. The three things that the library should do easily are:

  1. Help me easily display an "updater" to let user know something is happening (i.e. loading data),
  2. Assist in making the actual Ajax call without any hassle,
  3. and, most importantly, let me get 1 and 2 working without headaches.

Here is how JQuery helps in the three cases:

  1. The "updater":
    $('#updater').show();
    $('#updater').hide();
    Notice the way jQuery uses the standard CSS id selector. Could it be any easier?
  2. jQuery has the following Ajax calls available in its library:
    object.load( )
    $.get( )
    $.post( )
    $.getJSON( )
    This takes away (hides) all of the XmlHttp object nonsense from the whole Ajax call.
  3. See 1 and 2

ASP.NET MVC

There are tons of good posts/tutorials on exactly how the ASP.NET MVC model works so I will not attempt to get into it too much here. The most important thing to know is that there are three things working together:

  1. The Controller,
  2. The Model, and
  3. The View

The controller handles all of the requests, asks the model for data, and then instructs the view to present the data (if any) returned.

Routes

One of the neat things about the MVC framework is the notion of routes. The default route setup is as follows:

   1:  routes.MapRoute(
   2:          "Default",                                              // Route name
   3:          "{controller}/{action}/{id}",                           // URL with parameters
   4:          new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
   5:  );

This simply means that, from the root of your web app, whenever a URL of the form http://root/foo/baz/bar is presented, the routing engine will call the foo controller with the baz action while supplying it with the bar id.

Some Code

Enough explanation, now to some code!

The Model

Since this is not an exercise in using the database, I created a simple Model class for students:

   1:  public class Student
   2:  {
   3:     public string FirstName { get; set; }
   4:     public string LastName { get; set; }
   5:     public int StudentId { get; set; }
   6:          
   7:     public static IQueryable<Student> GetStudentDataList()
   8:     {
   9:        return new List<Student>() 
  10:        {
  11:           new Student { FirstName = "John", LastName = "Smith", StudentId = 1},
  12:           new Student { FirstName = "Susan", LastName = "Connor", StudentId = 2},
  13:           new Student { FirstName = "Bryan", LastName = "Jones", StudentId = 3},
  14:           new Student { FirstName = "Lucy", LastName = "Vargas", StudentId = 4},
  15:           new Student { FirstName = "Robert", LastName = "Jimenez", StudentId = 5},
  16:           new Student { FirstName = "Seth", LastName = "Juarez", StudentId = 6},
  17:           new Student { FirstName = "David", LastName = "Meeks", StudentId = 7},
  18:           new Student { FirstName = "Olivia", LastName = "Rassmusen", StudentId = 8},
  19:           new Student { FirstName = "Viola", LastName = "Masterson", StudentId = 9},
  20:           new Student { FirstName = "Russel", LastName = "Jones", StudentId = 10}
  21:        }
  22:        .AsQueryable<Student>();
  23:     }
  24:  }

This simply creates a new list of Students and returns them as an IQueryable.

The Controller

Since I want to only pass JSON serialized objects over the wire when making the Ajax calls, there is a handy return type for the action in the controller called JsonResult:

   1:  public JsonResult Find(string name)
   2:  {
   3:     // To simulate "wait"
   4:     System.Threading.Thread.Sleep(1500);
   5:          
   6:     return new JsonResult
   7:     {
   8:        Data = (from student in Student.GetStudentDataList()
   9:                where student.LastName.StartsWith(name)
  10:                select student).ToArray<Student>()
  11:     };
  12:  }

This will serialize the data out in the JSON format. Now for the actual interesting part:

The View

The html for this example is VERY simple:

   1:  <div id="query">
   2:        <%= Html.TextBox("textSearch") %>&nbsp;
   3:        <a href="#" id="linkFind">Find</a>&nbsp;&nbsp;&nbsp; 
   4:        <span class="update" id="updater">
   5:              <img src="<%= AppHelper.ImageUrl("indicator.gif") %>" alt="Loading" />
   6:              &nbsp;Loading...&nbsp;&nbsp;&nbsp;
   7:        </span>
   8:  </div>
   9:   <div class="label">Students:</div> 
  10:  <div id="studentList"></div>

There is a search box, a link, and update panel, and a div (studentList) that will be populated by the Ajax call. This is where the magic of the routing engine coupled with the JQuery Ajax call comes together:

 

   1:  $(document).ready(
   2:     function()
   3:     {
   4:        // Hide update box
   5:        $('#updater').hide();
   6:                  
   7:        var retrieveData = function(path,  query,  funStart,  funEnd, funHandleData)
   8:        {
   9:           // for displaying updater
  10:           funStart();
  11:                          
  12:           // retrieve JSON result
  13:           $.getJSON(
  14:              path,
  15:              { name : query },
  16:              function(data)
  17:              {
  18:                 // handle incoming data
  19:                 funHandleData(data);
  20:                 // for hiding updater
  21:                 funEnd();
  22:              }
  23:           );
  24:        };
  25:                  
  26:        // adding handling to find link
  27:        $('#linkFind').click(
  28:           function(event)
  29:           {
  30:              event.preventDefault();
  31:              retrieveData(
  32:                 // mvc route to JSON request
  33:                 '/Student/Find/', 
  34:                 // query from textbox
  35:                 $('#textSearch')[0].value, 
  36:                 // function to show updater
  37:                 function() { $('#updater').show(); }, 
  38:                 // function to hide updater
  39:                 function() { $('#updater').hide(); },
  40:                 // retrieving the data
  41:                 function(data)
  42:                 {
  43:                    // clear students (if any)
  44:                    $('#studentList > div').remove();
  45:                    // add students
  46:                    for(s in data)
  47:                    {
  48:                       var student = data[s];
  49:                       $('#studentList').append('<div>(' +  student.StudentId ... you get the idea                 
  50:                     }
  51:                 }
  52:              );
  53:            }
  54:         );
  55:      }
  56:  );

The retrieveData function uses the JQuery $.getJSON call to retrieve the data. It takes as arguments the path to the controller (remembering routes), the argument (in this case the query) that the controller action expects, as well as a couple of functions. These functions will handle the cases where the  request is started, the request is ended, and what to do with the data that is returned. Subsequently we add the event handler to the link that initiates the find request. Notice that we are passing in '/Student/Find/' as the path since we are using the Find action on the StudentController. The argument is passed in from the search text box. This sets into motion the asynchronous request to the controller. The controller then returns a JSON serialized array of Student objects. Once the data is received, the studentList div is then cleared and repopulated.

Screenshot

The request:

request

The response:

response

Conclusion

Hopefully this has been helpful! It was fun putting everything together. Feel free to send me an email or leave a comment on this post if there are any suggestions/comments.

Code