Post XML to a web service - asp.net

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()

Related

How to send multiple files with Response. ASP.NET

I'm trying to call below code in a loop hundreds of times:
Sub ExportReport(ByVal en As MyReport)
Dim warnings As Warning() = Nothing
Dim streamids As String() = Nothing
Dim mimeType As String = Nothing
Dim encoding As String = Nothing
Dim extension As String = Nothing
Dim bytes As Byte()
bytes = aReport.ServerReport.Render("WORD", Nothing, mimeType, encoding, extension, streamids, warnings)
Response.Buffer = True
Response.Clear()
Response.ContentType = mimeType
Response.AddHeader("content-disposition", "attachment; filename=" & en.ToString() & "." + extension)
Response.BinaryWrite(bytes)
Response.Flush()
Response.End()
End Sub
And I'm getting this error :
Server cannot append header after HTTP headers have been sent.
How can I change the code so that I can loop this piece of code? Thanks.
EDIT :
I added this line after Response.End()
Response.Redirect(Request.Url.AbsoluteUri)
And I get this error :
Cannot redirect after HTTP headers have been sent.
WWW works on a request / response mechanism. For every request there is only 1 response. You cannot change that basic mechanism. When browser sends a request it is expecting one and only one response. So if it receives more than 1 response, it either issues a warning to the user to block this behaviour or may choose to ignore the extra responses by itself. Thus these extra responses may be lost.
Having said that you have 2 options with you:
Zip all the files that you want to download and download as a single file.
You can use Popular framework Ionic.Zip.
First, keep all your files in a local directory on the server.
Then use this library to zip the entire folder.
Pseudo code:
Imports (var zip = New Ionic.Zip.ZipFile())
{
zip.AddDirectory("DirectoryOnDisk", "rootInZipFile")
Response.Clear()
Response.AddHeader("Content-Disposition", "attachment; filename=DownloadedFile.zip")
Response.ContentType = "application/zip"
zip.Save(Response.OutputStream)
Response.End()
}
Add a mechanism to issue multiple request using Javascript to get multiple responses, so browser still treats this behaviour as normal.
A normal web page will have a load of (headers) stuff set up for you already, but you don't want any of that: you want complete control over what is sent to the browser. If you cause a redirect to something which sends the headers shown in code later here, the browser will (normally) download the data.
In the code-behind you can have something like
Protected Sub btn_click(ByVal sender As Object, ByVal e As EventArgs) Handles btn.Click
Response.Redirect("~/sendfile.ashx?ref=" & enReference, False)
Context.ApplicationInstance.CompleteRequest()
End Sub
You will also need to add a generic handler (right-click on the project in Solution Explorer, Add->New Item... -> Visual Basic--Web--General choose "Generic Handler"; give it a name like sendfile.ashx) which is somewhat like
Imports System.IO
Public Class sendfile
Implements System.Web.IHttpHandler, IReadOnlySessionState
Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim enReference = context.Request.QueryString("ref")
' do whatever is needed to get the report from enReference '
Dim bytes As Byte() = aReport.ServerReport.Render("WORD", Nothing, mimeType, encoding, extension, streamids, warnings)
Dim downloadName = yourfilename & "." & yourextension
context.Response.ContentType = "application/octet-stream"
context.Response.AddHeader("content-disposition", "attachment; filename=""" & downloadName & """" )
context.Response.BinaryWrite(bytes)
End Sub
ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class
and you will need to work out the code to create the data to be sent.
If you don't need to use session state then you can remove the , IReadOnlySessionState part on the Implements line.
You might need to add context.Response.Flush(). If you find that the response does not have a Content-Length header, then you ought to add one so that the browser can show a meaningful download progress.

How to manitain session values during HttpWebRequest?

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.

How to get the binding address from a WSDL file

I generated a proxy class given a URL to a WSDL.
I need to let the end-user change the service's URL to his specific URL, like this:
ServiceProxy.Url = [URL set by end-user];
The issue is that this URL should not point to the WSDL, it should be the binding address which is found within the WSDL (wsdl:service -> wsdl:port -> wsdl:address) (this is a SAP web service, I understand that is why I must use the binding address).
I am thinking of using the XDocument class to get that value, but I am wondering if there is any "built-in" functionality in WCF or web services to get the binding address. Thank you.
I did a small function in VB.NET (sorry!) based on code at Parse Complex WSDL Parameter Information . Hope it helps.
Public Function GetURLFromWSDL(ByVal wsdl As String) As String
Dim request As HttpWebRequest = WebRequest.Create(wsdl)
request.ContentType = "text/xml;charset=""utf-8"""
request.Method = "GET"
request.Accept = "text/xml"
Using response As WebResponse = request.GetResponse()
Using stream As Stream = response.GetResponseStream()
Dim service As ServiceDescription = ServiceDescription.Read(stream)
Dim binding As SoapAddressBinding = service.Services(0).Ports(0).Extensions(0)
Return binding.Location
End Using
End Using
End Function

Upload files asynchronously with ASP.NET

I'm trying to make an asynchronous upload operation but I got this error message:
Error occurred, info=An exception
occurred during a WebClient request`.
Here's the upload function:
Private Sub UploadFile()
Dim uploads As HttpFileCollection
uploads = HttpContext.Current.Request.Files
Dim uri As Uri = New Uri("C:\UploadedUserFiles\")
Dim client = New WebClient
AddHandler client.UploadFileCompleted, AddressOf UploadFile_OnCompleted
For i As Integer = 0 To (uploads.Count - 1)
If (uploads(i).ContentLength > 0) Then
Dim c As String = System.IO.Path.GetFileName(uploads(i).FileName)
Try
client.UploadFileAsync(uri, c)
Catch Exp As Exception
End Try
End If
Next i
End Sub
Public Sub UploadFile_OnCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.AsyncCompletedEventArgs)
Dim client As WebClient = CType(e.UserState, WebClient)
If (e.Cancelled) Then
labMessage.Text = "upload files was cancelled"
End If
If Not (e.Error Is Nothing) Then
labMessage.Text = "Error occured, info=" + e.Error.Message
Else
labMessage.Text = "File uploaded successfully"
End If
End Sub
Update 1:
Private Sub UploadFile()
Dim uploads As HttpFileCollection
Dim fileToUpload = "C:\Demo\dummy.doc"
Dim uri As Uri = New Uri("C:\UploadedUserFiles\")
Dim client = New WebClient
AddHandler client.UploadFileCompleted, AddressOf UploadFile_OnCompleted
client.UploadFileAsync(uri, fileToUpload)
End Sub
client.UploadFileAsync(uri, fileToUpload) is throwing this error message
Error occured, info=System.Net.WebException: The request was aborted: The request was canceled. at System.Net.FileWebRequest.EndGetResponse(IAsyncResult asyncResult) at System.Net.WebClient.GetWebResponse(WebRequest request, IAsyncResult result) at System.Net.WebClient.DownloadBitsResponseCallback(IAsyncResult result)
By calling GetFileName you're truncating whatever path information was there. You should provide UploadFileAsync with a full path name.
Also, replace e.Error.Message with just e.Error so you get the full error details including inner exceptions. This will provide more info and probably lead you to the answer.
Dim uri As Uri = New Uri("C:\UploadedUserFiles\")
The above statement is wrong, how come you have Uri as a file system path, it should be "http://" or "https://" , if you are trying to upload it to your local asp.net web site project then you must have a url something like http://localhost:PORT/UploadedUserFiles ... and you will know port number when you execute project.
Dim uri As Uri = New Uri("http://localhost:PORT/Upload.aspx")
Try this:
1) Create a new class MyWebClient.
Class MyWebClient
Inherits WebClient
Protected Overrides Function GetWebRequest(address As Uri) As WebRequest
Dim req = MyBase.GetWebRequest(address)
Dim httpReq = TryCast(req, HttpWebRequest)
If httpReq IsNot Nothing Then
httpReq.KeepAlive = False
End If
Return req
End Function
End Class
2) Use this class instead of the default WebRequest.
Private Sub UploadFile()
Dim uploads As HttpFileCollection
uploads = HttpContext.Current.Request.Files
Dim uri As Uri = New Uri("C:\UploadedUserFiles\")
Dim client = New MyWebClient
AddHandler ...
I hope this helps.
From the reference to HttpContext.Current.Request.Files I am assuming that your are running the code in a web project. You don't have to use WebClient to save the file to your disk. All you have to do is this:
Private Sub UploadFile()
Dim uploads As HttpFileCollection
uploads = HttpContext.Current.Request.Files
Dim path As String = "C:\UploadedUserFiles\"
For i As Integer = 0 To (uploads.Count - 1)
If (uploads(i).ContentLength > 0) Then
Dim p As String = System.IO.Path.Combine(path, System.IO.Path.GetFileName(uploads(i).FileName))
uploads(i).SaveAs(p)
End If
Next i
End Sub
I'm not that good with VB.. so there might be syntax problems :) bear with me..
You can't upload files from the ASP.NET web request asyncronously via this mechanism. The file is actually in the body of the http request so it is already on the server. Request.Files provides a stream to the files that are already on the server.
You could use something like Silverlight or Flash from the client side.
You might want to investigate the AJAX Control Toolkit and use the AsyncFileUpload control.
The control has a server side event when upload is complete. (UploadedComplete)
It also has a SaveAs(string filename) method for the uploaded file.
Simple Usage:
Markup
<asp:AsyncFileUpload ID="upload" runat="server" OnUploadedComplete="displayFile"/>
Code Behind
protected void displayFile(object sender, AjaxControlToolkit.AsyncFileUploadEventArgs e)
{
upload.SaveAs("C:\\text.txt");//server needs permission
}
Try to add Header information to the WebClient Object as below :
With webClient
.Headers.Add("Content-Type", Web.MimeMapping.GetMimeMapping("C:\filename.txt"))
.Headers.Add("Keep-Alive", "true")
.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)")
.Credentials = New Net.NetworkCredential("UserName", "password")
End With

Send HTTP Command using VB.NET

I'm trying to send an HTTP command using VB.NET and I'm not quite sure how to do it. I don't want to actually navigate to the page, just execute the command.
http://xbmc.local/xbmcCmds/xbmcHttp?command=ExecBuiltIn&parameter=XBMC.updatelibrary%28video%29
What I'm doing is building an integrated interface for my XBMC home theater, and my home automation.
You can use the WebRequest object to send an HTTP Request.
' Create a WebRequest object with the specified url. '
Dim myWebRequest As WebRequest = WebRequest.Create(url)
' Send the WebRequest and wait for response. '
Dim myWebResponse As WebResponse = myWebRequest.GetResponse()
The WebResponse class has a number of properties you can check to see if the request succeeded or not. And just something to be aware of, GetResponse() will throw an exception if it times out.
Try the following
Dim client = WebRequest.Create("http://xbmc.local/xbmcCmds/xbmcHttp?command=ExecBuiltIn&parameter=XBMC.updatelibrary%28video%29")
Dim response = client.GetResponse()

Resources