1. 有关生存期的补充

正常情况下,每次调用 WebMethod,服务器都会创建一个新的 WebService 对象,即便客户端使用同一个代理对象多次调用 WebMethod。

而我们一旦调用了有缓存标记的 WebMethod,只要未超出缓存期,WebService 对象都不会被重新创建。在缓存期内调用没有缓存标记的 WebMethod,也会继续使用该 WebService 对象。有太多因素让这个缓存机制变得不那么可靠,因此我们不能奢望用缓存标记来维持特定的对象状态,况且缓存机制的设计初衷也只是为了快速输出那些比较稳定非常大的数据。

基于多用户并发调用这个环境,WebService 本身最好设计成无状态对象,我们可以使用 Session 和 Application 来保持特定的状态信息。

2. 异步调用

网上很多人在写有关 .net 2.0 的文章时,都喜欢用“优雅”这个词。的确,在 2.0 中编译器和代码生成器为我们封装了很多罗嗦的东西,诸如匿名方法、委托推断等等,当然还有这 WebService 的异步调用。我们不用再写那些个 BeginXXX、EndXXX 了,基于事件驱动的异步机制会自动为每个 WebMethod 生成一个 XXXAsync 的异步方法和 XXXCompleted 事件,我们只需调用该方法,并处理该事件即可完成异步操作,当真是优雅了不少。不要小看 2.0 的这些封装,我们编写的代码越少意味着出错的几率越小。

下面的示例中,我们使用了匿名方法来处理事件,看上去更简洁了些。

WebServices.cs

