How to manitain session values during HttpWebRequest? - asp.net

In my code I'm sending a HttpWebRequest to a page in my website.
When request sends to this page, It doesn't maintain the Session values.
Below is the code, from where I'm generating the web request:
Public Overloads Shared Function ReadURL(ByVal sUrl As String) As String
Dim sBody As String
Dim oResponse As HttpWebResponse
Dim oRequest As HttpWebRequest
Dim oCookies As New CookieContainer
oRequest = WebRequest.Create("http://localhost:64802/inventory/purchase_order.aspx?id=5654")
oRequest.CookieContainer = oCookies
oResponse = oRequest.GetResponse()
Dim oReader As New StreamReader(oResponse.GetResponseStream())
sBody = oReader.ReadToEnd
oReader.Close()
oResponse.Close()
Return sBody
End Function
Below is the code written on Page_Load of Purchaseorder.aspx.vb:
iDomains_ID = Session("Domains_ID")
iLogin_ID = Session("Login_ID")
sPage = Request.Path
If Request.QueryString.Count > 0 Then sPage &= "?" & Request.QueryString.ToString()
sPage = shared01.Encrypt(sPage, Application("PK"))
If Not User.Identity.IsAuthenticated Or iLogin_ID = 0 Then
Response.Redirect("/login.aspx?page=" & sPage)
Exit Sub
End If
Above code doesn't gets the session values and it redirects to the login page.
So, how i can maintain the session on both pages during HttpWebRequest.
Looking for your replies.
EDIT
I've tried to use CookieContainer class as you can see in above code. But it doesn't work at all.

As an alternative, assuming the calling and called pages are in the same application, you could use the Server.Execute method to load the content of the page without making a separate request to the site:
Public Overloads Function ReadURL(ByVal sUrl As String) As String
Using writer As New StringWriter()
Server.Execute("~/inventory/purchase_order.aspx?id=5654", writer, False)
Return writer.ToString()
End Using
End Function

If I've understood you correctly, you're making a request from one page in your site to another, and you want to send the cookies from the current HttpRequest with your WebRequest?
In that case, you'll need to manually copy the cookies to the CookieContainer:
For Each key As String In Request.Cookies.AllKeys
Dim sourceCookie As HttpCookie = Request.Cookies(key)
Dim destCookie As New Cookie(sourceCookie.Name, sourceCookie.Value, sourceCookie.Path, "localhost")
destCookie.Expires = sourceCookie.Expires
destCookie.HttpOnly = sourceCookie.HttpOnly
destCookie.Secure = sourceCookie.Secure
oCookies.Add(destCookie)
Next
NB: You'll either need to make the ReadUrl function non-Shared, or pass the current HttpRequest as a parameter.
You'll also need to make sure the calling page has EnableSessionState="false" in the <%# Page ... %> directive, otherwise the page you're calling will hang trying to obtain the session lock.

Your code seems like you will need to make a request and a post. The first request will redirect you to your login page. The second will be a request where you post to the login page, which will start the session and (?) store information into the session variables. That post (to the login page) will then redirect you to the page you want.
I used code in this example http://www.codeproject.com/Articles/145122/Fetching-ASP-NET-authenticated-page-with-HTTPWebRe (I tweaked it a bit) to write an application to do this.

Related

WebClient.DownloadFile returns login page even when credentials are provided

I am trying to download a file that is behind a login page. I have looked into many ways to add credentials but the response is always the log in page's html. I have tried 2 passes with client.uploadValues or client.uploadstring to get a cookie and a single pass just providing credentials.
Public Sub downloadImage()
Dim username As String = "xxxxx"
Dim password As String = "xxxxx"
Using client As New WebClient()
client.Credentials = New NetworkCredential(username, password)
client.DownloadFile("https://retailerservices.domain.com/Image/ItemHighRes/26634/1", AppDomain.CurrentDomain.BaseDirectory & "test.jpg")
End Using
End Sub
Any recommendations?

.NET 4.0 FormsAuthentication.SetAuthCookie FAIL

