|
'''' Does NOT work with ASP.NET Sessions 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
When I invoke the Web service the first time, everything works as
expected. The Web method returns the initial value for my session
variable, which is 1. Now if I click on Button1 to invoke my Web method
again, I expect to see a returned value of 2. However, no matter how
many times I click on Button1, I always see a value of 1 returned.
You might suspect the cause of this is that I''''m creating a new
instance of the proxy class for my Web service, so each time I click on
the button, I am losing my cookies (so to speak). Unfortunately, even
if you move the proxy initialization code into the constructor for your
Form class and use the same instance of the proxy for each Web
method call, you still will not see the session variable return with a
value greater than 1.
The problem is with the cookies. The Web service code does not see a
valid session ID with the request, so it creates a brand new HttpSessionState
object for each call, and returns the initial value of 1. The reason
for this is that the client proxy class, which inherits from the System.Web.Services.Protocols.SoapHttpClientProtocol class does not have an instance of the System.Net.CookieContainer class
associated with it. Basically, there is no place to store cookies that
are returned. To fix this problem, I changed my code as follows with
the new code highlighted:
'''' Works with cookied ASP.NET sessions but NOT with '''' cookieless sessions.
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
'''' Set the Cookie Container on the proxy
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
And now the code works as expected! With each click of Button1, I
see the returned value increase by 1. Note that the Cookies variable is
not declared inside my function. It is a private member of my form
class. I need to use the same instance of the CookieContainer
class with each request if I expect the same session ID cookie to be
returned to the server. This explains why a default cookie container is
not automatically associated with an instance of the SoapHttpClientProtocol
class. There is a good chance that you would want to use a separately
managed cookie container that could be shared among multiple instances
of the SoapHttpClientProtocol class, instead of automatically creating a new cookie container for each instance.
Cookieless Sessions
From the standpoint of the Web service developer, you might think
that quite a few people trying to consume your service will forget to
add a cookie container to their client proxies. With a clever twinkle
in your eye, you also might think that cookieless sessions may be the
perfect solution to this problem. If you set the cookieless attribute of the sessionState
element to "true" in your web.config, you will notice that sessions
still work perfectly when invoking your Web methods using the browser
interface. Unfortunately, there are still issues if you use the "Add
Web Reference" capabilities within Visual Studio .NET.
To investigate cookieless sessions, I decided to take the client
code I used above and simply see if it would work for a Web service
that was configured for cookieless sessions. I did not bother to delete
the cookie container code, because I wanted to have code that would
work with traditional cookied sessions as well as cookieless sessions.
Being a bit of an optimist, I simply ran the code as is.
Disappointingly, but not completely unexpectedly, I witnessed the
following exception:
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>
What happened is that the HTTP request received a response that was
not a "200 OK" HTTP response. For those of you familiar with HTTP, you
probably can correlate the HTML listed in the response shown as
indicating that this was a "302 Found" HTTP response. This means that
the request was redirected to the URL indicated in the hyperlink. The
HTML returned is actually just a nice thing that a browser can show if
for some reason it does not support redirects, or until the redirected
request completes. If you look at the hyperlink, you will notice that
the href includes an interesting substring of
"(l2z3psnhh2cf1oahmai44p21)". If you have been paying attention, you
have probably correctly deduced that this is the ASP.NET session ID,
and it has been embedded in the URL that we have been redirected to.
What we need is for our client proxy class to resend the request to
this new URL.
Having done more than my share of programming with the old Win32
WinInet API, I went looking for a property on our proxy class that
would allow me to turn on auto redirects. In layman''''s terms, this
simply means that if we received an HTTP response of "302 Found," we
would simply resend the request to the URL indicated by the HTTP
Location header in the response. I was feeling pretty smart when the
Microsoft® IntelliSense® in Visual Studio .NET showed me the AllowAutoRedirect property on my proxy class. I quickly added the following line to my code:
proxy.AllowAutoRedirect = True
I gave my program another try, thinking this was still slightly easier than creating a CookieContainer class, and assigning it to my proxy. I got the following exception (truncated for brevity):
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: …
If you looked at the contents of the error message, you would find
that you were looking at the HTML page that you see when you browse to
your .ASMX file. The question you might have is: Why it is returning
HTML when I am posting XML (in the form of a SOAP envelope) to the Web
service? As it turns out, you did not send an HTTP POST request with a
SOAP envelope, you simply sent an HTTP GET request with no body, and
your Web service appropriately assumed you were a browser and returned
its normal HTML response. How could this happen?
If you read the HTTP specification,
you will find that it is appropriate for an HTTP client to send an HTTP
GET request to the indicated URL in reaction to an HTTP "302 Found"
response, even if the initial request was an HTTP POST. This works
great with browsers, because just about all of their requests are HTTP
GET requests in the first place. It does not work well when you see
this result when you are posting data to a URL.
The justification for this is that potentially sensitive data may be
contained in the posted data, so you need to confirm with the user if
they really want to send the data to the new resource. If you are going
to the new location based off an auto-redirect setting, you are
obviously failing to confirm with the user whether it is okay to post
their data to a new location. Therefore the data is not sent, and a
simple HTTP GET request is sent instead.
I made the following modifications to set the URI on the proxy, catch the "302 Found" WebException,
prompt the user for permission to redirect their request, and call my
function again with the new location (changes from the previous code
are highlighted):
'''' Works with both cookied and cookieless ASP.NET sessions. 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 Dim proxy As New localhost.Service1() Dim ret As Integer '''' Set the Cookie Container on the proxy If Cookies Is Nothing Then Cookies = New System.Net.CookieContainer() End If proxy.CookieContainer = Cookies
'''' Set the Url on the proxy
If webServiceUrl Is Nothing Then
webServiceUrl = New Uri(proxy.Url)
Else
proxy.Url = webServiceUrl.AbsoluteUri
End If
上一页 [1] [2] [3] 下一页 [Web开发]详细介绍session的用法详解 [系统软件]Using dllimport and dllexport in C++ Classes [VB.NET程序]How to setup a basic Struts project using Ecli… [Web开发]Ajax using XMLHttpRequest and Struts [Web开发]参数传递解决window.open的session变量丢失 [Web开发]php实现多session并发运行 [Web开发]彻底放弃IIS让Apache也支持ASP.NET [Web开发]ASP.NET 2.0发送电子邮件中存在的问题 [Web开发]ASP.NET 2.0移动开发之属性重写和模板化 [Web开发]ASP.NET 2.0中实现模板中的数据绑定
|