[WebService(Namespace = "http://www.rainsts.net/", Description="我的Web服务")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebService : System.Web.Services.WebService
{
  [WebMethod]
  public string HelloWorld()
  {
    return "Hello World!";
  }
}

Client.cs

WebService ws = new WebService();
ws.HelloWorldCompleted += delegate(object sender, HelloWorldCompletedEventArgs e)
{
  Console.WriteLine(e.Result);
};

ws.HelloWorldAsync("xxx");

3. 缓存

WebMethodAttribute.CacheDuration 为 WebService 提供了缓存申明机制。通过添加该标记,我们可以缓存输出结果。不过缓存机制会影响 WebService 的生存期(见上)。

WebServices.cs

[WebService(Namespace = "http://www.rainsts.net/", Description="我的Web服务")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebService : System.Web.Services.WebService
{
  [WebMethod(CacheDuration=10)]
  public DateTime TestCache()
  {
    return DateTime.Now;
  }
}

Client.cs

WebService ws = new WebService();

for (int i = 0; i < 20; i++)
{
  Console.WriteLine("{0}:{1}", i + 1, ws.TestCache());
  Thread.Sleep(1000);
}

4. 保持状态

.NET WebService 是建立在 ASP.NET 基础上,在 WebService 中我们同样可以访问 Session、User、Application 等上下文对象,不过在某些使用细节上可能有所不同。

由于 WebService 客户端代理对象可能应用于 ConsoleApplication、WinForm 或 WebForm 等环境,而 Session 又必须通过 Cookie 来保存唯一的 SessionID,因此我们必须使用 CookieContainer 创建 Cookie 容器来保存 WebService 返回的 Session 信息,否则每次调用的 SessionID 都不同,自然无法使用 Session 来保存状态了。

创建容器对象后,必须将其引用赋值给代理对象的 CookieContainer 属性。在第一次调用 SessionEnabled WebMethod 后,该容器将持有 Session Cookie 信息。如果需要在多个代理对象中调用 SessionEnabled WebMethod,那么它们必须持有同一个 Cookie 容器对象。

WebServices.cs

[WebService(Namespace = "http://www.rainsts.net/", Description="我的Web服务")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebService : System.Web.Services.WebService
{
  [WebMethod(EnableSession = true)]
  public string TestSession()
  {
    string s = "TestSession";
    object o = Session[s];
    int i = o != null ? (int)o : 0;

++i;
    Session[s] = i;

return Session.SessionID.ToString() + ":" + i;
  }
}

Client.cs

WebService ws = new WebService();

// 创建Cookie容器,保持SessionID。否则每次调用的 SessionID 都不同。
CookieContainer cookies = new CookieContainer();
ws.CookieContainer = cookies;

for (int i = 0; i < 10; i++)
{
  Console.WriteLine("{0}:{1}", i + 1, ws.TestSession());
}

至于 Application 的使用和 WebForm 中基本没有什么区别。

WebServices.cs

[WebService(Namespace = "http://www.rainsts.net/", Description="我的Web服务")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebService : System.Web.Services.WebService
{
  [WebMethod]
  public DateTime TestApplicationState()
  {
    object o = Application["TestApplicationState"];
    if (o == null)
    {
      o = DateTime.Now;
      Application["TestApplicationState"] = o;
    }

return (DateTime)o;
  }
}

Client.cs

for (int i = 0; i < 10; i++)
{
  WebService ws = new WebService();
  Console.WriteLine("{0}:{1}", i + 1, ws.TestApplicationState());
  Thread.Sleep(1000);
}

5. SoapHeader

SoapHeader 多数情况下用来传递用户身份验证信息,当然它的作用远不止如此,有待于在实际应用中发掘。

SoapHeader 缺省情况下由客户端代理对象发送给 WebService,当然我们可以通过 WebMethodAttribute.Direction 来改变传送方向。

SoapHeader 使用步骤:

(1) 创建继承自 System.Web.WebServices.SoapHeader 的自定义 SoapHeader 类型。
(2) 在 WebService 中创建拥有 public 访问权限的自定义 SoapHeader 字段。
(3) 在需要使用 SoapHeader 的 WebMethod 上添加 SoapHeaderAttribute 访问特性。SoapHeaderAttribute 构造必须指定 memberName 参数,就是我们在第二步中申明的字段名称。
(4) 生成器会自动为客户端生成同名的自定义 SoapHeader 类型,只不过比起我们在 WebService 端创建的要复杂一些。同时还会为代理类型添加一个 soapheaderValue 属性。

在下面的演示代码,客户端将传递一个自定义 MyHeader 到 WebService。请注意,我们尽管在 WebService 中申明了 MyHeader 字段,但并没有创建对象实例,这是因为客户端传递过来的 XML 中包含了 SoapHeader 信息,基础结构会自动解析并创建对象实例,然后赋值给 my 字段。至于客户端,自然需要创建一个 MyHeader 对象实例,并赋值给 WebService.MyHeaderValue 属性。SoapHeaderAttribute.Direction 缺省就是 In,下面例子中的 "Direction = SoapHeaderDirection.In" 可以省略。

WebServices.cs

public class MyHeader : SoapHeader
{
  public string Username;
  public string Password;
}

[WebService(Namespace = "http://www.rainsts.net/", Description="我的Web服务")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebService : System.Web.Services.WebService
{
  public MyHeader my;

[WebMethod]
  [SoapHeader("my", Direction = SoapHeaderDirection.In)]
  public void TestSoapHeadIn()
  {
    System.Diagnostics.Debug.Write(my.Username);
    System.Diagnostics.Debug.Write(my.Password);
  }
}

Client.cs

WebService ws = new WebService();

MyHeader head = new MyHeader();
head.Username = "u2";
head.Password = "p2";

ws.MyHeadValue = head;
ws.TestSoapHeadIn();

我们改写一下,将传递方向改为从 WebService 到客户端。自然我们需要调整 "Direction = SoapHeaderDirection.Out",在 WebMethod 中我们还必须创建 MyHeader 实例,因为这次我们不会接受到客户端传递的 SoapHeader 了。客户端代理对象调用 WebMethod 后就可以使用 MyHeaderValue 属性访问其内容了。

WebServices.cs

public class MyHeader : SoapHeader
{
  public string Username;
  public string Password;
}

[WebService(Namespace = "http://www.rainsts.net/", Description="我的Web服务")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebService : System.Web.Services.WebService
{
  public MyHeader my;

[WebMethod]
  [SoapHeader("my", Direction = SoapHeaderDirection.Out)]
  public void TestSoapHeadOut()
  {
    my = new MyHeader();
    my.Username = "u1";
    my.Password = "p1";
  }
}

Client.cs

WebService ws = new WebService();
ws.TestSoapHeadOut();

Console.WriteLine(ws.MyHeaderValue.Username);
Console.WriteLine(ws.MyHeaderValue.Password);

6. 异常

ASP.NET WebService 通过 Fault XML 元素来传递异常信息,客户端代理对象会生成一个 SoapException 的异常,并使用 Fault XML 信息填充其相关属性,诸如 Message 等。另外我们可以对 WebService 进行异常包装,除了传递 Exception Message 外,还可以传递一些错误状态代码,以便客户端用户做进一步处理。

WebServices.cs

[WebService(Namespace = "http://www.rainsts.net/", Description="我的Web服务")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebService : System.Web.Services.WebService
{
  [WebMethod]
  public void TestException()
  {
    try
    {
      throw new Exception("aaa...");
    }
    catch (Exception e)
    {
      throw new SoapException(e.Message, new System.Xml.XmlQualifiedName("ErrorCode01"), e);
    }
  }
}

Client.cs

WebService ws = new WebService();

try
{
  ws.TestException();
}
catch (System.Web.Services.Protocols.SoapException e)
{
  Console.WriteLine(e.Message);
  Console.WriteLine(e.Code.Name);
}

原文地址:http://www.rainsts.net/article.asp?id=282

转载于:https://www.cnblogs.com/wfwup/archive/2009/12/02/1615186.html

WebServices 基础知识相关推荐

  1. android基础知识

    技术型男 随笔 - 20, 文章 - 0, 评论 - 4, 引用 - 0 android基础知识 1. 前言 1.1. 什么是3G.4G Ÿ 第三代移动通信技术(3rd - Generation),速 ...

  2. 嵌入式Linux的OTA更新,基础知识和实现

    嵌入式Linux的OTA更新,基础知识和实现 OTA updates for Embedded Linux, Fundamentals and implementation 更新的需要 一旦嵌入式Li ...

  3. 计算机基础知识第十讲,计算机文化基础(第十讲)学习笔记

    计算机文化基础(第十讲)学习笔记 采样和量化PictureElement Pixel(像素)(链接: 采样的实质就是要用多少点(这个点我们叫像素)来描述一张图像,比如,一幅420x570的图像,就表示 ...

  4. 嵌入式linux编程,嵌入式Linux学习笔记 - 嵌入式Linux基础知识和开发环境的构建_Linux编程_Linux公社-Linux系统门户网站...

    注:所有内容基于友善之臂Mini2440开发板 一.嵌入式Linux开发环境的构建 嵌入式开发一般分为三个步骤: 1.编译bootloader,烧到开发板 2.编译嵌入式Linux内核,烧到开发板 3 ...

  5. 《计算机网络应用基础》模拟试卷(六),《计算机与网络应用基础知识1》模拟试卷...

    <计算机与网络应用基础知识1>模拟试卷 (4页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.9 积分 <计算机与网络应用基础知识1& ...

  6. python向量计算库教程_NumPy库入门教程:基础知识总结

    原标题:NumPy库入门教程:基础知识总结 视学算法 | 作者 知乎专栏 | 来源 numpy可以说是 Python运用于人工智能和科学计算的一个重要基础,近段时间恰好学习了numpy,pandas, ...

  7. python常用变量名_python基础知识整理

    Python Python开发 Python语言 python基础知识整理 序言:本文简单介绍python基础知识的一些重要知识点,用于总结复习,每个知识点的具体用法会在后面的博客中一一补充程序: 一 ...

  8. 计算机基础知识掌握欠缺,《计算机基础知识》实验教学改革探讨.pdf

    <计算机基础知识>实验教学改革探讨.pdf Science& TechnologyVision 科 技 视 界 科技 探·索·争鸣 计<算机基础知识>实验教学改革探讨 ...

  9. python计算wav的语谱图_Python实现电脑录音(含音频基础知识讲解)

    前言 今天开始进入近期系列文章的第一篇,如何用 Python 来实现录音功能. 在开始"造轮子"之前,个人一直强调一个观点,如果有些东西已经有了,不妨直接去 github 上搜,用 ...

最新文章

  1. Android问题汇总
  2. 集成平台集群任务动态分派
  3. 新的学期、新的开始、新的付出、新的收获!
  4. [译] 美国证券法对 ICO 及相关 Fund 的最新动态
  5. win03组策略-入门篇
  6. yudian温控表a1温度怎么补偿_贴片电容怎么确定型号
  7. python 实现代码雨(转载)
  8. 企业办理CMMI认证是怎么收费的?
  9. 【通俗易懂的通信】贝叶斯公式 全概率公式 及其理解
  10. “程序员年薪50万到底有多累、多辛苦?”,句句扎心
  11. TypeScript-键盘映射
  12. PCB logo 制作 视频教程 内含 PCBLogoCreator软件
  13. 捕捉百合网的女同志和echarts展示
  14. 【Codeforces 1157F】 Maximum Balanced Circle | 思维、dp、二分
  15. linux查看其他用户history,从Linux服务器上的其他用户隐藏命令历史记...
  16. 新手机为什么一注册陌陌就封解析硬改软改
  17. rapidSVN : Error while performing action: ra_serf: The server sent a truncated HTTP response body.
  18. 图文详解STM32F0xx基于标准库新建工程
  19. 百度飞桨 x Datawhale联合主办黑客马拉松!
  20. mapgis转shp左右位置偏差

热门文章

  1. javascript --- polyfill中几个常用方法
  2. Python之NumPy(axis=0 与axis=1)区分
  3. spark 免密码登录- ssh 指定非22端口
  4. struts2 中文件的位置问题
  5. Linux-Android 修改屏蔽长按键功能
  6. cant find module express
  7. hdu 4409 Family Name List LCA +stl
  8. ROS与navigation教程——基本导航调整指南
  9. 【TensorFlow】——索引与切片
  10. java前端ajax提交数据_Java 前端使用Ajax通过FormData传递文件和表单数据到后台