I know there are a few questions out there on this already but none seem to help my problem.
I am debugging a VB.NET webForms app and I cannot Get FormsAuthentication.SetAuthCookie to work (with a non-persistent cookie). It seems to create an HttpContext.Current.User object when I check for it in a watch window it seems to have created the object, but not its "Identity" property.
I've read a bunch of SO posts checked the basic things, like seeing if my browser supports cookies, etc... This project is a direct port from an earlier project of ours, which uses the same code for all things listed here, and it works just fine, relatively speaking. Where this throws an exception is where it's called from my BLL code that is supposed to get it.
Here is the code that calls the FormsAuthentication method...:
'When participant logs in having already created records in DB.
Protected Sub btnGo_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles btnGo.Click
If Me.txtUsername.Text.Trim.Length <> 0 AndAlso Me.txtPassword.Text.Trim.Length <> 0 Then
If Membership.ValidateUser(Me.txtUsername.Text, Me.txtPassword.Text) Then
FormsAuthentication.SetAuthCookie(Me.txtUsername.Text, False)
'This is where we run into trouble; the property checks with the forms auth...
MyBLL.Common.CurrentUser = New MyBLL.User(Me.txtUsername.Text)
'set site property..
If Site_ IsNot Nothing Then
MyBLL.Common.CurrentUser.Site = Me.Site_
End If
MyBLL.Common.CurrentParticpant = Nothing
MyBLL.Common.CurrentParticpantVisitID = -1
Response.Redirect("~/Apps/Dashboard.aspx", True)
Else
Me.lblLoginMsg.Visible = True
End If
Else
Me.lblLoginMsg.Visible = True
End If
End Sub
Here is the code for the BLL object (which has a shared property calling user from HttpContext...)
Public Shared Property CurrentUser() As MyBLL.User
Get
Dim objUser As MyBLL.User
If Not IsNothing(HttpContext.Current.Session("currentSiteUser")) Then
objUser = CType(HttpContext.Current.Session("currentSiteUser"), MyBLL.User)
If objUser.Username <> HttpContext.Current.User.Identity.Name Then
objUser = New MyBLL.User(HttpContext.Current.User.Identity.Name)
HttpContext.Current.Session("currentSiteUser") = objUser
End If
Else
objUser = New MyBLL.User(HttpContext.Current.User.Identity.Name)
HttpContext.Current.Session("currentSiteUser") = objUser
End If
Return objUser
End Get
Set(ByVal value As MyBLL.User)
'_CurrentUser = value
HttpContext.Current.Session("currentSiteUser") = value
End Set
End Property
Here is the Forms element from my webConfig; everything seems alright here to me...
<authentication mode="Forms">
<forms loginUrl="~/Public/Default2.aspx" defaultUrl="~/Public/Default2.aspx" timeout="60"/>
</authentication>
You should immediately redirect after callaing the SetAuthCookie method and only on subsequent requests you may hope to get the full IPrincipal to be initialized. Do not try to access HttpContext.Current.User.Identity.Name in the same controller action in which you called the SetAuthCookie method. It won't have any effect. The redirect is important so that on the next request the forms authentication module will built the principal from the request cookie.
In your CurrentUser method you seem to be calling the HttpContext.Current.User.Identity.Name property but this is not available until you redirect.

jQuery/ASP.NET concurrent Ajax calls

