`
yizhyi
  • 浏览: 61688 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Web Service中保持ASP.net的状态

    博客分类:
  • .net
阅读更多

简介

网络程序开发者们遇到的最普遍的问题就是如何在无状态的基于HTTP协议的交互中保持状态信息。有许多聪明的办法可以解决HTTP协议的无状态问题,例如对每个请求重复发送应用程序数据包、使用HTTP认证机制来将请求映射到特定的用户、使用Cookie来存储一系列请求的状态等。在ASP.net技术中提供了一个非常有效的方案来保持状态,该方案隐藏了所有高难度的,具有挑战性的工作的细节,用户只需简单地使用System.Web.SessionState.HttpsessionState类。同时,你也可以像在ASP.NET程序的Web页面(.ASPx)中那样在Web Service的方法中使用这个类,只有一点小小的不同。

  ASP.net的session对象概述

ASP.NET的session状态信息是通过两个机制保持。其一是使用Cookie。当客户端发送一个请求到服务器端时,服务器将发回一个附加HTTP Set-Cookie头的响应信息,而Cookie的值就是以键/值对的形式保存在该信息里边。在对同一服务器的所有的同步请求中,客户端在HTTP Cookie头中发送Cookie键/值对。然后服务器可以将并发的请求同初始的请求对应起来。ASP.net使用一个保存会话的ID的cookie来保持会话状态。该ID标识被用来为特定的用户找到与其对应的HttpSessionState类的实例。类HttpsessionState仅仅提供了一个通用的数据集,你可以在其中保存你需要的任何信息。 字串1

ASP.net用来保持状态的另外一种机制是无须使用Cookie。一些浏览器被用户设置为禁止使用Cookie或者干脆就不支持Cookie,ASP.NET提供了一种机制来解决这个问题,它的主要原理是将一个请求重定向到一个包含ASP.net状态ID的URL。当该请求被接受到时,这个嵌在URL中的ID被截取下来,服务器通过该ID找到合适的HttpsessionState类的实例。这种方式在HTTP协议的使用GET方式的请求中工作的很好,但是在.net的XML Web Service代码中会出现问题。

必须指出的是,有些时候把信息直接存储在Cookie中要比存储在Session中更好。避免使用Session可以节省服务器资源,而且你也无须考虑一些烦人的问题,比如定位一个特定的Session对象、Session对象因为请求的长时间的延迟而被移除或者在服务器上没必要地保留直到过期。然而,如果你有一些包含你不希望与你提供的服务的使用者共享的执行信息,或者有一些你不希望通过未加密的信道传输的私有数据,或者你认为将这些数据插入HTTP协议头中是不切实际的,那么你就应该使用ASP.net中的HttpSessionState,它将使你轻松解决这些问题。HttpSessionState类返回一个索引键,用以将一个特定的用户映射到一个为该用户保存信息的HttpsessionState类的实例。总之,无论是ASP.NET的HttpsessionState类还是HTTP的Cookie都可以在ASP.net Web Service中使用。

字串2



  为什么要在XML Web Service中使用基于HTTP的机制来实现状态保持呢?

在SOAP请求中有许多方法来保持状态。一个切实可行的方法就是在SOAP头中包含一些像ASP中的会话ID的信息,然而问题在于你不得不:1) 仍然要自己编写服务器端代码,并且 2) 确信你的客户会像对待HTTP Cookie一样对待你的包含会话ID的SOAP头并且将它附加到每个请求中回传给你。当然有很多时候使用SOAP头的方法会很方便,但是也有很多时候还不如使用基于HTTP协议的方法。

很容易在ASP.NET中使用Session来保持状态信息,HttpSessionState类为你封装了存储Session状态的细节问题。绝大多数的客户端已经能够明白他们必须返回服务器设置的cookie,而且HttpsessionState类也支持在SOAP通信中常用的底层传输。因此,很明显,使用ASP.net的session机制会是满足状态控制要求的明智的选择。

  使服务器支持session

在ASP.net中,对Web方法的状态支持默认是关闭的,你必须为每个要使用Session状态的Web方法显式地激活Session支持。激活Session支持的方法是添加一个Enablesession选项到你的函数的WebMethod属性中,并且将其值设置为true。下面的代码演示了如何激活Session并且在方法中访问session状态信息。 字串4

[VB.NET]

<WebMethod(Enablesession:=True)> _
Public Function IncrementsessionCounterX() As Integer
Dim counter As Integer
If Context.session("Counter") Is Nothing Then
counter = 1
Else
counter = Context.session("Counter") + 1
End If
Context.session("Counter") = counter
Return counter
End Function


如你所料,如果你为一个Web方法激活了Session支持,并不意味着其它的Web方法的Session支持也被激活。事实上,如果Web方法的EnableSession选项没有被显式地设置为true,那么Context.session属性的值将是null。

假设通过设置web.config文件禁止session,那么即使你在WebMethod属性中使用了EnableSession选项,Context.Session的值也将一直是null。web.config文件中的/configuration/system.web/sessionState项有一个mode参数,它决定了你的ASP.net程序使用何种方法来保持Session状态。该参数默认设置为“InProc”,这时HttpsessionState对象将简单地保存在ASP.NET进程的内存区。如果被设置为“Off”,那么ASP.net程序的session支持就被关闭了。 字串8

从服务器端看来,ASP.net的session状态的有效范围仅仅是某一个给定的ASP.net应用程序,这就意味着一个HttpSessionState类的实例只能被一个特定用户向某一个虚拟目录发出的所有Session被激活的ASP.net请求所使用,也就是说,使用同一个会话ID的向其它的虚拟目录的请求将导致ASP.net不能找到对应的session对象——因为会话ID不是为该ASP.net应用程序设定的。ASP.NET并不区分对ASPX和ASMX文件的请求,直到该请求需要使用session对象,因此,理论上你可以在一个Web方法调用和一个普通的ASPX文件之间共享session状态信息。然而,我们将看到也有些客户端的问题使这个想法变得不那么容易实现。

当设置一个HTTP cookie,你可以指定其过期时间。过期时间指定在多久的时间内,客户端应该将该cookie回传给服务器。如果一个cookie没有被设置过期时间,那么它仅仅在该进程处理请求的时间内被回传。例如,IE将一直回传cookie,除非你关闭了浏览器的特定窗口。ASP.net的用来保存会话ID的Cookie没有过期时间,因此,如果一台客户机上的多个进程向你的服务器上发送HTTP请求,它们也不会共享同一个HttpsessionState对象,甚至两个进程同时运行也是这样。

如果你要处理来自同一个进程的并发的Web Service调用,那么这些请求将在服务器上被排序,从而使得在某一时刻只有一个请求被执行。ASP.NET的Web Service不像普通.ASPX页面,支持允许多请求的并发进程的对HttpSessionState对象的只读访问,所有session被激活的Web方法调用都具有read/write访问的权限,因此必须对之进行排序。 字串5
客户端的问题

在你的WebService中成功的使用HttpSessionState的功能事实上依赖于对用户的一些假设。首先,也是最重要的一点,如果你是用默认的HTTP Cookie模式来保存Session状态,你的客户端就必须支持cookie;如果你是用无cookie的机制来支持session,那么你的客户端必须能够并且愿意重定向到一个新的URL,该URL由原来的URL中插入会话ID而得到。结果将表明,这并不是一个无足轻重的问题,它关系到你能否成功地部署你的程序。

  所有工作都依赖于浏览器

如果你是用Microsoft Visual Studio.net来开发ASP.net Web Service应用程序,那么默认的调试方法就是打开IE访问你的.asmx文件。通常,系统将提供一个可以调用你的Web方法的友好的界面,这是一个调试你的Web Service代码的很好的途径。如果你已经将Web方法的EnableSession选项设置为true,它被非常漂亮地支持,甚至如果你打开了无cookie的Session支持,客户端浏览器也可以完美地完成这项工作,你的session对象将如你所愿地工作。

然而,大多数的Web Service请求不是来自浏览器,而是来自应用程序中的Web引用。我们如何使用.net框架的“添加Web引用”的特性呢?让我们来看一看。

添加Web引用的问题

我将使用我们前面看到的代码段来创建一个简单的XML Web Service。记起来了吧?这个Web方法被称作IncrementSessionCounter,它仅仅是简单地把一个整数存储在HttpsessionState对象中,然后每次调用则将它加1,并且返回当前值。从客户端浏览器我们可以看到这个数字的值随着调用次数的增加而增加。

步,我创建了一个简单的WinForm应用程序,并且将上述的Web Service添加到Web引用中。下面就是调用我的Web Service的代码:

' 这里并没有与session打交道
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim proxy As New localhost.Service1()
Dim ret As Integer
ret = proxy.IncrementsessionCounter()
Label1.Text = "Result: " & CStr(ret)
End Sub

当我第一次调用Web Service时,一切正常,Web方法返回1,这就是那个session变量的应有的初始值。现在我点击Button1来再次调用这个Web方法,我希望看到的返回值是2。可惜的是,无论我点击多少次Button1,返回值一直都是1。

字串4



你也许会怀疑原因就是我每次都创建了一个新的proxy类的实例去调用Web方法,因此每次我点击按钮,都会丢失次调用时的cookie。不幸的是,即使你将proxy类的初始化代码移到窗体的构造函数中,然后对每次Web方法调用使用同一个proxy类的实例,你还是不可能看到返回值有增加的迹象。


问题在于cookie。Web Service代码并未从调用请求中发现有效的会话ID,因此它每次被调用都创建一个全新的HttpsessionState对象,并且返回它的初始值1。因为作为客户端的proxy类是从类System.Web.Service.Protocols.SoapHttpClientProtocol继承的,它不包含System.Net.CookieContainer类的实例,因此,没有地方来存放返回的cookie。为了解决这个问题,我对代码做了如些修改:

' 使用了ASP.NET的session
' 但是并不是无Cookie的session.
Private Cookies As System.Net.CookieContainer

Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim proxy As New localhost.Service1()
Dim ret As Integer
字串9

' 为proxy类设置cookie容器
If Cookies Is Nothing Then
Cookies = New System.Net.CookieContainer()
End If
proxy.CookieContainer = Cookies
ret = proxy.IncrementsessionCounter()
Label1.Text = "Result: " & CStr(ret)
End Sub

现在代码工作正常了!每点击一次Button1,我都可以看到返回值增加1。注意到我并不是在函数中声明变量Cookies的,它是窗体类的一个私有成员,因为如果希望每次都返回同一个会话ID给服务器的话,就必须在每次请求中使用CookieContainer类的同一个实例。这就解释了为什么SoapHttpClientProtocol类默认不自动地设置的cookie容器。正应为此,你可以在多个SoapHttpClientProtocol类的实例中共享一个cookie容器,而不是为其每个实例自动地创建一个新的cookie容器。
无cookie的session

从Web Service的开发者的角度来看,你可以想到相当多的人在试图使用你的Web服务时忘记在客户端代理类中添加Cookie容器。聪明的开发者或许灵光一闪,就会发现无cookie的Session应该可以出色地解决这个问题。如果将web.config文件中sessionState元素的cookieless参数设置为“true”,你将会发现,通过浏览器界面调用Web方法时,session变量工作正常,但是如果你在Visual Studio.net中通过“添加Web引用”来调用它时,依然存在着一些问题。 字串9

为了研究无cookie的session,我决定使用上面已经使用过的代码,看看它能否在session状态被设置为cookieless的服务器环境中能否工作正常。我也不想费心去删除cookie容器的相关代码,因为我希望得到能在两种session状态下都正常工作的代码。作为一个天生的乐观主义者,我一个字也不改就直接运行它。令人失望的事发生了——不过也不是完全没有想到,我不得不面对这个异常:

An unhandled exception of type 'System.Net.WebException' occurred in system.web.services.dll

Additional information: The request failed with the error message:
--
<html><head><title>Object moved</title></head><body>
<h2>Object moved to <a href='/HttpsessionState/(l2z3psnhh2cf1oahmai44p21)/service1.asmx'>here</a>.</h2>
</body></html>

发生了什么呢?原来HTTP请求收到的不是“200 OK”响应。如果你熟悉HTTP协议,你或许可以从响应中的HTML代码中发现这是一个“302 Found”响应,这意味着该请求被重定向到超链接中指定的地址。返回HTML代码是很明智的,这样如果一个浏览器因为某些原因不支持重定向的话,它可以把代码显示出来,或者在重定向过程中显示这些代码直到重定向完成。注意到超链接中包含了一个有趣的字符串“(l2z3psnhh2cf1oahmai44p21)”,显然,我们可以推断这就是ASP.net的会话ID,它被嵌入了我们要重定向到的位置的URL中。在客户端代理中,我们需要做的仅仅是重新发送请求到这个新的URL。 字串3

无须再在Win32 WinInet API编程中跋涉,我们可以直接找到proxy类的一个属性允许自动重定向。用外行人的说法,就是如果我们接收到一个“302 Found”响应,就直接将请求重新发送到相应中HTTP位置头所指示的URL。当Visual Studio.net的智能提示显示proxy类的AllowAutoRedirect属性时,我感到这东西真是机灵得可爱。我马上就在代码中加上如行:

  proxy.AllowAutoRedirect = True

我认为这仍然比创建一个CookieContainer类并关联到proxy类要容易得多,于是我又一次运行程序。很不幸,我遭遇了如下异常(为了简洁起见有所删节):

An unhandled exception of type 'System.InvalidOperationException' occurred
in system.web.services.dll

Additional information: Client found response content type of 'text/html; charset=utf-8',
but expected 'text/XML'.

The request failed with the error message: …

如果你看到错误消息的内容,你会发现你所看到的HTML页面跟你浏览.ASMX文件的页面一样。问题是,为什么当我传送XML(以SOAP封装了的形式)到Web Service服务器时它返回的却是HTML代码?结果证实,你并没有在SOAP封装中发送HTTP POST请求,而仅仅发送了一个简单的没有内容的HTTP GET请求,因此你的Web Service服务端理所当然地假设这个请求来自浏览器,于是它返回普通的HTML响应。为什么会这样呢?

字串2



如果你了解HTTP协议,你会发现一个HTTP客户端在收到“302 Found”响应时发送HTTP GET请求到响应中指定的地址是合情合理的,即使初始请求是HTTP POST。这种方式下浏览器工作得很好,因为开始几乎所有的请求都是HTTP GET类型的,只有当你试图传递数据到一个URL时,才会出现上述失败的结果。

理由是在传送的数据中可能包含潜在的敏感数据,因此你需要确认是否用户真的想向新的资源传送数据。显然如果你转向基于重定向设置的新地址,你就没能确认用户是否真的允许将他们的数据发送到新的地址。因此数据并没有被发送,而代之以简单的HTTP GET请求。

我对代码做了如下修改,捕获“302 Found”异常,提示用户同意重定向他们的请求,然后再次在新的位置调用我的Web方法。

' 同时使用基于Cookie和Cookie的session
Private Cookies As System.Net.CookieContainer
Private webServiceUrl as Uri

Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
字串5

Dim proxy As New localhost.Service1()
Dim ret As Integer
' 设置proxy类的Cookie容器
If Cookies Is Nothing Then
Cookies = New System.Net.CookieContainer()
End If
proxy.CookieContainer = Cookies
' 设置proxy类的URL
If webServiceUrl Is Nothing Then
webServiceUrl = New Uri(proxy.Url)
Else
proxy.Url = webServiceUrl.AbsoluteUri
End If
Try
ret = proxy.IncrementsessionCounter()
Catch we As WebException
' 如果我们想检测HTTP状态码
' 那么就需要一个HttpWebResponse类的实例
If TypeOf we.Response Is HttpWebResponse Then
Dim HttpResponse As HttpWebResponse
HttpResponse = we.Response
If HttpResponse.StatusCode = HttpStatusCode.Found Then
' 这是一个“302 Found”响应,提示用户是否进行重定向
If MsgBox(String.Format(redirectPrompt, _
HttpResponse.Headers("Location")), _
MsgBoxStyle.YesNo) = _
MsgBoxResult.Yes Then
' 用户选择Yes,重新尝试新的URL
webServiceUrl = New Uri(webServiceUrl, _
字串5

HttpResponse.Headers("Location"))
Button1_Click(sender, e)
Return
End If
End If
End If
Throw we
End Try
Label1.Text = "Result: " & CStr(ret)
End Sub

现在ASP.net的session工作正常了。在你的应用程序中,你可以根据情况自行决定是否提示用户重定向HTTP POST请求。举一个例子,如果你正在调用一个Web Service,你也许就不希望出现任何可见的对话框。

这样看来,要使ASP.net的session完全正常地工作还真不是很容易。但是,应该意识到上面的代码所展示的原理在其他情况样的有用。例如,任何平台上的任何Web Service,只要它使用HTTP cookie,都需要一个cookie容器,类似地,也许有很多其他的原因导致当你向一个Web Service服务器发送请求时收到“302 Found”响应。在一个复杂的应用程序中调用Web Service时,可能有许多特殊的情形需要你去处理,cookie和重定向的问题就是两种这样的情形,你应该将之作为你的Web Service调用代码中最基本的部分。

  结 论

字串2


  在你调用Web方法的过程中,ASP.net对状态保持是非常有用的,你必须意识到,当你使用手边的浏览器界面测试你的Web Service时,你并没有面对客户端程序必须处理的问题。幸运的是,这些问题并不是很难解决。 

 

 http://www.dsdne.org/html/bianchengleyuan/_NETbiancheng/20070704/7223_2.html

分享到:
评论

相关推荐

    asp.net写的web service例子

    这个例子是为初学者设计的,旨在演示如何创建和使用Web Service,以及如何在ASP.NET环境中调用这些服务。 Web Service是一种通过HTTP协议进行通信的服务,允许不同系统之间交换数据。它基于SOAP(Simple Object ...

    web service 小例子asp.net带access数据库

    在这个"web service小例子asp.net带access数据库"中,我们将探讨如何在ASP.NET环境中创建一个简单的Web服务,并将其与Access数据库集成。 首先,我们需要了解ASP.NET Web服务的基础。ASP.NET Web服务,也称为ASMX...

    ASP.NET与Web Service实例剖析

    【ASP.NET与Web Service实例剖析】是一场技术讲座或教程,专注于讲解如何使用ASP.NET技术和Web Service进行实际项目开发。ASP.NET是微软推出的用于构建Web应用程序的开发框架,而Web Service则是一种基于XML的通信...

    ASP.NET与Web Service实例剖析中文版(PPT)

    ASP.NET和Web Service是微软开发框架中的核心技术,用于构建高效、可伸缩的Web应用程序和服务。这份"ASP.NET与Web Service实例剖析中文版(PPT)"资料涵盖了这两个主题的关键概念、技术和实际应用,对于学习和理解这...

    ASP .NET 与 Web Service 实例剖析

    在ASP.NET中集成Web Service,可以利用HttpClient类发送SOAP请求,并解析返回的XML数据。这样,Web Service可以作为后台数据源,为ASP.NET网页提供动态内容。例如,网页上的天气预报模块可以调用上述的"GetWeather...

    如何在IIS6.0里面显示ASP.NET v2.0.50727

    为确保ASP.NET能够正常运行,需对`Network Service`用户和`ASPNET`用户(在某些环境中可能为`IUSR`用户)进行正确的权限配置。这包括给予这两个用户访问`C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727`目录及其子...

    ASP.NET与Web Service实例剖析中文版

    4. **状态管理**:理解Session、Cookie和Application状态在ASP.NET中的使用。 5. **Web Service的开发与调用**:创建SOAP或RESTful Web Service,以及如何从客户端(如JavaScript或移动应用)调用这些服务。 6. **...

    asp.net 利用webservice,dataset创建火车票查询系统

    在本项目中,我们将探讨如何使用ASP.NET技术,结合Web服务(WebService)和DataSet来创建一个火车票查询系统。这是一个常见的Web应用程序开发实践,旨在提供用户友好的界面,查询全国范围内的火车票信息。 首先,...

    ASP.NET Web Service

    在ASP.NET中,可以通过配置Web.config文件或在代码中添加验证逻辑来实现这一点。例如,可以设置`<system.web>`部分的`<authentication>`和`<authorization>`元素,以要求用户提供用户名和密码来访问Web服务。 当...

    使用ASP.NET AJAX异步调用Web Service和页面中的类方法

    ASP.NET AJAX 提供了一种强大的机制,使得开发者可以方便地在客户端JavaScript中异步调用Web Service和页面中的类方法,极大地简化了原本复杂的Ajax通信。这一特性是ASP.NET AJAX框架的核心优势之一,它允许开发者...

    ASP.net 中用C#调用Java web service 图解教程

    ASP.NET 中使用 C# 调用 Java Web Service ...在 ASP.NET 中使用 C# 调用 Java Web Service 需要了解 Web Service 的基本概念、使用 C# 调用 Java Web Service 和在 ASP.NET 中实现 Web Service 的客户端和服务器端。

    WCF Rest Service Example in Asp.net

    在ASP.NET中,WCF REST服务可以轻松集成到Web应用程序中,与其他ASP.NET功能协同工作,如身份验证、授权和状态管理。此外,还可以利用ASP.NET MVC的路由功能来实现更加灵活的URL模式。 总结起来,WCF REST服务在ASP...

    asp.net连接sql数据库web.config配置

    在ASP.NET中,连接SQL Server数据库通常涉及到对`web.config`文件的配置。`web.config`是ASP.NET应用程序的核心配置文件,它包含了诸如应用程序设置、连接字符串、身份验证模式等重要信息。本篇文章将深入探讨如何在...

    C#Web服务Asp.net调用winFrom调用

    在IT行业中,C#是一种广泛使用的编程语言,尤其在开发Windows桌面应用程序(WinForms)和Web服务(ASP.NET)方面。本主题将深入探讨如何在ASP.NET Web服务中调用WinForms应用程序的功能,以实现更复杂的系统集成和...

    ASP.Net web server demo

    这将帮助理解如何在ASP.NET中创建和消费Web服务,包括ASMX和WCF服务。此外,还可能包含了配置文件(如web.config)和数据库连接字符串,用于设置应用的运行环境和数据库连接。 通过分析和学习这个ASP.NET Web ...

    ASP.NET Webservice天气预报实例

    ASMX是ASP.NET中创建Web Service的标准文件扩展名,它包含一个或多个Web方法,这些方法可以通过HTTP协议被远程调用。在"Weather"这个实例中,可能有一个名为"WeatherService.asmx"的ASMX文件,其中定义了获取天气...

Global site tag (gtag.js) - Google Analytics