原文地址:http://www.developer.com/net/asp/article.php/3657826
[原文源码下载]
原文发布日期:2007.02.08
作者:Bipin Joshi
翻译:webabcd
介绍
尽管AJAX是种客户端技术,但实际上的开发过程,它经常要调用一个服务器端的过程。通常,网站上的数据是存放在一个关系型数据库中,为了让AJAX更有用处,处理服务器端数据需要一种简单可靠的方法。幸运的是,ASP.NET AJAX提供了一种有效的基础架构来做这件事情,浏览器和服务器在Internet上可以进行AJAX通信。自然而然,Web Service在数据传输和客户端/服务器之间的一般通信方面可以扮演一个重要角色。本文就演示了如果通过ASP.NET AJAX调用ASP.NET web services。
软件需求
本文所有的范例都是使用ASP.NET AJAX RC版,而且,要在SQL Server 2005 (Express版即可)上有一个Northwind数据库。范例使用Visual Studio 2005作为开发环境。
范例场景
范例开发了一个Web页面,用于输入Northwind数据库职员表中的职员数据。页面通过ASP.NET AJAX功能,调用一个Web Service来完成职员表中的数据增、删、改、查。
创建一个Web Service
作为开始,使用Visual Studio 2005创建一个新的Web站点,注意把ASP.NET AJAX项目模板添加到新站点对话框,这个对话框包括一个"ASP.NET AJAX Enabled Web Site" 模板。
![](http://www.developer.com/img/2007/02/Figure1.jpg)
图1:新站点创建模板
使用"ASP.NET AJAX Enabled Web Site" 模板创建的新站点和用普通方法创建的站点区别如下:
·它的Web.config自动包括许多ASP.NET AJAX专用的配置信息。
·System.Web.Extensions程序集被添加到引用中。
当然,我们可以更改一个普通的Web站点,以使之符合AJAX要求,但模板可以大大简化我们的工作。
现在我们创建了一个新的Web站点,添加一个新的web service并命名为EmployeeService.asmx,EmployeeService将包括5个Web方法
表1:EmployeeService中的Web方法
GetEmployees() 和 GetEmployee()方法以Employee对象的形式返回数据,因此,首先创建一个Employee类。右键单击App_Code文件夹,选择“添加新项…”,添加一个叫Employee的类,下面显示Employee类的全部代码:
public
class
Employee
{
private int intEmployeeID;
private string strFirstName;
private string strLastName;
public int EmployeeID
{
get
{
return intEmployeeID;
}
set
{
intEmployeeID = value;
}
}
public string FirstName
{
get
{
return strFirstName;
}
set
{
strFirstName = value;
}
}
public string LastName
{
get
{
return strLastName;
}
set
{
strLastName = value;
}
}
}
Employee类申明三个Private变量来分别存放employee ID, first name和 last name,三个变量再封装在三个public属性中:EmployeeID, FirstName和LastName。
打开 web.config文件,添加<connectionStrings>部分如下:
<
connectionStrings
>
<
add
name
="connstr"
connectionString
=
"data source=./sqlexpress;
initial catalog=northwind;
integrated security=true"
/>
</
connectionStrings
>
这部分存放数据库链接字符串,用于指向Northwind数据库,确保修改SqlServer名称、IP地址以及验证方式以和我们的开发环境相符。
现在,打开EmployeeService.cs添加如下代码:
private
string
strConn
=
""
;
public
EmployeeService()
{
strConn = ConfigurationManager.ConnectionStrings["connstr"].
ConnectionString;
}
代码使用了ConfigurationManager类来读取配置文件中的数据库链接字符串,并存放在一个类级别的变量strConn中,这个变量将被下面的所有Web Method所使用。
现在,添加GetEmployees() web method:
[WebMethod]
public
Employee[] GetEmployees()
{
SqlConnection cnn = new SqlConnection(strConn);
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
cmd.CommandText = "select employeeid,firstname,
lastname from employees";
SqlDataReader reader = cmd.ExecuteReader();
List<Employee> list = new List<Employee>();
while (reader.Read())
{
Employee emp = new Employee();
emp.EmployeeID = reader.GetInt32(0);
emp.FirstName = reader.GetString(1);
emp.LastName = reader.GetString(2);
list.Add(emp);
}
reader.Close();
cnn.Close();
return list.ToArray();
}
代码创建了SqlConnection and SqlCommand 对象,然后执行SELECT查询,以获取Employees表中EmployeeID, FirstName 和LastName字段。结果通过SqlDataReader返回。然后,创建一个generic-based Employee数组,通过While循环,给每个Employee实例的属性赋值。当While循环完毕的时候,关闭SqlDataReader 和 SqlConnection。GetEmployees()方法返回的类型是Employee数组。因此,generic List使用List类中的ToArray()方法来转换成Employee数组。
现在,添加一个GetEmployee() web method如下:
[WebMethod]
public
Employee GetEmployee(
int
pEmployeeId)
{
SqlConnection cnn = new SqlConnection(strConn);
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
cmd.CommandText = "select employeeid,firstname,lastname
from employees where employeeid=@id";
SqlParameter id = new SqlParameter("@id", pEmployeeId);
cmd.Parameters.Add(id);
SqlDataReader reader = cmd.ExecuteReader();
Employee emp = new Employee();
while (reader.Read())
{
emp.EmployeeID = reader.GetInt32(0);
emp.FirstName = reader.GetString(1);
emp.LastName = reader.GetString(2);
}
reader.Close();
cnn.Close();
return emp;
}
GetEmployee() web method接受一个employee ID参数作为输入,代码和前面的非常相似,但这次只返回一个employee。注意,使用SqlParameter来定义传入的EmployeeID。
现在,再添加Insert()、Update()和 Delete()web methods,其中,Insert() web method 以要添加的Employee的 first name 和 last name 作为参数,Update() web method 以要更新的employee ID 以及新的first name 和 last name作为参数,并执行UPDATE语句, Delete() web method 以要删除的employee ID 作为参数,然后执行DELETE 语句
[WebMethod]
public
int
Insert(
string
pFirstName,
string
pLastName)
{
SqlConnection cnn = new SqlConnection(strConn);
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
cmd.CommandText = "insert into employees(firstname,lastname)
values (@fname,@lname)";
SqlParameter fname = new SqlParameter("@fname", pFirstName);
SqlParameter lname = new SqlParameter("@lname", pLastName);
cmd.Parameters.Add(fname);
cmd.Parameters.Add(lname);
int i = cmd.ExecuteNonQuery();
cnn.Close();
return i;
}
[WebMethod]
public
int
Update(
int
pEmployeeId,
string
pFirstName,
string
pLastName)
{
SqlConnection cnn = new SqlConnection(strConn);
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
cmd.CommandText = "update employees set firstname=@fname,
lastname=@lname where employeeid=@id";
SqlParameter fname = new SqlParameter("@fname", pFirstName);
SqlParameter lname = new SqlParameter("@lname", pLastName);
SqlParameter id = new SqlParameter("@id", pEmployeeId);
cmd.Parameters.Add(fname);
cmd.Parameters.Add(lname);
cmd.Parameters.Add(id);
int i = cmd.ExecuteNonQuery();
cnn.Close();
return i;
}
[WebMethod]
public
int
Delete(
int
pEmployeeId)
{
SqlConnection cnn = new SqlConnection(strConn);
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
cmd.CommandText = "delete from employees where employeeid=@id";
SqlParameter id = new SqlParameter("@id", pEmployeeId);
cmd.Parameters.Add(id);
int i = cmd.ExecuteNonQuery();
cnn.Close();
return i;
}
这就完成了web service的创建。到目前为止,还没有做任何和AJAX特性相关的任何工作,现在,时机已经成熟,我们通过下面的代码更改web service类的定义:
using
System.Web.Script.Services;
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
[WebService(Namespace
=
"
http://tempuri.org/
"
)]
[WebServiceBinding(ConformsTo
=
WsiProfiles.BasicProfile1_1)]
[ScriptService]
public
class
EmployeeService : System.Web.Services.WebService
{
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
注意特地标明的黑体字,我们导入了System.Web.Script.Services命名空间,这个命名空间来自System.Web.Extensions程序集,这个命名空间提供了[ScriptService]属性,这将使web service可以被来自客户端的JavaScript (如ASP.NET AJAX)调用。
好了,我们开始准备从ASP.NET AJAX调用Web Service了!
如何调用Web Service
这部分,我们将创建一个Web页面作为数据输入,通过调用刚刚创建的Web Service来操作Employees表。作为开始,我们先添加一个EmployeeServiceClient.aspx页面,打开工具箱,选择View > Toolbox菜单,在工具箱上,选中AJAX Extensions这样的节点(见图2)
![](http://www.developer.com/img/2007/02/Figure2.jpg)
图 2: 增加模板后的新站点创建对话框
AJAX Extensions部分显示一个Web页面上所有可以使用的ASP.NET AJAX组件。所有使用ASP.NET AJAX的页面都需要一个ScriptManager组件。打开ScriptManager属性窗口,定位Services属性,打开Service引用编辑器,如图3:
![](http://www.developer.com/img/2007/02/Figure3.jpg)
图 3: Service 引用编辑器
点击对话框底部的Add按钮,设置Path属性以指向Web Service(EmployeeService.asmx)的虚拟路径,下面的标记将会产生在Web页面文件中:
<
asp:ScriptManager
ID
="ScriptManager1"
runat
="server"
>
<
Services
>
<
asp:ServiceReference
Path
="EmployeeService.asmx"
/>
</
Services
>
</
asp:ScriptManager
>
对每个Web Service调用,都需要在<asp:ScriptManager>部分添加一个<asp:ServiceReference>元素,此标记把要使用的web service注册到当前web form上。
![](http://www.developer.com/img/2007/02/Figure4.jpg)
图 4: 设计页面表单
表单包括一个下拉框(<SELECT>) ,用于显示所有的employee IDs,一旦选中其中一个employee ID,employee的详细信息将显示在2个文本框中,然后可以更新这些信息。如果要添加一个employee,只需要输入first name 和 last name,然后点击“插入”按钮就可以了。同理,如果要删除一个employee,选择下拉框中的employee ID,点击“删除”按钮。在INSERT、UPDATE或者 DELETE操作完成后,将会显示成功或者失败的信息。下面是所有的页面代码:
<
table
>
<
tr
>
<
td
colspan
="2"
>
<
asp:Label
ID
="Label4"
runat
="server"
Font-Size
="X-Large"
Text
="Employee Management"
>
</
asp:Label
></
td
>
</
tr
>
<
tr
>
<
td
style
="width: 100px"
>
<
asp:Label
ID
="Label1"
runat
="server"
Text
="Employee ID :"
></
asp:Label
></
td
>
<
td
style
="width: 100px"
>
<
select
id
="Select1"
>
</
select
>
</
td
>
</
tr
>
<
tr
>
<
td
style
="width: 100px"
>
<
asp:Label
ID
="Label2"
runat
="server"
Text
="First Name :"
></
asp:Label
></
td
>
<
td
style
="width: 100px"
>
<
input
id
="Text1"
type
="text"
/></
td
>
</
tr
>
<
tr
>
<
td
style
="width: 100px"
>
<
asp:Label
ID
="Label3"
runat
="server"
Text
="Last Name :"
></
asp:Label
></
td
>
<
td
style
="width: 100px"
>
<
input
id
="Text2"
type
="text"
/></
td
>
</
tr
>
<
tr
>
<
td
align
="center"
colspan
="2"
>
<
input
id
="Button3"
type
="button"
value
="Insert"
/>
<
input
id
="Button4"
type
="button"
value
="Update"
/>
<
input
id
="Button5"
type
="button"
value
="Delete"
/>
</
td
>
</
tr
>
<
tr
>
<
td
align
="center"
colspan
="2"
>
<
span
id
="lblMsg"
style
="font-weight: bold;
color: red;"
></
span
>
</
td
>
</
tr
>
</
table
>
注意:我们没有使用ASP.NET服务器端控件,如DropDownList、 TextBox 以及 Button。取而代之的是,我们用的传统的HTML控件,如:<SELECT> 以及 <INPUT>。这因为我们要想通过客户端JavaScript调用web service,而不是通过服务端代码。同理,注意底下的<SPAN>标记,这是用来显示成功或者失败的信息的。
下一步,在<head>元素内增加一个<script>部分,添加一个CallWebMethod()的函数:
function CallWebMethod(methodType)
{
switch(methodType)
{
case "select":
EmployeeService.GetEmployees(FillEmployeeList,ErrorHandler,
TimeOutHandler);
break;
case "selectone":
var select=document.getElementById("Select1");
var empid=select.options[select.selectedIndex].value;
EmployeeService.GetEmployee(empid,DisplayEmployeeDetails,
ErrorHandler,TimeOutHandler);
break;
case "insert":
var text1=document.getElementById("Text1");
var text2=document.getElementById("Text2");
EmployeeService.Insert(text1.value,text2.value,
InsertEmployee,ErrorHandler,
TimeOutHandler);
break;
case "update":
var select=document.getElementById("Select1");
var empid=select.options[select.selectedIndex].value;
var text1=document.getElementById("Text1");
var text2=document.getElementById("Text2");
var emp=new Employee();
emp.EmployeeID=empid;
emp.FirstName=text1.value;
emp.LastName=text2.value;
EmployeeService.Update(empid,text1.value,text2.value,
UpdateEmployee,ErrorHandler,
TimeOutHandler);
break;
case "delete":
var select=document.getElementById("Select1");
var empid=select.options[select.selectedIndex].value;
EmployeeService.Delete(empid,DeleteEmployee,ErrorHandler,
TimeOutHandler);
break;
}
}
CallWebMethod() 函数 就是用来调用web service的中央控制函数。 这个函数接收一个字符串参数用来标识调用的方法,它包括一个switch 语句来判断调用的方法,每个 case 块 调用一个web method。 注意web method 是如何被调用的:ASP.NET AJAX 框架自动创建一个JavaScript 代理类,这个代理类和要调用的web service有相同的名称。因此,上面代码中 EmployeeService 并不是真正的 类,而是一个JavaScript 代理类。 代理类包括原始web service中所有的Web Method。除了原来的web method 所包括的参数外,每个方法还包括3个额外的参数。
第一个参数是一个JavaScript 函数,用于当web method 成功完成时调用的。记住:所有客户端和服务器端的AJAX 通信都是异步的,因此,这个函数用来捕获web method 的返回值。第二个参数是用于发生错误的情况下调用的JavaScript 函数。最后,第三个参数是当调用Web Service 发生超时的情况下调用的JavaScript 函数。
第一种情况,case ("select"),就是简单的调用GetEmployees() 方法;第二种情况,case ("selectone"),调用GetEmployee()方法,通过传统的JavaScript 代码获取下拉框中的employee ID;同理,第三、第四、第五个Case依次调用Insert()、 Update()和 Delete()方法。
上面的代码通过5个JavaScript函数实现相应的web method 成功调用:FillEmployeeList(), DisplayEmployeeDetails(), InsertEmployee(), UpdateEmployee()以及 DeleteEmployee()。每个函数接收一个参数作为web method相应的返回值。
function
FillEmployeeList(result)
{
var select=document.getElementById("Select1");
for(var i=0;i<result.length;i++)
{
var option=new Option(result[i].EmployeeID,
result[i].EmployeeID);
select.options.add(option);
}
}
function
DisplayEmployeeDetails(result)
{
var text1=document.getElementById("Text1");
var text2=document.getElementById("Text2");
text1.innerText=result.FirstName;
text2.innerText=result.LastName;
var lblMsg=document.getElementById("lblMsg");
lblMsg.innerText="";
}
function
InsertEmployee(result)
{
if(result>0)
{
var lblMsg=document.getElementById("lblMsg");
lblMsg.innerText="Employee added successfully!";
}
else
{
var lblMsg=document.getElementById("lblMsg");
lblMsg.innerText="Error occurred while adding new employee!";
}
}
function
UpdateEmployee(result)
{
if(result>0)
{
var lblMsg=document.getElementById("lblMsg");
lblMsg.innerText="Employee updated successfully!";
}
else
{
var lblMsg=document.getElementById("lblMsg");
lblMsg.innerText="Error occurred while updating the employee!";
}
}
function
DeleteEmployee(result)
{
if(result>0)
{
var lblMsg=document.getElementById("lblMsg");
lblMsg.innerText="Employee deleted successfully!";
}
else
{
var lblMsg=document.getElementById("lblMsg");
lblMsg.innerText="Error occurred while deleting employee!";
}
}
FillEmployeeList() 函数以Employee对象数组作为输入参数,还记得GetEmployees() web method 返回的Employee对象数组吧。然后对这个数组迭代处理,在每次迭代中,一个新的OPTION元素被创建并添加到下拉框中。DisplayEmployeeDetails()函数以一个Employee对象作为输入,这个Employee对象包括了一个Employee的详细信息,并显示在2个文本框中。InsertEmployee(), UpdateEmployee()和DeleteEmployee()函数以一个整型的数值标明INSERT, UPDATE和DELETE操作所影响的记录数,一个大于0的数值标明操作成功,并在<SPAN>标记内显示一个成功的信息;否则,显示一个错误信息。当页面第一次加载时,需要用现有的employee ID给下拉框赋值,这得通过调用一个特定的名为pageLoad()的函数中实现:
function
pageLoad()
{
CallWebMethod("select");
}
pageLoad()函数在客户端浏览器页面加载时自动调用,最后,错误处理(error handler)和超时处理(timeout handler)函数如下:
function
ErrorHandler(result)
{
var msg=result.get_exceptionType() + "/r/n";
msg += result.get_message() + "/r/n";
msg += result.get_stackTrace();
alert(msg);
}
function
TimeOutHandler(result)
{
alert("Timeout :" + result);
}
TimeOutHandler() 函数在任何web method 调用发生超时的情况下调用。它仅仅显示了一个Alert给用户。 ErrorHandler() 函数在有错误发生的情况下调用,其输入result 参数提供了3个方法:get_exceptionType()、get_message()以及 get_stackTrace()。这三个方法分别返回异常类型(type of exception)、详细错误信息 和堆栈跟踪(stack trace)。这里ErrorHandler()函数也仅仅显示了一个alert给终端用户。
测试网页
现在,我们已经实现了web service和客户端应用程序。测试一下吧!运行网页,试着增加、更新、删除一个employee看看,图5显示更新一个employee后的效果:
![](http://www.developer.com/img/2007/02/Figure5.jpg)
图 5: 更新Employee后的页面效果
要想测试错误处理函数,把初始化数据库链接字符串改成一个空值,然后运行网页看看,这次,就会显示一个警报(alert),如图6:
![](http://www.developer.com/img/2007/02/Figure6.jpg)
图 6: 链接字符串错误报警
调用外部Web Services
这个例子中,EmployeeService也是Web站点的一部分。有时候,我们的程序也许需要调用根本就没有部署在我们的域的web services。 ASP.NET AJAX内部需要依赖XML HTTP 对象,而由于安全原因,是不能和部署在其它外部站点进行通信的。这就意味着上面所说的技术对外部的web services调用无效。不幸的是,ASP.NET AJAX关于此问题还没有直接的解决方案(至少在RC版本)。然而,微软发布了一个仍在CTP阶段的“Bridge”技术,我们可以使用此技术来调用一个部署在本地的封装(Wrapper)的类,然后在这个类中来调用外部的实际的Web Service。在当前的RC版本中,我们可以在我们的Web Site中创建一个Wrapper Web Service,以它来调用最初的Web Service。然后在客户端程序中通过调用Wrapper Web Service实现通信。下面显示必要的步骤:
1. 在web站点中添加一个web引用,指向外部的Web service;
2. 创建一个本地Web service;
3. 在新创建的Web service中,提供封装的web method,这些方法调用外部的Web Method;
4. 用本文中所说的方法在客户端应用程序中调用本地新添加的web Service。
调用ASP.NET Web Services的基础架构
ASP.NET AJAX提供了完整的架构以从客户端JavaScript调用ASP.NET web services。我们可以轻松地用AJAX把服务器端数据集成进用户响应的Web页面中。而我们所需要做的就是仅仅用[ScriptService]属性来标识web Service。ASP.NET AJAX 框架会为我们的web service自动生成JavaScript代理,然后通过使用代理来调用web methods。
下载源码
[原文源码下载]
作者:Bipin Joshi
Email:http://www.dotnetbips.com/contact.aspx
简介:Bipin Joshi是DotNetBips.com的管理员。他是http://www.binaryintellect.com/的发起人,这个公司提供.NET framwork的培训和咨询服务。他在印度孟买为开发者提供培训。他也是微软的MVP(ASP.Net)和ASPInsiders的会员。
译者注:原文中的document.getElementById可以用$get来代替
[原文源码下载]
ASP.NET AJAX调用Web Service
原文发布日期:2007.02.08
作者:Bipin Joshi
翻译:webabcd
介绍
尽管AJAX是种客户端技术,但实际上的开发过程,它经常要调用一个服务器端的过程。通常,网站上的数据是存放在一个关系型数据库中,为了让AJAX更有用处,处理服务器端数据需要一种简单可靠的方法。幸运的是,ASP.NET AJAX提供了一种有效的基础架构来做这件事情,浏览器和服务器在Internet上可以进行AJAX通信。自然而然,Web Service在数据传输和客户端/服务器之间的一般通信方面可以扮演一个重要角色。本文就演示了如果通过ASP.NET AJAX调用ASP.NET web services。
软件需求
本文所有的范例都是使用ASP.NET AJAX RC版,而且,要在SQL Server 2005 (Express版即可)上有一个Northwind数据库。范例使用Visual Studio 2005作为开发环境。
范例场景
范例开发了一个Web页面,用于输入Northwind数据库职员表中的职员数据。页面通过ASP.NET AJAX功能,调用一个Web Service来完成职员表中的数据增、删、改、查。
创建一个Web Service
作为开始,使用Visual Studio 2005创建一个新的Web站点,注意把ASP.NET AJAX项目模板添加到新站点对话框,这个对话框包括一个"ASP.NET AJAX Enabled Web Site" 模板。
![](http://www.developer.com/img/2007/02/Figure1.jpg)
图1:新站点创建模板
使用"ASP.NET AJAX Enabled Web Site" 模板创建的新站点和用普通方法创建的站点区别如下:
·它的Web.config自动包括许多ASP.NET AJAX专用的配置信息。
·System.Web.Extensions程序集被添加到引用中。
当然,我们可以更改一个普通的Web站点,以使之符合AJAX要求,但模板可以大大简化我们的工作。
现在我们创建了一个新的Web站点,添加一个新的web service并命名为EmployeeService.asmx,EmployeeService将包括5个Web方法
Method Name | Description |
GetEmployees() | 返回Employees表里的雇员列表。 这个列表是一个Employee对象数组 |
GetEmployee() | 接收EmployeeID参数返回Employee对象的详细信息 |
Insert() | 给Employees表里增加一个新的雇员信息 |
Update() | 更新Employees表里的某个雇员信息 |
Delete() | 删除Employees表里的某个雇员信息 |
GetEmployees() 和 GetEmployee()方法以Employee对象的形式返回数据,因此,首先创建一个Employee类。右键单击App_Code文件夹,选择“添加新项…”,添加一个叫Employee的类,下面显示Employee类的全部代码:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
Employee类申明三个Private变量来分别存放employee ID, first name和 last name,三个变量再封装在三个public属性中:EmployeeID, FirstName和LastName。
打开 web.config文件,添加<connectionStrings>部分如下:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
这部分存放数据库链接字符串,用于指向Northwind数据库,确保修改SqlServer名称、IP地址以及验证方式以和我们的开发环境相符。
现在,打开EmployeeService.cs添加如下代码:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
代码使用了ConfigurationManager类来读取配置文件中的数据库链接字符串,并存放在一个类级别的变量strConn中,这个变量将被下面的所有Web Method所使用。
现在,添加GetEmployees() web method:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
代码创建了SqlConnection and SqlCommand 对象,然后执行SELECT查询,以获取Employees表中EmployeeID, FirstName 和LastName字段。结果通过SqlDataReader返回。然后,创建一个generic-based Employee数组,通过While循环,给每个Employee实例的属性赋值。当While循环完毕的时候,关闭SqlDataReader 和 SqlConnection。GetEmployees()方法返回的类型是Employee数组。因此,generic List使用List类中的ToArray()方法来转换成Employee数组。
现在,添加一个GetEmployee() web method如下:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
GetEmployee() web method接受一个employee ID参数作为输入,代码和前面的非常相似,但这次只返回一个employee。注意,使用SqlParameter来定义传入的EmployeeID。
现在,再添加Insert()、Update()和 Delete()web methods,其中,Insert() web method 以要添加的Employee的 first name 和 last name 作为参数,Update() web method 以要更新的employee ID 以及新的first name 和 last name作为参数,并执行UPDATE语句, Delete() web method 以要删除的employee ID 作为参数,然后执行DELETE 语句
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
这就完成了web service的创建。到目前为止,还没有做任何和AJAX特性相关的任何工作,现在,时机已经成熟,我们通过下面的代码更改web service类的定义:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
注意特地标明的黑体字,我们导入了System.Web.Script.Services命名空间,这个命名空间来自System.Web.Extensions程序集,这个命名空间提供了[ScriptService]属性,这将使web service可以被来自客户端的JavaScript (如ASP.NET AJAX)调用。
好了,我们开始准备从ASP.NET AJAX调用Web Service了!
如何调用Web Service
这部分,我们将创建一个Web页面作为数据输入,通过调用刚刚创建的Web Service来操作Employees表。作为开始,我们先添加一个EmployeeServiceClient.aspx页面,打开工具箱,选择View > Toolbox菜单,在工具箱上,选中AJAX Extensions这样的节点(见图2)
![](http://www.developer.com/img/2007/02/Figure2.jpg)
图 2: 增加模板后的新站点创建对话框
AJAX Extensions部分显示一个Web页面上所有可以使用的ASP.NET AJAX组件。所有使用ASP.NET AJAX的页面都需要一个ScriptManager组件。打开ScriptManager属性窗口,定位Services属性,打开Service引用编辑器,如图3:
![](http://www.developer.com/img/2007/02/Figure3.jpg)
图 3: Service 引用编辑器
点击对话框底部的Add按钮,设置Path属性以指向Web Service(EmployeeService.asmx)的虚拟路径,下面的标记将会产生在Web页面文件中:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
对每个Web Service调用,都需要在<asp:ScriptManager>部分添加一个<asp:ServiceReference>元素,此标记把要使用的web service注册到当前web form上。
![](http://www.developer.com/img/2007/02/Figure4.jpg)
图 4: 设计页面表单
表单包括一个下拉框(<SELECT>) ,用于显示所有的employee IDs,一旦选中其中一个employee ID,employee的详细信息将显示在2个文本框中,然后可以更新这些信息。如果要添加一个employee,只需要输入first name 和 last name,然后点击“插入”按钮就可以了。同理,如果要删除一个employee,选择下拉框中的employee ID,点击“删除”按钮。在INSERT、UPDATE或者 DELETE操作完成后,将会显示成功或者失败的信息。下面是所有的页面代码:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
注意:我们没有使用ASP.NET服务器端控件,如DropDownList、 TextBox 以及 Button。取而代之的是,我们用的传统的HTML控件,如:<SELECT> 以及 <INPUT>。这因为我们要想通过客户端JavaScript调用web service,而不是通过服务端代码。同理,注意底下的<SPAN>标记,这是用来显示成功或者失败的信息的。
下一步,在<head>元素内增加一个<script>部分,添加一个CallWebMethod()的函数:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
CallWebMethod() 函数 就是用来调用web service的中央控制函数。 这个函数接收一个字符串参数用来标识调用的方法,它包括一个switch 语句来判断调用的方法,每个 case 块 调用一个web method。 注意web method 是如何被调用的:ASP.NET AJAX 框架自动创建一个JavaScript 代理类,这个代理类和要调用的web service有相同的名称。因此,上面代码中 EmployeeService 并不是真正的 类,而是一个JavaScript 代理类。 代理类包括原始web service中所有的Web Method。除了原来的web method 所包括的参数外,每个方法还包括3个额外的参数。
第一个参数是一个JavaScript 函数,用于当web method 成功完成时调用的。记住:所有客户端和服务器端的AJAX 通信都是异步的,因此,这个函数用来捕获web method 的返回值。第二个参数是用于发生错误的情况下调用的JavaScript 函数。最后,第三个参数是当调用Web Service 发生超时的情况下调用的JavaScript 函数。
第一种情况,case ("select"),就是简单的调用GetEmployees() 方法;第二种情况,case ("selectone"),调用GetEmployee()方法,通过传统的JavaScript 代码获取下拉框中的employee ID;同理,第三、第四、第五个Case依次调用Insert()、 Update()和 Delete()方法。
上面的代码通过5个JavaScript函数实现相应的web method 成功调用:FillEmployeeList(), DisplayEmployeeDetails(), InsertEmployee(), UpdateEmployee()以及 DeleteEmployee()。每个函数接收一个参数作为web method相应的返回值。
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
FillEmployeeList() 函数以Employee对象数组作为输入参数,还记得GetEmployees() web method 返回的Employee对象数组吧。然后对这个数组迭代处理,在每次迭代中,一个新的OPTION元素被创建并添加到下拉框中。DisplayEmployeeDetails()函数以一个Employee对象作为输入,这个Employee对象包括了一个Employee的详细信息,并显示在2个文本框中。InsertEmployee(), UpdateEmployee()和DeleteEmployee()函数以一个整型的数值标明INSERT, UPDATE和DELETE操作所影响的记录数,一个大于0的数值标明操作成功,并在<SPAN>标记内显示一个成功的信息;否则,显示一个错误信息。当页面第一次加载时,需要用现有的employee ID给下拉框赋值,这得通过调用一个特定的名为pageLoad()的函数中实现:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
pageLoad()函数在客户端浏览器页面加载时自动调用,最后,错误处理(error handler)和超时处理(timeout handler)函数如下:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
TimeOutHandler() 函数在任何web method 调用发生超时的情况下调用。它仅仅显示了一个Alert给用户。 ErrorHandler() 函数在有错误发生的情况下调用,其输入result 参数提供了3个方法:get_exceptionType()、get_message()以及 get_stackTrace()。这三个方法分别返回异常类型(type of exception)、详细错误信息 和堆栈跟踪(stack trace)。这里ErrorHandler()函数也仅仅显示了一个alert给终端用户。
测试网页
现在,我们已经实现了web service和客户端应用程序。测试一下吧!运行网页,试着增加、更新、删除一个employee看看,图5显示更新一个employee后的效果:
![](http://www.developer.com/img/2007/02/Figure5.jpg)
图 5: 更新Employee后的页面效果
要想测试错误处理函数,把初始化数据库链接字符串改成一个空值,然后运行网页看看,这次,就会显示一个警报(alert),如图6:
![](http://www.developer.com/img/2007/02/Figure6.jpg)
图 6: 链接字符串错误报警
调用外部Web Services
这个例子中,EmployeeService也是Web站点的一部分。有时候,我们的程序也许需要调用根本就没有部署在我们的域的web services。 ASP.NET AJAX内部需要依赖XML HTTP 对象,而由于安全原因,是不能和部署在其它外部站点进行通信的。这就意味着上面所说的技术对外部的web services调用无效。不幸的是,ASP.NET AJAX关于此问题还没有直接的解决方案(至少在RC版本)。然而,微软发布了一个仍在CTP阶段的“Bridge”技术,我们可以使用此技术来调用一个部署在本地的封装(Wrapper)的类,然后在这个类中来调用外部的实际的Web Service。在当前的RC版本中,我们可以在我们的Web Site中创建一个Wrapper Web Service,以它来调用最初的Web Service。然后在客户端程序中通过调用Wrapper Web Service实现通信。下面显示必要的步骤:
1. 在web站点中添加一个web引用,指向外部的Web service;
2. 创建一个本地Web service;
3. 在新创建的Web service中,提供封装的web method,这些方法调用外部的Web Method;
4. 用本文中所说的方法在客户端应用程序中调用本地新添加的web Service。
调用ASP.NET Web Services的基础架构
ASP.NET AJAX提供了完整的架构以从客户端JavaScript调用ASP.NET web services。我们可以轻松地用AJAX把服务器端数据集成进用户响应的Web页面中。而我们所需要做的就是仅仅用[ScriptService]属性来标识web Service。ASP.NET AJAX 框架会为我们的web service自动生成JavaScript代理,然后通过使用代理来调用web methods。
下载源码
[原文源码下载]
作者:Bipin Joshi
Email:http://www.dotnetbips.com/contact.aspx
简介:Bipin Joshi是DotNetBips.com的管理员。他是http://www.binaryintellect.com/的发起人,这个公司提供.NET framwork的培训和咨询服务。他在印度孟买为开发者提供培训。他也是微软的MVP(ASP.Net)和ASPInsiders的会员。
译者注:原文中的document.getElementById可以用$get来代替