I have a webpage where users can look for clients and select them. After selection they can be send to the webserver through an jQuery Ajax call. On the server database operations and another webservice is called, so this can take a while. That is why I wanted to present a progress bar to the user.
This progressbar is also updated by a Ajax call.
The problem seems to be that asp.net doesn't allow concurrent calls and the session state queues all calls. You can solve this in mvc by setteing the attribute [SessionState(SessionStateBehavior.ReadOnly)]
But I don't find to do this in my page-behind webmethods. Anyway, the worker method is using session state (for security, and updating the session variable for the progressbar).
The progress method is only reading and returning the session variable.
Is there a solution for it, or is another approach necessary?
I am using asp.net 4.
You could set the session mode to readonly at the #Page directive in your markup:
<%# Page Title="Home Page" EnableSessionState="ReadOnly" Language="C#" %>
I have found the solution:
1) The WebMethod only needs to receive the data and start a new thread:
<WebMethod()> _
Public Shared Function importContacts(ByVal contactGuids As String, ByVal campaignGuids As String) As String
Dim paramsList As New List(Of Object)
paramsList.Add(contactGuids)
paramsList.Add(campaignGuids)
paramsList.Add(HttpContext.Current.Session)
Dim th As New Threading.Thread(AddressOf processImport)
th.Start(paramsList)
Return ""
End Function
The Ajax call is ended quickly and on the browser you can start polling for progress.
2) The thread function needs to convert the parameters first, then you can use the session state:
Public Shared Sub processImport(params As Object)
Dim paramsList As List(Of Object) = params
Dim contactGuids As String = paramsList(0)
Dim campaignGuids As String = paramsList(1)
Dim _session As HttpSessionState = paramsList(2)
_session("EmailMarketingDatabase_progress") = 0
...
End Sub
3) The progress WebMethod looks like this:
<WebMethod()> _
Public Shared Function getProgressStatus() As Integer
Return HttpContext.Current.Session("EmailMarketingDatabase_progress")
End Function

Session state lost after HttpWebRequest within AJAX post

I have a bit of strange behaviour in an asp.net web application that involves the session state being lost.
Process
A user logs into the application and the session is set. They then fill out 1 field, and the application then does an AJAX POST to a .asmx web service. Within the web service, I am using a HttpWebRequest to grab data from another server.
This data is then output to the browser.
A few more fields are then filled in, and the data is then again Post to the same web service via an AJAX POST.
Problem
Straight after the HttpWebRequest, I grab the username from a session variable. This works.
On the next AJAX request however, the session no longer exists.
While testing this, I removed the stage at which the HttpWebRequest is called and my session is never lost. So for some reason, the session is removed AFTER my first AJAX POST and before the second AJAX POST only if I am running the HttpWebRequest code.
Code
I am not doing anything fancy in the code. Just doing a simple jQuery AJAX Post
$.ajax({
url: method,
data: params,
type: "POST",
contentType: "application/json; charset=utf-8", dataType: "json",
success: function (data) {
// handle data
},
error: function(xhr,status,error) { }
});
Creating a System.Net.HttpWebRequest and then getting the System.Net.HttpWebResponse out of that.
Then reading a session variable dim username as string = Session(_SESSION_USERNAME).ToString()
I have never noticed this behaviour before when using HttpWebRequest before (not using any AJAX though)
Function Backfill(value As String) As Details
Dim details As Details = Nothing
Dim appSettings As ConfigSettings.AppConfig = ConfigSettings.AppConfig.getConfig()
Dim url As String = appSettings.Settings.BackfillUrl
Dim username As String = appSettings.Settings.BackfillUser
Dim password As String = appSettings.Settings.BackfillPass
Dim expParameters As String = ""
Dim xml As XmlDocument = Nothing
Dim xmlHttp As XMLHTTP = Nothing
Dim nodeList As XmlNodeList = Nothing
Dim node As XmlNode = Nothing
Dim response As String = ""
Dim success As String = ""
'
' REMOVED TO HIDE INFO
expParameters = "<PARAMETERS>" & _
"</PARAMETERS>"
Try
xmlHttp = New XMLHTTP()
xmlHttp.open("POST", url)
xmlHttp.Send(expParameters)
response = xmlHttp.responseText()
xml = New XmlDocument
xml.LoadXml(response)
SaveExperianFile(xml, value)
nodeList = xml.DocumentElement.ChildNodes
node = nodeList.Item(0)
success = node.Attributes.GetNamedItem("success").Value.ToString.Trim
If success.ToLower.Trim = "y" Then
details = SetDetails(xml)
End If
Catch ex As Exception
Finally
If Not xmlHttp Is Nothing Then
xmlHttp.Dispose()
xmlHttp = Nothing
End If
End Try
Return details
End Function
edit
The XMLHTTP Class code can be seen here http://codepaste.net/ymnqsf
edit
Seems as though something strange is happening when I am saving the XMLDocument to my file system.
Private Sub SaveExperianFile(xml As XmlDocument, value As String)
Dim appConfig As ConfigSettings.AppConfig = ConfigSettings.AppConfig.getConfig()
Try
xml.Save(HttpContext.Current.Server.MapPath(appConfig.Settings.SavePath & value & "_backfill.xml"))
Catch ex As Exception
End Try
End Sub
If I don't call this method, then the session is always set.
Question
Do you know what is causing this behaviour?
Can you check if you just loose the session or the whole application is restarted. If you are saving the XML in the virtual directory / web application folder then it might case web application to restart. If many dozen files were added in short succession to each other, that would be a case to restart the App Pool.
just a hunch, but maybe you need to maintain cookies across HttpWebRequests.
have a look at this question for more help.
Http web request doesn't maintaining session

Post XML to a web service

I have a web service, which accepts XML input. What I am trying to do is setup an aspx page which posts xml to the service. Here is my code so far, but I am getting an error 400 (bad request) when I try to submit...
Imports System.Net
Imports System.IO
Partial Class _Default
Inherits System.Web.UI.Page
Protected Sub Submit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Submit.Click
Dim strDataToPost As String
Dim myWebRequest As WebRequest
Dim myRequestStream As Stream
Dim myStreamWriter As StreamWriter
Dim myWebResponse As WebResponse
Dim myResponseStream As Stream
Dim myStreamReader As StreamReader
' Create a new WebRequest which targets the web service method
myWebRequest = WebRequest.Create("http://foo/p09SoapHttpPort")
' Data to send
strDataToPost = DataToSend.Text & Server.UrlEncode(Now())
' Set the method and content type
With myWebRequest
.Method = "POST"
.ContentType = "text/xml"
.Timeout = -1
.ContentLength = strDataToPost.Length()
End With
' write our data to the Stream using the StreamWriter.
myRequestStream = myWebRequest.GetRequestStream()
myStreamWriter = New StreamWriter(myRequestStream)
myStreamWriter.Write(strDataToPost)
myStreamWriter.Flush()
myStreamWriter.Close()
myRequestStream.Close()
' Get the response from the remote server.
myWebResponse = myWebRequest.GetResponse()
' Get the server's response status
myResponseStream = myWebResponse.GetResponseStream()
myStreamReader = New StreamReader(myResponseStream)
ResponseLabel.Text = myStreamReader.ReadToEnd()
myStreamReader.Close()
myResponseStream.Close()
' Close the WebResponse
myWebResponse.Close()
End Sub
End Class
If anyone knows of any good web resources on how to upload .xml files to a web service method that would also be a great help and would answer this question as I can re-work it that way.
Thanks.
P.S in the last edit, I modified the code to have .contentlength (thanks for the assistance). Unfortunately after this I am still getting 'Bad Request'. If anyone can confirm / disconfirm my code should be working, I will start investigating the service itself.
The data you're trying to post might look a little funny if you're concatenating a time string to it:
strDataToPost = DataToSend.Text & Server.UrlEncode(Now())
If DataToSend is proper XML, then you're adding the Url Encoding of Now() which makes me think it will no longer be valid XML.
Check to make sure your StreamWriter is not inserting additional characters (CR, LF). If it does, then the length you're sending does not correspond to the actual data, but that probably wouldn't have caused a problem before you started sending the content length.
Is your web service configuration to accept XML directly? I'm wondering if you might have to encapsulate the XML in multipart/form-data in order for your web service to accept it.
I'm not a web service expert, but I compared your code to some working code I have, and the only relevant difference is that you are not setting the ContentLength of your request.
myWebRequest.ContentLength = strDataToPost.Length()

Resources