• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1033
  • Last Modified:

VB.net - uploading a file to a web site

Based on the process outlined here, http://www.codeproject.com/Articles/28917/Setting-a-file-to-upload-inside-the-WebBrowser-com, I'm looking for help incorporating this into my vb.net project.
0
sirbounty
Asked:
sirbounty
  • 80
  • 48
6 Solutions
 
Bob LearnedCommented:
Let's start by converting to VB.NET:

private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            HtmlDocument doc = webBrowser1.Document;
            for (int i = 0; i < doc.Forms.Count; i++)
            {
                HtmlElement form = doc.Forms[i]; // must be declared inside the loop because there's a closure
                if (form.GetAttribute("enctype").ToLower() != "multipart/form-data") { continue; }
                
                form.AttachEventHandler("onsubmit", delegate(object o, EventArgs arg)
                    {
                        FormToMultipartPostData postData = new FormToMultipartPostData(webBrowser1, form);
                        postData.SetFile("file", @"C:\windows\win.ini");
                        postData.Submit();
                    });
                form.SetAttribute("hasBrowserHandler", "1"); // expose that we have a handler to JS
            }
        }

Open in new window

0
 
Bob LearnedCommented:
VB.NET:

Private Sub webBrowser1_DocumentCompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs) Handles webBrowser1.DocumentCompleted
	Dim doc As HtmlDocument = webBrowser1.Document
	For Each form As HtmlElement In doc.Forms
		' must be declared inside the loop because there's a closure
		If form.GetAttribute("enctype").ToLower() <> "multipart/form-data" Then
			Continue For
		End If

		form.AttachEventHandler("onsubmit", Sub(o As Object, arg As EventArgs) 
		Dim postData As New FormToMultipartPostData(webBrowser1, form)
		postData.SetFile("file", "C:\windows\win.ini")
		postData.Submit()

			' expose that we have a handler to JS
		form.SetAttribute("hasBrowserHandler", "1")
	Next form
End Sub

Open in new window

0
 
Bob LearnedCommented:
FormToMultipartPostData.cs:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.IO;


namespace FormToMultipartPostData
{
    /**
     * 
     * This is a helper class to build postData header an body with the values from 
     * the given HTML form. The purpose of this class is to attach files to 
     * the <INPUT TYPE="FILE"> fields.
     * 
     * License: Code Project Open License (CPOL)
     * (c) Kirill Hryapin, 2008
     * (c) Steven Cheng (Microsoft), 2005 (?)
     * 
     * See usage example in Form1.cs included with this distribution.
     * 
     */

    public class FormToMultipartPostData
    {
        private struct ValuePair // KeyValuePair<string, string> sounds too verbose for me
        {
            public string name;
            public string value;
            public ValuePair(string name, string value)
            {
                this.name = name;
                this.value = value;
            }
        }

        public struct RequestParameters
        {
            public byte[] data;
            public string headers;
        }

        private List<ValuePair> values = new List<ValuePair>();
        private List<ValuePair> files = new List<ValuePair>();
        private Dictionary<string, string> overloadedFiles = new Dictionary<string,string>();

        private HtmlElement form;
        private WebBrowser webbrowser;

        /**
         * In most circumstances, this constructor is better (allows to use Submit() method)
         */
        public FormToMultipartPostData(WebBrowser b, HtmlElement f)
        {
            form = f; webbrowser = b;
            GetValuesFromForm(f);
        }

        /**
         * Use this constructor if you don't want to use Submit() method
         */
        public FormToMultipartPostData(HtmlElement f)
        {
            GetValuesFromForm(f);
        }

        /**
         * Submit the form
         */
        public void Submit()
        {
            Uri url = new Uri(webbrowser.Url, form.GetAttribute("action"));
            RequestParameters req = GetEncodedPostData();
            webbrowser.Navigate(url, form.GetAttribute("target"), req.data, req.headers);
        }

        /**
         * Load values from form
         */
        private void GetValuesFromForm(HtmlElement form)
        {
            // Get values from the form
            foreach (HtmlElement child in form.All)
            {
                switch (child.TagName)
                {
                    case "INPUT":
                        switch (child.GetAttribute("type").ToUpper())
                        {
                            case "FILE":
                                AddFile(child.Name, child.GetAttribute("value"));
                                break;
                            case "CHECKBOX":
                            case "RADIO":
                                if (child.GetAttribute("checked") == "True")
                                {
                                    AddValue(child.Name, child.GetAttribute("value"));
                                }
                                break;
                            case "BUTTON":
                            case "IMAGE":
                            case "RESET":
                                break; // Ignore those?
                            default:
                                AddValue(child.Name, child.GetAttribute("value"));
                                break;
                        }
                        break;
                    case "TEXTAREA":
                    case "SELECT": // it's legal in IE to use .value with select (at least in IE versions 3 to 7)
                        AddValue(child.Name, child.GetAttribute("value"));
                        break;
                } // of "switch tagName"
            } // of "foreach form child"
        }

        private void AddValue(string name, string value)
        {
            if (name == "") return; // e.g. unnamed buttons
            values.Add(new ValuePair(name, value));
        }

        private void AddFile(string name, string value)
        {
            if (name == "") return;
            files.Add(new ValuePair(name, value));
        }

        /**
         * Set file field value [the reason why this class exist]
         */
        public void SetFile(string fieldName, string filePath)
        {
            this.overloadedFiles.Add(fieldName, filePath);
        }

        /**
         * One may need it to know whether there's specific file input
         * For example, to perform some actions (think format conversion) before uploading
         */
        public bool HasFileField(string fieldName)
        {
            foreach (ValuePair v in files) {
                if (v.name == fieldName) { return true; }
            }
            return false;
        }

        /**
         * Encode parameters 
         * Based on the code by Steven Cheng, http://bytes.com/forum/thread268661.html
         */
        public RequestParameters GetEncodedPostData()
        {
            string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");

            Stream memStream = new System.IO.MemoryStream();
            byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

            string formdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";
            foreach (ValuePair v in values)
            {
                string formitem = string.Format(formdataTemplate, v.name, v.value);
                byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
                memStream.Write(formitembytes, 0, formitembytes.Length);
            }
            memStream.Write(boundarybytes, 0, boundarybytes.Length);

            string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n";

            foreach (ValuePair v in files)
            {
                string filePath;

                if (overloadedFiles.ContainsKey(v.name))
                {
                    filePath = overloadedFiles[v.name];
                }
                else
                {
                    if (v.value.Length == 0) { continue; } // no file
                    filePath = v.value;
                }

                try // file can be absent or not readable
                { 
                    FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);

                    string header = string.Format(headerTemplate, v.name, filePath);
                    byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
                    memStream.Write(headerbytes, 0, headerbytes.Length);

                    byte[] buffer = new byte[1024];
                    int bytesRead = 0;
                    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                    {
                        memStream.Write(buffer, 0, bytesRead);
                    }

                    memStream.Write(boundarybytes, 0, boundarybytes.Length);
                    fileStream.Close();
                }
                catch (Exception x) // no file?..
                {
                    MessageBox.Show(x.Message, "Cannot upload the file", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
            }

            RequestParameters result = new RequestParameters();

            memStream.Position = 0;
            result.data = new byte[memStream.Length];
            memStream.Read(result.data, 0, result.data.Length);
            memStream.Close();

            result.headers = "Content-Type: multipart/form-data; boundary=" + boundary + "\r\n" +
                             "Content-Length: " + result.data.Length + "\r\n" +
                             "\r\n";

            return result;
        }
    }
}

Open in new window

0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
Bob LearnedCommented:
VB.NET:

Imports System.Collections.Generic
Imports System.Text
Imports System.Windows.Forms
Imports System.IO


Namespace FormToMultipartPostData
	'*
'     * 
'     * This is a helper class to build postData header an body with the values from 
'     * the given HTML form. The purpose of this class is to attach files to 
'     * the <INPUT TYPE="FILE"> fields.
'     * 
'     * License: Code Project Open License (CPOL)
'     * (c) Kirill Hryapin, 2008
'     * (c) Steven Cheng (Microsoft), 2005 (?)
'     * 
'     * See usage example in Form1.cs included with this distribution.
'     * 
'     


	Public Class FormToMultipartPostData
		Private Structure ValuePair
			' KeyValuePair<string, string> sounds too verbose for me
			Public name As String
			Public value As String
			Public Sub New(name As String, value As String)
				Me.name = name
				Me.value = value
			End Sub
		End Structure

		Public Structure RequestParameters
			Public data As Byte()
			Public headers As String
		End Structure

		Private values As New List(Of ValuePair)()
		Private files As New List(Of ValuePair)()
		Private overloadedFiles As New Dictionary(Of String, String)()

		Private form As HtmlElement
		Private webbrowser As WebBrowser

		'*
'         * In most circumstances, this constructor is better (allows to use Submit() method)
'         

		Public Sub New(b As WebBrowser, f As HtmlElement)
			form = f
			webbrowser = b
			GetValuesFromForm(f)
		End Sub

		'*
'         * Use this constructor if you don't want to use Submit() method
'         

		Public Sub New(f As HtmlElement)
			GetValuesFromForm(f)
		End Sub

		'*
'         * Submit the form
'         

		Public Sub Submit()
			Dim url As New Uri(webbrowser.Url, form.GetAttribute("action"))
			Dim req As RequestParameters = GetEncodedPostData()
			webbrowser.Navigate(url, form.GetAttribute("target"), req.data, req.headers)
		End Sub

		'*
'         * Load values from form
'         

		Private Sub GetValuesFromForm(form As HtmlElement)
			' Get values from the form
			For Each child As HtmlElement In form.All
				Select Case child.TagName
					Case "INPUT"
						Select Case child.GetAttribute("type").ToUpper()
							Case "FILE"
								AddFile(child.Name, child.GetAttribute("value"))
								Exit Select
							Case "CHECKBOX", "RADIO"
								If child.GetAttribute("checked") = "True" Then
									AddValue(child.Name, child.GetAttribute("value"))
								End If
								Exit Select
							Case "BUTTON", "IMAGE", "RESET"
								Exit Select
							Case Else
								' Ignore those?
								AddValue(child.Name, child.GetAttribute("value"))
								Exit Select
						End Select
						Exit Select
					Case "TEXTAREA", "SELECT"
						' it's legal in IE to use .value with select (at least in IE versions 3 to 7)
						AddValue(child.Name, child.GetAttribute("value"))
						Exit Select
					' of "switch tagName"
				End Select
			Next
			' of "foreach form child"
		End Sub

		Private Sub AddValue(name As String, value As String)
			If name = "" Then
				Return
			End If
			' e.g. unnamed buttons
			values.Add(New ValuePair(name, value))
		End Sub

		Private Sub AddFile(name As String, value As String)
			If name = "" Then
				Return
			End If
			files.Add(New ValuePair(name, value))
		End Sub

		'*
'         * Set file field value [the reason why this class exist]
'         

		Public Sub SetFile(fieldName As String, filePath As String)
			Me.overloadedFiles.Add(fieldName, filePath)
		End Sub

		'*
'         * One may need it to know whether there's specific file input
'         * For example, to perform some actions (think format conversion) before uploading
'         

		Public Function HasFileField(fieldName As String) As Boolean
			For Each v As ValuePair In files
				If v.name = fieldName Then
					Return True
				End If
			Next
			Return False
		End Function

		'*
'         * Encode parameters 
'         * Based on the code by Steven Cheng, http://bytes.com/forum/thread268661.html
'         

		Public Function GetEncodedPostData() As RequestParameters
			Dim boundary As String = "----------------------------" + DateTime.Now.Ticks.ToString("x")

			Dim memStream As Stream = New System.IO.MemoryStream()
			Dim boundarybytes As Byte() = System.Text.Encoding.ASCII.GetBytes((Convert.ToString(vbCr & vbLf & "--") & boundary) + vbCr & vbLf)

			Dim formdataTemplate As String = (Convert.ToString(vbCr & vbLf & "--") & boundary) + vbCr & vbLf & "Content-Disposition: form-data; name=""{0}"";" & vbCr & vbLf & vbCr & vbLf & "{1}"
			For Each v As ValuePair In values
				Dim formitem As String = String.Format(formdataTemplate, v.name, v.value)
				Dim formitembytes As Byte() = System.Text.Encoding.UTF8.GetBytes(formitem)
				memStream.Write(formitembytes, 0, formitembytes.Length)
			Next
			memStream.Write(boundarybytes, 0, boundarybytes.Length)

			Dim headerTemplate As String = "Content-Disposition: form-data; name=""{0}""; filename=""{1}""" & vbCr & vbLf & "Content-Type: application/octet-stream" & vbCr & vbLf & vbCr & vbLf

			For Each v As ValuePair In files
				Dim filePath As String

				If overloadedFiles.ContainsKey(v.name) Then
					filePath = overloadedFiles(v.name)
				Else
					If v.value.Length = 0 Then
						Continue For
					End If
					' no file
					filePath = v.value
				End If

				Try
					' file can be absent or not readable
					Dim fileStream As New FileStream(filePath, FileMode.Open, FileAccess.Read)

					Dim header As String = String.Format(headerTemplate, v.name, filePath)
					Dim headerbytes As Byte() = System.Text.Encoding.UTF8.GetBytes(header)
					memStream.Write(headerbytes, 0, headerbytes.Length)

					Dim buffer As Byte() = New Byte(1023) {}
					Dim bytesRead As Integer = 0
					While (InlineAssignHelper(bytesRead, fileStream.Read(buffer, 0, buffer.Length))) <> 0
						memStream.Write(buffer, 0, bytesRead)
					End While

					memStream.Write(boundarybytes, 0, boundarybytes.Length)
					fileStream.Close()
				Catch x As Exception
					' no file?..
					MessageBox.Show(x.Message, "Cannot upload the file", MessageBoxButtons.OK, MessageBoxIcon.Warning)
				End Try
			Next

			Dim result As New RequestParameters()

			memStream.Position = 0
			result.data = New Byte(memStream.Length - 1) {}
			memStream.Read(result.data, 0, result.data.Length)
			memStream.Close()

			result.headers = (Convert.ToString("Content-Type: multipart/form-data; boundary=") & boundary) + vbCr & vbLf + "Content-Length: " + result.data.Length + vbCr & vbLf + vbCr & vbLf

			Return result
		End Function

		Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
			target = value
			Return value
		End Function
	End Class
End Namespace

Open in new window

0
 
sirbountyAuthor Commented:
It's the class where I got stuck - even after converting it... :(
0
 
sirbountyAuthor Commented:
Ah, but your version looks much better...
0
 
Bob LearnedCommented:
My code converter of choice:

http://converter.telerik.com/
0
 
sirbountyAuthor Commented:
Code fix recommended:
Dim postData As New FormToMultipartPostData (WebBrowser1, form)
to
Dim postData As New FormToMultipartPostData.FormToMultipartPostData(WebBrowser1, form)
0
 
sirbountyAuthor Commented:
Yep, I use the same converter (I think you showed me that one a few years ago ;^)
0
 
Bob LearnedCommented:
To simplify your code, you should remove the Namespace FormToMultipartPostData...End Namespace lines.  C# code had namespace, but it is not needed in VB.NET.
0
 
sirbountyAuthor Commented:
Ok, as-is, it doesn't seem to be applying the file path.  Fortunately with the appliance it will always be the same file.
(removing the namespace corrected the problem from above).

Since I don't quite understand the code, I'm not sure what I should be looking for.  Could it be that the SetFile method is looking for "file" and it's actually labeled something different on the page?  Or am I looking in the wrong direction?
0
 
sirbountyAuthor Commented:
Not sure if this is needed/relevant, but this is what I find in the page source for that browse section:

<input type="file" 
id="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload" 
name="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload" 
size="40" 
class="formField" />


<tbody><tr><td>
<a href="#" onclick="return oamSubmitForm('zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm','zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:downloadMsgLockConfig');" id="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:downloadMsgLockConfig">Download current configuration</a>
</td><td>

Open in new window

0
 
Bob LearnedCommented:
What does the <form> element look like?
0
 
sirbountyAuthor Commented:
What do you need from it?
Shows a Document: {System.Windows.Forms.HtmlDocument}
DomElement: {[object]}
Several "Event" options - all objects as well...
Have an ID, which appears to be the same as above, an inner-html & text, as well as outer of the same.
0
 
sirbountyAuthor Commented:
Wait - at this point, I haven't sent a click to the Browse button - I'm thinking I should do that first and then proceed with the above?  
I'll try that now...
0
 
sirbountyAuthor Commented:
Nope - that just 'leaves' it at the "Choose File to Upload" dialogue box...
0
 
sirbountyAuthor Commented:
I'm wondering if the problem is that the box where the file name ends up, is greyed out - and you cannot type in it - you must choose the browse button to upload.
Still possible with this code?
0
 
Bob LearnedCommented:
There is a problem with the VB.NET conversion here:

form.AttachEventHandler("onsubmit", delegate(object o, EventArgs arg)
{
     FormToMultipartPostData postData = new FormToMultipartPostData(webBrowser1, form);
     postData.SetFile("file", @"C:\windows\win.ini");
     postData.Submit();
});

The delegate function is known as an anonymous function.  It attaches new code to the onsubmit event handler.
0
 
Bob LearnedCommented:
Try this:

form.AttachEventHandler("onsubmit", AddressOf OnSubmit) 

...

Private Sub OnSubmit(ByVal sender As Object, ByVal e As EventArgs)
        Dim postData As New FormToMultipartPostData(webBrowser1, form)
	postData.SetFile("file", "C:\windows\win.ini")
	postData.Submit()
End Sub

Open in new window

0
 
Bob LearnedCommented:
"What does the <form> element look like?"
I need to see the <form> element in the HTML, not from your code.

Like this:
<form action="demo_form.asp" method="get">
0
 
sirbountyAuthor Commented:
I don't see a form action...
<form id="zdmSummaryDetailsSubview:relContentViewpc1:zdmTabsForm2" name="zdmSummaryDetailsSubview:relContentViewpc1:zdmTabsForm2" method="post" action="/console/services/zdm/index.jsf" enctype="application/x-www-form-urlencoded"><table border="0" cellpadding="0" cellspacing="0" width="100%" class="wizardButtonBox"><tbody><tr><td></td></tr></tbody></table><input type="hidden" name="zdmSummaryDetailsSubview:relContentViewpc1:zdmTabsForm2_SUBMIT" value="1" /><input type="hidden" name="javax.faces.ViewState" value="rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAN0AAFhcHQAFy9zZXJ2aWNlcy96ZG0vaW5kZXguanNw" /></form>

Open in new window


Should
form.AttachEventHandler("onsubmit", AddressOf OnSubmit)
be
form.AttachEventHandler("oamSubmitForm", AddressOf OnSubmit) ? ( see prior post)
0
 
sirbountyAuthor Commented:
Do I need to publicly declare 'form' for OnSubmit to use?  Or pass it as an argument somehow?
0
 
sirbountyAuthor Commented:
As-is, it's not hitting the onsubmit sub...

Here's my current documentcompleted sub:
Private Sub WebBrowser1_DocumentCompleted(sender As Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
        If e.Url.AbsolutePath.ToLower.Contains("login") Then Exit Sub
        If ServiceTabClicked Then
            If ZDMConfigTabClicked Then
'                Dim browseButton As mshtml.HTMLInputElement = helper.GetHtmlElementById(Of mshtml.HTMLInputElement)("zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload")
'                browseButton.click()
                Dim doc As HtmlDocument = WebBrowser1.Document
                For i As Integer = 0 To doc.Forms.Count - 1
                    Form = doc.Forms(i)
                    If form.GetAttribute("enctype").ToLower() <> "multipart/form-data" Then Continue For
                    form.AttachEventHandler("onsubmit", AddressOf OnSubmit)
                    form.SetAttribute("hasBrowserHandler", "1")
                Next
            Else
                Dim zdmCfgTab As mshtml.HTMLInputElement = helper.GetHtmlElementById(Of mshtml.HTMLInputElement)("zdmSummaryDetailsSubview:relContentViewpc1:configZDMTabbedPane.2") '"zdmSummaryDetailsSubview:relContentViewpc1:zdmTabsForm:bcServiceZDM")
                '"zdmSummaryDetailsSubview:relContentViewpc1:configZDMTabbedPane.2"
                zdmCfgTab.click()
                ZDMConfigTabClicked = True
            End If
        Else
            VSite.Path = "console/services/zdm/index.jsf"
            WebBrowser1.Navigate(VSite.Uri.ToString)
            ServiceTabClicked = True
        End If
    End Sub

Open in new window

0
 
sirbountyAuthor Commented:
Don't know if this helps, but before the upload this is what I see for the 'file':
<input type="file" id="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload" name="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload" size="40" class="formField" />

Open in new window

After:
<INPUT id=zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload
 class=formField 
  value="\\SERVER\PATH\FILE.CSV" 
  size=40 
  type=file 
name=zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload>

Open in new window

0
 
Bob LearnedCommented:
Form element:

<form id="zdmSummaryDetailsSubview:relContentViewpc1:zdmTabsForm2" name="zdmSummaryDetailsSubview:relContentViewpc1:zdmTabsForm2" method="post" action="/console/services/zdm/index.jsf" enctype="application/x-www-form-urlencoded"

There is a call to GetValuesFromForm, which looks at all the children for the form element.  If it finds an <input> element with type="file", it adds to the "files" collection.

Private files As New List(Of ValuePair)()

...

Private Sub GetValuesFromForm(form As HtmlElement)

Open in new window


On submit, there is a call to the Submit method, where it gets the "action" attribute from the <form> element:

                Public Sub Submit()
			Dim url As New Uri(webbrowser.Url, form.GetAttribute("action"))
			Dim req As RequestParameters = GetEncodedPostData()
			webbrowser.Navigate(url, form.GetAttribute("target"), req.data, req.headers)
		End Sub

Open in new window


It then makes a call to the overloaded WebBrowser.Navigate, passing in the "target" frame attribute.  

Here is the signature:

WebBrowser.Navigate Method (Uri, String, Byte(), String)
http://msdn.microsoft.com/en-us/library/ms161356(v=vs.110).aspx
0
 
sirbountyAuthor Commented:
Ok, that makes it a little bit clearer for me, thanks.
But (a) does that eliminate the need for me to locate the browse button and 'click' it?  and (b) I've tried it both ways and neither route seems to be doing anything.
0
 
Bob LearnedCommented:
Here is some help towards debugging (placing breakpoints), since I can't...

1) Attached an event handler to the OnSubmit event here.  That would mean that you need to have a submit action to fire the event.

form.AttachEventHandler("onsubmit", AddressOf OnSubmit)

It looks like a submit function is triggered here, but that is for "Download current configuration".  I don't see one for "Upload current configuration.

<a href="#" onclick="return oamSubmitForm('zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm','zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:downloadMsgLockConfig');" id="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:downloadMsgLockConfig">Download current configuration</a>

2) When the OnSubmit event is triggered, it should call the Submit method, which calls the WebBrowser.Navigate:

webbrowser.Navigate(url, form.GetAttribute("target"), req.data, req.headers)
0
 
sirbountyAuthor Commented:
Yes, there is a link to download the current config (it has never really worked when I tried it), but we just append to an existing external config file sitting on a share.

The way I'm interpretting this is that we've setup an event hanlder for when the page attempts to submit the file, but there doesn't seem to be a way to actually submit the file, or is that what clicking the browse button should trigger?  Because that seems to move away from the scope of the page and generate a popup dialogue that's no longer associated with the web page.  Should this event handler be able to manipulate that dialogue?

Could it be that the event handler is named incorrectly?
Is the "hasBrowserHandler" attribute still applicable (I'm not sure what the benefit is for that)?
I did try putting a breakpoint at OnSubmit, but it doesn't hit it.  I also adjusted the code to set the handler before clicking the browse button:
Dim browseButton As mshtml.HTMLInputElement = helper.GetHtmlElementById(Of mshtml.HTMLInputElement)("zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload")

Dim doc As HtmlDocument = WebBrowser1.Document
  For i As Integer = 0 To doc.Forms.Count - 1
    form = doc.Forms(i)
    If form.GetAttribute("enctype").ToLower() <> "multipart/form-data" Then Continue For
    form.AttachEventHandler("onsubmit", AddressOf OnSubmit)
    form.SetAttribute("hasBrowserHandler", "1")
  Next
  browseButton.click()
End If

Open in new window


I can attach the full page code if that would help.  I'm afriad I just don't know enough to know what else to look for (but I'm still trying - and learning! :^)
0
 
Bob LearnedCommented:
I just noticed something in the code that you posted:

If form.GetAttribute("enctype").ToLower() <> "multipart/form-data" Then Continue For

Open in new window


This means if the enctype attribute is not "multipart/form-data", then skip.

The form enctype is here:

enctype="application/x-www-form-urlencoded"
0
 
sirbountyAuthor Commented:
I had hopes, but no, still nothing.

Looking at the source, the only enctype before the browse button is showing multipart/form-data.  Is that not the relevant one?
<table width="920"><tbody><tr><td><form id="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm" name="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm" method="post" action="/console/services/zdm/index.jsf"
enctype="multipart/form-data"><div class="leftPaddedSection"><div class="form"><table border="0" cellspacing="2" width="100%"><tbody><tr><td class="formLabelNoWrap">Default Domain *</td><td class=""><input id="defaultDomain" name="defaultDomain" type="text" value="COMPANY.com" size="30" class="formField" /></td></tr><tr><td class="formLabelNoWrap">Message Format</td><td class=""><select id="msgFormat" name="msgFormat" size="1" class="formField">      <option value="V2">Version 2</option>      <option value="V3" selected="selected">Version 3</option></select></td></tr><tr><td class="formLabelNoWrap"><nobr>Session Timeout Period (minutes) *</nobr></td><td class="">
<input id="sessionTimeout" name="sessionTimeout" type="text" value="20" size="12" class="formField" /></td></tr><tr><td class="formLabelNoWrap">Identity Timeout Policy</td><td class=""><select id="identityTimeoutPolicy" name="identityTimeoutPolicy" size="1" class="formField" onchange="submit()">      <option value="OFF">Disabled</option>      <option value="NEVER">Enabled - Never Times Out</option>      <option value="TIMEOUT" selected="selected">Enabled - With Timeout Period</option></select></td></tr><tr><td class="formLabelNoWrap">Identity Timeout Period</td><td class=""><input id="identityTimeout" name="identityTimeout" type="text" value="12" size="12" class="formField" /> <select id="identityTimeoutUnit" name="identityTimeoutUnit" size="1" class="formField">      <option value="HOUR" selected="selected">Hour(s)</option>      <option value="DAY">Day(s)</option>      <option value="WEEK">Week(s)</option></select></td></tr><tr><td class="formLabelNoWrap"><span class="formLabelTop">Message Locking Configuration</span></td>
0
 
sirbountyAuthor Commented:
Thinking I may be misunderstanding (again)...should I be focusing on the Save button and making sure that submit gets overridden with the file details? (I have a new question open for that one, since it's an anchor element and I've been unable to get the click event working for that)
0
 
Bob LearnedCommented:
So many details, so little time...

Please show me the HTML elements for the <input type="file> for the upload, and the associated <form> element.
0
 
sirbountyAuthor Commented:
I pulled this block which includes the options before (setting I don't change), the browse button and the save button/link:
<form id="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm"   name="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm" 
  method="post" 
  action="/console/services/zdm/index.jsf" 
  enctype="multipart/form-data">
<div class="leftPaddedSection"><div class="form">
  <table border="0" cellspacing="2" width="100%">
   <tbody><tr><td class="formLabelNoWrap">Default Domain *</td><td class="">
     <input id="defaultDomain" name="defaultDomain" type="text" value="companyname.com" size="30" class="formField" />
	</td></tr><tr>
	<td class="formLabelNoWrap">Message Format</td>
	<td class="">
       <select 
	 id="msgFormat" 
	 name="msgFormat" 
 	 size="1" 
	 class="formField">	
	 <option value="V2">Version 2</option>	
	 <option value="V3" selected="selected">Version 3</option>
       </select>
       </td>
       </tr>
       <tr>
       <td class="formLabelNoWrap"><nobr>Session Timeout Period (minutes) *</nobr></td>
       <td class="">
       <input 
	 id="sessionTimeout" 
	 name="sessionTimeout" 
	 type="text" 
	 value="20" 
	 size="12" 
	 class="formField" />
       </td>
       </tr>
       <tr><td class="formLabelNoWrap">Identity Timeout Policy</td>
       <td class="">
       <select 
	 id="identityTimeoutPolicy" 
	 name="identityTimeoutPolicy" 
	 size="1" 
	 class="formField" 
	 onchange="submit()">	
	 <option value="OFF">Disabled</option>	
	 <option value="NEVER">Enabled - Never Times Out</option>	
	 <option value="TIMEOUT" selected="selected">Enabled - With Timeout Period</option>
       </select>
       </td></tr>
       <tr><td class="formLabelNoWrap">Identity Timeout Period</td>
	<td class="">
	<input id="identityTimeout" name="identityTimeout" type="text" value="12" size="12" class="formField" /> 
	<select id="identityTimeoutUnit" name="identityTimeoutUnit" size="1" class="formField">	
	<option value="HOUR" selected="selected">Hour(s)</option>	
	<option value="DAY">Day(s)</option>	
	<option value="WEEK">Week(s)</option></select></td></tr>
	<tr>
	<td class="formLabelNoWrap">
	<span class="formLabelTop">Message Locking Configuration</span>
	</td>
	<td class="">
	<br/>
	<span class="formTip">Browse to select a CSV file, then click the Save button to upload it.</span>
	<table border="0" cellpadding="2" cellspacing="0">
	<tbody>
	<tr>
	<td>
	<input type="file" 
	  id="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload"   	  name="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload" 
	  size="40" 
	  class="formField" />
	</td>
	<td></td>
	</tr>
  </tbody>
</table>
<table border="0" cellpadding="3" cellspacing="0">
<tbody>
<tr><td>
<a href="#" onclick="return oamSubmitForm('zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm','zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:downloadMsgLockConfig');" id="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:downloadMsgLockConfig">Download current configuration</a></td><td> </td><td><a href="#" onclick="var cf = function(){if (!confirm('Are you sure you want to delete all message locking filters?')) return false};var oamSF = function(){return oamSubmitForm('zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm','zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:clearMsgLockConfig');};return (cf()==false)? false : oamSF();" id="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:clearMsgLockConfig">Clear current configuration</a></td></tr></tbody></table></td></tr></tbody></table></div></div><br/><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td>

<div class="ButtonRowR">
  <table class='ButtonWrapper'>
    <tr>
      <td>
        <a href="#" 
	  onclick="return oamSubmitForm	('zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm','zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:saveZDMSessionConfig');" 	  id="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:saveZDMSessionConfig" class="ButtonLeft">
	  <div class='ButtonRight'>
 	    <div class='ButtonMiddle'>Save</div>
	  </div>
	</a>
      </td>
    </tr>
  </table>
</div>
</td>
</tr>
</tbody>
</table>

Open in new window

0
 
Bob LearnedCommented:
We need to focus here:

<div class="ButtonRowR">
  <table class='ButtonWrapper'>
    <tr>
      <td>
       <a href="#"
        onclick="return oamSubmitForm      ('zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm','zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:saveZDMSessionConfig');"         id="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:saveZDMSessionConfig" class="ButtonLeft">
       <div class='ButtonRight'>
           <div class='ButtonMiddle'>Save</div>
        </div>
      </a>
      </td>
    </tr>
  </table>
</div>

Is that the relevant anchor that you can't get click() to work?
0
 
sirbountyAuthor Commented:
Yes, but I think it's because of the function that it's trying to execute.
Four parameters required: (formName, linkId, target, params)
0
 
sirbountyAuthor Commented:
Changed this line (to onclick)
 form.AttachEventHandler("onclick", AddressOf OnSubmit)
and it hit the handler...although it still popped up a script error (yes/no prompt)
0
 
sirbountyAuthor Commented:
Stepping through the code shows:
? child.Name
"zdmSummaryDetailsSubview:footerViewpc1:footerFormpc1_SUBMIT"
? child.GetAttribute("value")
"1"

? child.Name
"javax.faces.ViewState"
? child.GetAttribute("value")
"rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kN5YnxBzKWwCAAB4cAAAAAN0AAE1cHQAFx9zZXJ2aWNlcy43ZG0vaW5kZXguanNw"

(this from the Case Else - I don't really need to catch these)

It never hit the input, file case element.
Once it went through I fired off the remainder and it did add the attribute, but then bombed at

result.headers = (Convert.ToString("Content-Type: multipart/form-data; boundary=") & boundary) + vbCr & vbLf + "Content-Length: " + result.data.Length + vbCr & vbLf + vbCr & vbLf

with a conversion error.
I think we're getting closer?
0
 
Bob LearnedCommented:
Try this:
result.headers = "Content-Type: multipart/form-data; boundary=" & boundary & vbCr & vbLf & "Content-Length: " & result.data.Length & vbCr & vbLf & vbCr & vbLf

Open in new window

0
 
sirbountyAuthor Commented:
Well, it prevented the coversion error, but with the script error still there it doesn't seem to be submitting the file.
I did try changing the reference to the input file to set that attribute for "file" to the location of the file.  Didn't seem to change anything there either.
I'll try turning the script error suppresion back on (left it off so I could get past the security alert, but now I've installed the cert)...
0
 
sirbountyAuthor Commented:
It seems to loop through the doccompleted sub multiple times after I click the save button.
No script errors this time, but about the 3rd time it hits the completed sub, it doesn't find the browse button, so errors on the missing object.  And the page now looks like it didn't completely load.
I let the sub finish out and tried a refresh, but it's still not uploading  the file.
I know when it has new config data, because there's a section on the header that states an update to all nodes is needed...
0
 
Bob LearnedCommented:
At this point I can't assume that this line was reached:

webbrowser.Navigate(url, form.GetAttribute("target"), req.data, req.headers)

Open in new window

0
 
Bob LearnedCommented:
And, we shouldn't assume that this line is reached:

postData.Submit()

Open in new window

0
 
Bob LearnedCommented:
Do you reach this line?

Private Sub AddFile(name As String, value As String)
                  If name = "" Then
                        Return
                  End If
                 files.Add(New ValuePair(name, value))
            End Sub
0
 
Bob LearnedCommented:
What is "result.data.Length" here?

result.headers = "Content-Type: multipart/form-data; boundary=" & boundary & vbCr & vbLf & "Content-Length: " & result.data.Length & vbCr & vbLf & vbCr & vbLf
0
 
sirbountyAuthor Commented:
First two comments - yes, I hit breakpoints at both (though after the script error).
No to the AddFile sub - it never hits that case element.
result.data.length is 416 at the line you posted last, but for the webbrowser.navigate, the url appears correct, but the form attribute "target" is empty...
0
 
Bob LearnedCommented:
1) The "target" attribute is not specified, and that's OK, since you don't need it (target frame).

2) It should call AddFile here:

Select Case child.TagName
    Case "INPUT"
          Select Case child.GetAttribute("type").ToUpper()
            Case "FILE"
                 AddFile(child.Name, child.GetAttribute("value"))
                  Exit Select
                  Case "CHECKBOX", "RADIO"
...
0
 
sirbountyAuthor Commented:
I'll step through it again and see what the tagname is - pretty sure it kept hitting the case else...
0
 
sirbountyAuthor Commented:
First pass to GetValuesFromForm,
child.TagName = "A" so it skips, next it's "INPUT" but "type" attribute is 'hidden',
so it hits the case else and adds "hidden" with a value of '1'
Third time it's "INPUT" with 'hidden' and a value of a really long string of seemingly random characters.
It doesn't return after this.
0
 
Bob LearnedCommented:
It needs to find the <input type="file"> element.

<input type="file"         id="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload"           name="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload"
        size="40"
        class="formField" />
      </td>
0
 
sirbountyAuthor Commented:
And for the GetEncodedPostData, the values (2 of them) are:
? values(0)
{Voltage_Test.FormToMultipartPostData.ValuePair}
    name: "zdmSummaryDetailsSubview:footerViewpc1:footerFormpc1_SUBMIT"
    value: "1"
? values(1)
{Voltage_Test.FormToMultipartPostData.ValuePair}
    name: "javax.faces.ViewState"
    value: "rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAN0AAE1cHQAFy9zZXJ2aWNlcy96ZG0vaW5kZXguanNw"
0
 
sirbountyAuthor Commented:
I presume I need to leave this?
Changed this line (to onclick)
 form.AttachEventHandler("onclick", AddressOf OnSubmit)
It wasn't hitting the handler otherwise... Or is there some other event I should be looking for?
0
 
Bob LearnedCommented:
According to the sample project, you need to attach an event handler to the "onsubmit" event:

form.AttachEventHandler("onsubmit", ...

When the event doesn't get raised, it is because there is no submit.  That should happen on the <input type="file"> element, which we are having a problem finding.
0
 
sirbountyAuthor Commented:
I think this is why it's not making sense to me...
The only 'event' that I see in the source is when the save button is clicked.  There is no action shown for the browse button.  Are we assuming we can technically skip that procedure and just ensure that the file value gets populated correctly and then submit via the save button?  Or should I focus on actually clicking the browse button and that somehow is inserting the file into the popup dialogue?
0
 
Bob LearnedCommented:
This is pretty complex, so let's review:

1) Attach an event handler to the "onsubmit" event.

2) The <Save> anchor, when clicked, raises the "submit" event.

3) Find an <input type="file"> HTML element.

4) When the "onsubmit" event is raised, handle it.

5) Let JavaScript know that the client-side event was handled by external handler:
form.SetAttribute("hasBrowserHandler", "1")

6) The FormToMultipartPostData.Submit method uses a POST to get the file bytes, and upload to the server.

All these steps need to work correctly, or the upload will not occur.
0
 
sirbountyAuthor Commented:
Putting it back to onsubmit doesn't do anything.
I grab the id for the save button, click it, get the script error, then it just kind of sits there... :(

The only onsubmit that I see in the source is within the page function:
function oamSubmitForm(formName, linkId, target, params) {
	var clearFn = 'clearFormHiddenParams_'+formName.replace(/-/g, '\$:').replace(/:/g,'_')
    if (typeof window[clearFn] =='function') {
        window[clearFn](formName)
    }
    var form = document.forms[formName]
    var agentString = navigator.userAgent.toLowerCase()
    if (agentString.indexOf('msie') != -1) {
        if (!(agentString.indexOf('ppc') != -1 && agentString.indexOf('windows ce') != -1 && version >= 4.0)) {
            window.external.AutoCompleteSaveForm(form)
        }
    }
    var oldTarget = form.target
    if(target != null) {
        form.target=target
    }
    if((typeof params!='undefined') && params != null) {
        for(var i=0, param; (param = params[i]); i++) {
            oamSetHiddenInput(formName,param[0], param[1])
        }
    }
    oamSetHiddenInput(formName,formName +':'+'_idcl',linkId)
    if(form.onsubmit) {
        var result=form.onsubmit()
        if((typeof result=='undefined')||result) {
            try {
                form.submit()
            } catch(e) {
            }
        }
    }else {
        try{
            form.submit()
        }catch(e){
        }
    }
    form.target=oldTarget
    if((typeof params!='undefined') && params != null) {
        for(var i=0, param; (param = params[i]); i++) {
            oamClearHiddenInput(formName,param[0], param[1])
        }
    }
    oamClearHiddenInput(formName,formName +':'+'_idcl',linkId)
    return false
}

Open in new window

0
 
sirbountyAuthor Commented:
Perhaps a silly, certainly ignorant, question - case doesn't matter with 'onsubmit' does it?
0
 
sirbountyAuthor Commented:
So I shouldn't be focused on the onclick listed under the anchor tag?
<a href="#" 
	onclick="return 
	oamSubmitForm ('zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm','zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:saveZDMSessionConfig');" 
	id="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:saveZDMSessionConfig" 
	class="ButtonLeft">
	<div class="ButtonRight"><div class="ButtonMiddle">Save</div></div>
</a>

Open in new window

0
 
Bob LearnedCommented:
"case doesn't matter with 'onsubmit' does it?"
That is never a silly question when working with C# and Javascript, but as a VB.NET programmer it makes sense that you think it is silly.  Case does matter in most cases.

This line will submit the page:
form.submit()

If you have attached to the correct handler, then the event should be handled by the VB.NET code.
0
 
sirbountyAuthor Commented:
And this is the only instance I see window.external, within that function above (window.external.AutoCompleteSaveForm(form)) which is where the script error is thrown immediately after clicking save.
0
 
sirbountyAuthor Commented:
This line will submit the page:
form.submit()
So use that rather than Savebutton.click()?
0
 
Bob LearnedCommented:
"So I shouldn't be focused on the onclick listed under the anchor tag?"
Yes, you should be focused on that, since it calls the oamSubmitForm, which in turn calls the form.submit(), which raises the "onsubmit" event, which is handled by the code.

Knee bone connected to the thigh bone...
Thigh bone connected to the hip bone...
0
 
sirbountyAuthor Commented:
submit is not a member of system.windows.forms.htmlelement.
Trying form.raiseevent instead...
0
 
sirbountyAuthor Commented:
Gah - raiseevent gives me "Value does not fall within the expected range." :(
0
 
Bob LearnedCommented:
While those were valiant attempts, they will not get you where you need to be.  I believe that it should be possible if we follow the code example project from CodeProject, we just need to get all the steps to work as expected.
0
 
sirbountyAuthor Commented:
Ok, so backing up to your outline above...only step #1 is definitely completed/working.
I'm unsure that the save anchor being clicked is raising the submit event.  Based on what I'm seeing, it is not, or at least it's throwing a script error first that may or may not be interfering.  Suppressing the script errors doesn't seem to do anything.

I'm going to step through the forms.count loop and see if I can determine any uniqueness there.
I also moved the form.raiseevent("submit") within this loop, after the hasBrowserHandler is set.
0
 
sirbountyAuthor Commented:
? doc.forms(0).getattribute("enctype") & vbTab & doc.forms(0).id
"application/x-www-form-urlencoded zdmSummaryDetailsSubview:headerViewpc1:headerFormpc1"

? doc.forms(1).getattribute("enctype") & vbTab & doc.forms(1).id
"application/x-www-form-urlencoded zdmSummaryDetailsSubview:headerViewpc1:globalActionsFormpc1"

? doc.forms(2).getattribute("enctype") & vbTab & doc.forms(2).id
"application/x-www-form-urlencoded zdmSummaryDetailsSubview:nav1Viewpc1:navServicesFormpc1"

? doc.forms(3).getattribute("enctype") & vbTab & doc.forms(3).id
"application/x-www-form-urlencoded zdmSummaryDetailsSubview:nav2Viewpc1:nav2ServiceZDMFormpc1"

? doc.forms(4).getattribute("enctype") & vbTab & doc.forms(4).id
"application/x-www-form-urlencoded zdmSummaryDetailsSubview:relContentViewpc1:zdmTabsForm"

? doc.forms(5).getattribute("enctype") & vbTab & doc.forms(5).id
"application/x-www-form-urlencoded "

? doc.forms(6).getattribute("enctype") & vbTab & doc.forms(6).id
"multipart/form-data zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm"

? doc.forms(7).getattribute("enctype") & vbTab & doc.forms(7).id
"application/x-www-form-urlencoded zdmSummaryDetailsSubview:relContentViewpc1:zdmTabsForm2"

? doc.forms(8).getattribute("enctype") & vbTab & doc.forms(8).id
"application/x-www-form-urlencoded zdmSummaryDetailsSubview:footerViewpc1:footerFormpc1"

So, it appears that element 6 is the one I want, and the only one with multipart/form-data.
The inner/outer html shows:

"  <FORM id=zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm encType=multipart/form-data method=post name=zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm action=/console/services/zdm/index.jsf file="\\hfdp-spd-020\email\voltagepoc\message locking\msglocking.csv"><DIV class=leftPaddedSection>  <DIV class=form>  <TABLE border=0 cellSpacing=2 width="100%">  <TBODY>  <TR>  <TD class=formLabelNoWrap>Default Domain *</TD>  <TD><INPUT id=defaultDomain class=formField value=aetna.com size=30 name=defaultDomain></TD></TR>  <TR>  <TD class=formLabelNoWrap>Message Format</TD>  <TD><SELECT id=msgFormat class=formField size=1 name=msgFormat> <OPTION value=V2>Version 2</OPTION> <OPTION selected value=V3>Version 3</OPTION></SELECT></TD></TR>  <TR>  <TD class=formLabelNoWrap><NOBR>Session Timeout Period (minutes) *</NOBR></TD>  <TD><INPUT id=sessionTimeout class=formField value=20 size=12 name=sessionTimeout></TD></TR>  <TR>  <TD class=
formLabelNoWrap>Identity Timeout Policy</TD>  <TD><SELECT id=identityTimeoutPolicy class=formField onchange=submit() size=1 name=identityTimeoutPolicy> <OPTION value=OFF>Disabled</OPTION> <OPTION value=NEVER>Enabled - Never Times Out</OPTION> <OPTION selected value=TIMEOUT>Enabled - With Timeout Period</OPTION></SELECT></TD></TR>  <TR>  <TD class=formLabelNoWrap>Identity Timeout Period</TD>  <TD><INPUT id=identityTimeout class=formField value=12 size=12 name=identityTimeout> <SELECT id=identityTimeoutUnit class=formField size=1 name=identityTimeoutUnit> <OPTION selected value=HOUR>Hour(s)</OPTION> <OPTION value=DAY>Day(s)</OPTION> <OPTION value=WEEK>Week(s)</OPTION></SELECT></TD></TR>  <TR>  <TD class=formLabelNoWrap><SPAN class=formLabelTop>Message Locking Configuration</SPAN></TD>  <TD><BR><SPAN class=formTip>Browse to select a CSV file, then click the Save button to upload it.</SPAN>  <TABLE border=0 cellSpacing=0 cellPadding=2>  <TBODY>  <TR>  <TD><INPUT id=zdmSummaryDetailsSubview:relContentViewpc1:tabZDM
Service:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload class=formField size=40 type=file name=zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload></TD>  <TD></TD></TR></TBODY></TABLE>  <TABLE border=0 cellSpacing=0 cellPadding=3>  <TBODY>  <TR>  <TD><A id=zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:downloadMsgLockConfig onclick="return oamSubmitForm('zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm','zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:downloadMsgLockConfig');" href="#">Download current configuration</A></TD>  <TD></TD>  <TD><A id=zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:clearMsgLockConfig onclick="var cf = function(){if (!confirm('Are you sure you want to delete all message locking filters?')) return false};var oamSF = function(){return oam
SubmitForm('zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm','zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:clearMsgLockConfig');};return (cf()==false)? false : oamSF();" href="#">Clear current configuration</A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></DIV></DIV><BR>  <TABLE border=0 cellSpacing=0 cellPadding=0 width="100%">  <TBODY>  <TR>  <TD>  <DIV class=ButtonRowR>  <TABLE class=ButtonWrapper>  <TBODY>  <TR>  <TD><A id=zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:saveZDMSessionConfig class=ButtonLeft onclick="return oamSubmitForm('zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm','zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:saveZDMSessionConfig');" href="#">  <DIV class=ButtonRight>  <DIV class=ButtonMiddle>Save</DIV></DIV></A></TD></TR></TBODY></TABLE></DIV></
TD></TR></TBODY></TABLE><INPUT value=1 type=hidden name=zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm_SUBMIT><INPUT value=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAN0AAE1cHQAFy9zZXJ2aWNlcy96ZG0vaW5kZXguanNw type=hidden name=javax.faces.ViewState></FORM>"

Open in new window


Within there, I see the INPUT file type:
<INPUT id=zdmSummaryDetailsSubview:relContentViewpc1:tabZDM
Service:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload class=formField size=40 type=file name=zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload>

and I also see the save anchor element:
<A id=zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:saveZDMSessionConfig class=ButtonLeft onclick="return oamSubmitForm('zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm','zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:saveZDMSessionConfig');" href="#">

So since I'm clicking the anchor element, I need to somehow associate the INPUT file type to reference the external file, correct?

In the form loop, it hits i=6, as expected, attaches the event handler to "onsubmit", sets the attribute "hasBrowserHandler" to 1, and that's where I attempt the form.RaiseEvent("submit").  Hitting that line throws an ArgumentException was unhandled by user code: Value does not fall within the expected range.

<sigh> - It was all so 'easy' compared to this... :\
0
 
sirbountyAuthor Commented:
Took a step even further back, just to see if I could get 'any' success clicking an anchor.
So, immediately after logon, I grab the anchor for the Service tab and try to click, but it's coming up as 'nothing' when choosing HTMLAnchorElement.  Could it be that these should be defined as something besides an anchor? :\
0
 
sirbountyAuthor Commented:
Or could it be that it's supposed to reference the 'name' value?  I notice some have id & name, some only have ID... :\
0
 
sirbountyAuthor Commented:
Don't know why I had such trouble locating the Service tab, but once I did, by stepping throuh to the GetHtmlElementById, I was able to locate it.  Once clicked, however, and this is only changing tabs, it barfed on the window.external script error again.  Looks like that's expecting a value each time that function is called.
0
 
sirbountyAuthor Commented:
I'm guessing this part of the function is ensuring it's not a mobile device, and attempting to enable autocomplete?  Though I don't know why, or how to disable that, it appears to be the only source of this window.external in the source.
if (agentString.indexOf('msie') != -1) {
        if (!(agentString.indexOf('ppc') != -1 && agentString.indexOf('windows ce') != -1 && version >= 4.0)) {
            window.external.AutoCompleteSaveForm(form)
        }
    }
0
 
sirbountyAuthor Commented:
I'm stumped. :(

I even tried having my code 'wait' till I populated the file field manually, and follow up with a save click, and it still throws the script error for window.external...

I'll upload the source, in case that helps trigger anything on your end.
zdm.txt
0
 
Bob LearnedCommented:
You need to pass the correct User Agent string in the headers, that includes "msie" in the request headers, since it really is Internet Explorer, which is why it barfs on the AutoCompleteSaveForm.

Changing the User Agent in a web browser control
http://www.lukepaynesoftware.com/articles/programming-tutorials/changing-the-user-agent-in-a-web-browser-control/

Remember that Fiddler comment?  You can look at what Internet Explorer passes as the user agent.
0
 
sirbountyAuthor Commented:
I went back and 'fiddled' with fiddler - still couldn't get it to grab anything, though it does state that some policies might prevent that.
I'll have a look at the user agent.
0
 
sirbountyAuthor Commented:
User error with fiddler...under my admin account it captures, so that's sorted....
0
 
sirbountyAuthor Commented:
I see upon logon, the user agent is set to this:

User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; MS-RTC LM 8)
0
 
Bob LearnedCommented:
That Javascript goes is looking for "msie", which is "MSIE 8.0".
0
 
sirbountyAuthor Commented:
Although I'm seeing a lot more in fiddler now, I'm not sure how to implement it.
The user agent method above indicates to use .navigate to pass the user agent, but if I'm grabbing an anchor reference, I don't have .navigate.

However, I did get a successful "service tab" click/navigate using:

WebBrowser1.Navigate(Site.Uri.ToString, "_self", Nothing, "User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; MS-RTC LM 8)")

Would I just replace the .click method with a navigate to the href="#"?  So long as I can locate and modify the file= attribute?
0
 
Bob LearnedCommented:
I looked at the HTML text that you sent me, but I wouldn't be able to set up a mock web site without the Javascript that is referenced:

<script language="JavaScript" type="text/javascript" src="/console/scripts/helpPopup.js?5.1.2"></script>
<script language="JavaScript" type="text/javascript" src="/console/scripts/position.js?5.1.2"></script>
<script language="JavaScript" type="text/javascript" src="/console/scripts/utils.js?5.1.2"></script>
<script language="JavaScript" type="text/javascript" src="/console/scripts/progress.js?5.1.2"></script>
<script language="JavaScript" type="text/javascript" src="/console/scripts/ieflicker.js?5.1.2"></script>
<script language="JavaScript" type="text/javascript" src="/console/scripts/events.js?5.1.2"></script>

You could use developer tools on the web browser, and capture the Javascript text, and send me the files, and I could set up a web site with that HTML, and see if I can't get an upload.
0
 
sirbountyAuthor Commented:
I don't know if that opens up a new can of worms or not...you make it sound so simple, and yet... ;^)

I think I might be able to play with Fiddler over the weekend and see if I can come up with at least something helpful.  I tried navigating to the "#" reference link, but didn't work.

For the 'data' that is submitted from the csv, I do see this in fiddler:
Content-Disposition: form-data; name="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload"; filename="\\unc_path\filename.csv"
Content-Type: application/vnd.ms-excel

Open in new window

0
 
sirbountyAuthor Commented:
Sheesh - I don't know if I'm close or not.
After submitting save, adding the file info to the header, I got

Problem accessing /%23. Reason:
    Not Found

Haha.  I hope I don't break something. :^)
0
 
Bob LearnedCommented:
That sounds like an HTTP 404 error, which means "Resource not found".   Is this a Javascript error?

I found the Javascript that I was looking for, embedded in the HTML:

function oamSubmitForm(formName, linkId, target, params) {
        var clearFn = 'clearFormHiddenParams_' + formName.replace(/-/g, '\$:').replace(/:/g, '_');
        if (typeof window[clearFn] == 'function') {
            window[clearFn](formName);
        }
        var form = document.forms[formName];
        var agentString = navigator.userAgent.toLowerCase();
        if (agentString.indexOf('msie') != -1) {
            if (!(agentString.indexOf('ppc') != -1 && agentString.indexOf('windows ce') != -1 && version >= 4.0)) {
                window.external.AutoCompleteSaveForm(form);
            }
        }
        var oldTarget = form.target;
        if (target != null) {
            form.target = target;
        }
        if ((typeof params != 'undefined') && params != null) {
            for (var i = 0, param;
                (param = params[i]); i++) {
                oamSetHiddenInput(formName, param[0], param[1]);
            }
        }
        oamSetHiddenInput(formName, formName + ':' + '_idcl', linkId);
        if (form.onsubmit) {
            var result = form.onsubmit();
            if ((typeof result == 'undefined') || result) {
                try {
                    form.submit();
                } catch (e) {}
            }
        } else {
            try {
                form.submit();
            } catch (e) {}
        }
        form.target = oldTarget;
        if ((typeof params != 'undefined') && params != null) {
            for (var i = 0, param;
                (param = params[i]); i++) {
                oamClearHiddenInput(formName, param[0], param[1]);
            }
        }
        oamClearHiddenInput(formName, formName + ':' + '_idcl', linkId);
        return false;
    }

Open in new window

0
 
Bob LearnedCommented:
%23 = # in URL encoding.
0
 
Bob LearnedCommented:
Without CSS, this is what I see:

Snapshot
0
 
Bob LearnedCommented:
If I attach a file, and then click on the Save link, then I get this error:

Error snapshot
0
 
Bob LearnedCommented:
.jsf extensions are related to the Java FacesServlet.  It looks like it is trying to show a Home page.
0
 
sirbountyAuthor Commented:
Well that's a pretty good representation of the site. :^)
Are you using IE?  When I ran it from chrome it looked more like that.  IE showed the save button on the right and uses 'browse' instead of 'choose file'.

I thought index.jsf was the home page. :\
0
 
Bob LearnedCommented:
I don't like IE, so I always use Chrome as my browser of choice.

The anchor tags have an href="#", which means scroll to the top of the page:

Example:
<a href="#" onclick="var cf = function(){window.open('/console/help/Vg_securemail_console_help.htm', 'VgSMConsoleHelp', 'height=500,width=700,status,toolbar=0,menubar=0,status=0,scrollbars,resizable'); return false;}

I would like to understand how that error comes up.  Is it a Javascript error?  Can you attach a screen shot?
0
 
Bob LearnedCommented:
I am wondering if "zdm" refers to this:

Voltage SecureMail Cloud
https://www.voltage.com/vsn/login-pages.htm

Zero Download Messenger (ZDM);
0
 
sirbountyAuthor Commented:
Indeed it does.  We are using their secure mail product.  
We currently have to manually append to this csv file to lock a message.
This would allow the customer to get immediate message locking rather than wait on a tech to see the email and respond...

Which error did you want a screenshot of?
0
 
Bob LearnedCommented:
The /%23 not found error.
0
 
sirbountyAuthor Commented:
Sure, it was kind of bland, but I'll upload it...
0
 
sirbountyAuthor Commented:
Oh, I looked at the code again, and it was one attempt I had made to change the uri path to simply "#".
When I used the debugger to view the site's path value, it was "%23" - that must be where that came from...
0
 
sirbountyAuthor Commented:
Yeah, it's no longer appearing...was apparently just a mistake I made yesterday testing.
0
 
sirbountyAuthor Commented:
Was trying to use the .navigate with the useragent and the data I saw from fiddler.
Clearly I don't know what I'm doing...

 WebBrowser1.Navigate("#", "_self", Nothing, UserAgent & vbCrLf & "Content-Disposition: form-data; name=" & Chr(34) & "zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload" & Chr(34) & "; filename=" & Chr(34) & "\\UNCpath\lockfile.csv" & Chr(34) & vbCrLf & "Content-Type: application/vnd.ms-excel")
0
 
sirbountyAuthor Commented:
This is why the %23, and I tried the .navigate with the suggestion, but it didn't seem to work - went back to the first service page. :\
http://social.msdn.microsoft.com/Forums/en-US/11459b7a-1ee1-4a54-a4fb-76967ee22c96/webbrowser-control-how-to-navigate-to-an-anchor-new-uri-conversion-issue-23?forum=netfxcompact

Seems like my problem now is that I can navigate using the useragent, but I can't "click" with it...
0
 
Bob LearnedCommented:
Would that be the first time that you navigate to a URL?  I would think that you need to send it on every navigate.  Another possibility might be to create a custom WebBrowser class, and in the BeforeNavigate, set the user agent.

public class ExtendedWebBrowser : WebBrowser
{
    bool renavigating = false;

    public string UserAgent { get; set; }

    public ExtendedWebBrowser()
    {
        DocumentCompleted += SetupBrowser;

        //this will cause SetupBrowser to run (we need a document object)
        Navigate("about:blank");
    }

    void SetupBrowser(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        DocumentCompleted -= SetupBrowser;
        SHDocVw.WebBrowser xBrowser = (SHDocVw.WebBrowser)ActiveXInstance;
        xBrowser.BeforeNavigate2 += BeforeNavigate;
        DocumentCompleted += PageLoaded;
    }

    void PageLoaded(object sender, WebBrowserDocumentCompletedEventArgs e)
    {

    }

    void BeforeNavigate(object pDisp, ref object url, ref object flags, ref object targetFrameName,
        ref object postData, ref object headers, ref bool cancel)
    {
        if (!string.IsNullOrEmpty(UserAgent))
        {
            if (!renavigating)
            {
                headers += string.Format("User-Agent: {0}\r\n", UserAgent);
                renavigating = true;
                cancel = true;
                Navigate((string)url, (string)targetFrameName, (byte[])postData, (string)headers);
            }
            else
            {
                renavigating = false;
            }
        }
    }
}

Open in new window

0
 
Bob LearnedCommented:
VB.NET:

Public Class ExtendedWebBrowser
	Inherits WebBrowser
	Private renavigating As Boolean = False

	Public Property UserAgent() As String

	Public Sub New()
		AddHandler DocumentCompleted, AddressOf SetupBrowser

		'this will cause SetupBrowser to run (we need a document object)
		Navigate("about:blank")
	End Sub

	Private Sub SetupBrowser(sender As Object, e As WebBrowserDocumentCompletedEventArgs)
		RemoveHandler DocumentCompleted, AddressOf SetupBrowser
		Dim xBrowser As SHDocVw.WebBrowser = DirectCast(ActiveXInstance, SHDocVw.WebBrowser)
		AddHandler xBrowser.BeforeNavigate2, AddressOf BeforeNavigate
		AddHandler DocumentCompleted, AddressOf PageLoaded
	End Sub

	Private Sub PageLoaded(sender As Object, e As WebBrowserDocumentCompletedEventArgs)

	End Sub

	Private Sub BeforeNavigate(pDisp As Object, ByRef url As Object, ByRef flags As Object, ByRef targetFrameName As Object, ByRef postData As Object, ByRef headers As Object, _
		ByRef cancel As Boolean)
		If Not String.IsNullOrEmpty(UserAgent) Then
			If Not renavigating Then
				headers += String.Format("User-Agent: {0}" & vbCr & vbLf, UserAgent)
				renavigating = True
				cancel = True
				Navigate(url.ToString(), targetFrameName.ToString(), DirectCast(postData, Byte()), headers.ToString())
			Else
				renavigating = False
			End If
		End If
	End Sub
End Class

Open in new window

0
 
sirbountyAuthor Commented:
Hmm, that seems promising.  I'll try to implement it... haha.
0
 
sirbountyAuthor Commented:
Would I need to move my documentcompleted sub into there as well?
0
 
Bob LearnedCommented:
No, your code could stand as it is, since you are just extending the WebBrowser class to add additional behavior.  That class would have a UserAgent property, that you set once, and would be passed to the web site every time before the control needed to navigate.
0
 
Bob LearnedCommented:
BTW, what version of Visual Studio are you working with?
0
 
sirbountyAuthor Commented:
2010
0
 
sirbountyAuthor Commented:
SHDocVw.Webbrosser is not defined - I need to add reference to that dll, yes?  Cause that's what I'm doing unless you tell me otherwise. :^)
0
 
sirbountyAuthor Commented:
And I change my designer to
Me.Webbrowser1 = New ExtendedWebBrowser, yes?
0
 
sirbountyAuthor Commented:
I don't really see much of a change, other than I did remove the user agent from my doccompleted sub and that's working...

Here's my sub - maybe I've simply set something up bogus...

Private Sub WebBrowser1_DocumentCompleted(sender As Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
        If e.Url.AbsolutePath.ToLower.Contains("login") Then Exit Sub 'still at the logon page
        If ServiceTabClicked Then
            If ZDMConfigTabClicked Then
                If SaveButtonClicked Then
                    'read form to find 'success' or 'error/else' 
                    'todo: once file successfully uploaded, form displays results in red/green
                Else
                    Dim filename As String = "\\URLPath\LockFile.csv"
                    Dim browseButton As mshtml.HTMLInputElement = helper.GetHtmlElementById(Of mshtml.HTMLInputElement)("zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload")
                    browseButton.setAttribute("filename", filename) 'something I've tried - doesn't work
                    Dim SaveButton As mshtml.HTMLAnchorElement = helper.GetHtmlElementById(Of mshtml.HTMLAnchorElement)("zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:saveZDMSessionConfig")

                    Dim doc As HtmlDocument = WebBrowser1.Document
                    For i As Integer = 0 To doc.Forms.Count - 1
                        ' must be declared inside the loop because there's a closure
                        form = doc.Forms(i)
                        If form.GetAttribute("enctype").ToLower() <> "multipart/form-data" Then Continue For
                        form.AttachEventHandler("onsubmit", AddressOf OnSubmit)
                        ' form.AttachEventHandler("onclick", AddressOf OnSubmit)
                        form.SetAttribute("hasBrowserHandler", "1")
                        'have also found this elsewhere as form.SetAttribute("hasBrowserHandlers", "true") but doesn't seem to change anything
                    Next
                    SaveButtonClicked = True 'technically it's not at this point
                    'VoltageSite.Path += "#" 'this was throwing my %23 error
                    WebBrowser1.Navigate(VoltageSite.Uri.ToString) ' not working
                    'SaveButton.click() ' still throws the script error :(
                End If
            Else
                Dim zdmCfgTab As mshtml.HTMLInputElement = helper.GetHtmlElementById(Of mshtml.HTMLInputElement)("zdmSummaryDetailsSubview:relContentViewpc1:configZDMTabbedPane.2")
                zdmCfgTab.click()
                zdmCfgTab = Nothing
                ZDMConfigTabClicked = True
            End If
        Else
            VoltageSite.Path = "console/services/zdm/index.jsf"
            WebBrowser1.Navigate(VoltageSite.Uri.ToString) ', "_self", Nothing, UserAgent)
            'WebBrowser1.Navigate(VoltageSite.Uri.ToString)
            ServiceTabClicked = True
        End If
    End Sub

Open in new window

0
 
Bob LearnedCommented:
Which edition of Visual Studio 2010 do you have?  Do you have the ability to record Coded UI tests?

How to: Create a Coded UI Test
http://msdn.microsoft.com/en-us/library/dd286681(v=vs.100).aspx

Using Visual Studio Premium or Visual Studio Ultimate, you can create a coded UI test that can test that the user interface for an application functions correctly
0
 
sirbountyAuthor Commented:
If I don't, I can probably get permissions to install another edition...I'll check and get back to you.
Thanks.
0
 
sirbountyAuthor Commented:
Well apparently 'permission' will be very hard to come by. :(
Nonetheless, I'm still testing.  I'm going to run through fiddler once more and try to build a new project from the ground up using what I find there.  Hopefully the new/fresh perspective will help.
0
 
Bob LearnedCommented:
I was curious what edition you were using after some out-of-the-box thinking.  With Coded UI unit tests, you can record a test, generate some code, and play it back with different arguments, which might get you what you need.
0
 
sirbountyAuthor Commented:
I have VS 2010 Professional :(
0
 
sirbountyAuthor Commented:
I've walked through recreating the entire thing from scratch...though I didn't use mshtml this time.
Everything works up until that point. :(

In Fiddler, I can see that it's setting the input, type=file, value to the path of the csv.
Yet, when I try to use setattribute against that, it remains blank.  I'm guessing because that field is essentially 'locked' unless using the browse button, so I'm wondering if I'm back to trying to track down the handle of the file dialogue...
0
 
sirbountyAuthor Commented:
Yep, once I programmatically clicked the browse button and selected the file, it's holding the "value" attribute... ugh.
0
 
sirbountyAuthor Commented:
Apparenlty this is 'by design'... http://www.cs.tut.fi/~jkorpela/forms/file.html#value
<sigh>
0
 
Bob LearnedCommented:
"Yet, when I try to use setattribute against that, it remains blank."
Can you explain what you mean by that?  

You can't set the value attribute for the <input type="file">, since it is a security violation.  This whole exercise has been detecting the submit, and posting the file.  I am lost why that didn't work as expected.
0
 
sirbountyAuthor Commented:
I think I know why - I had previously been focused on grabbing the button ID.
Re-reading that site I've modified that to grabbing the correct form ID and now it's working through the loop and located the FILE element...stay tuned.
0
 
sirbountyAuthor Commented:
I don't know if I'm more hard-headed or more ignorant, but I think much of this is starting to make more sense to me...

So, here's what I'm seeing now:
Still throws the script error (window.external) on the button click, but I don't know how the useragent can be added to a click event (like we had with the navigate method).

It runs through the GetValusFromForm - it does locate the "FILE" element, but obviously it's blank.
But it includes several of the other settings that it's passing.
It returns to the event handler, and sets the file (I changed this to "filename" since it's actually showing in fiddler as filename).

Right before postData.Submit(), I examine the data.
I have 8 values (the aforementioned settings) listed in PostData.values (count=8).
I have a files (count=1) property as well.
For PostData.Files(0) I have
name:"zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload"
value: ""

I would have expected that to be the path of the file... :(
0
 
Bob LearnedCommented:
Do you know what the file name is going to be?

You could change this line:

AddFile(child.Name, child.GetAttribute("value"))

Open in new window


to this:

AddFile(child.Name, m_fileName)

Open in new window

0
 
sirbountyAuthor Commented:
As it continues through to GetEncodedPostData(),
headerTemplate is equal to
"Content-Disposition: form-data; name="{0}"; filename="{1}"  Content-Type: application/octet-stream    "

Since the file path was empty, I forced it in that same routine, and it got to the point where it read the file and added it to the memStream, but I couldn't tell once it hit the navigate if it worked. (Hope that makes sense)
0
 
sirbountyAuthor Commented:
Tried hard coding it in there, but it didn't seem to take the file.
I'll run through again after I grab a bite and turn fiddler back on to try to see if I can find the difference.

Meanwhile, do you know of a way to have the .Click() procedure include the UserAgent?  Not sure if that sorts it, or if I need to ensure that it's added in this additional class...just thinking outloud.
0
 
Bob LearnedCommented:
"but I couldn't tell once it hit the navigate if it worked. (Hope that makes sense)"

There are two indications that I could think of:

1) Error
2) The file didn't upload
0
 
sirbountyAuthor Commented:
Running it through fiddler, I have 4 warnings:
Content-length mismatch; Request Header indicated 17,185 bytes, but client sent 0 bytes (twice)
Failed to obtain requestbody.System.IO.InvalidDataException The request body did not contain the specified number of bytes.  Got 0, expected 17185 (twice)
0
 
sirbountyAuthor Commented:
But, fidder does show the same body info:

Content-Disposition: form-data; name="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:msglockfileupload"; filename="My CSV File!"
Content-Type: application/octet-stream
0
 
sirbountyAuthor Commented:
I'm finding the reference for hasBrowserHandler to be hasBrowserHandlers and instead of a value of 1, examples show a value of "true".
I'm not sure if setting attributes for both versions is a bad idea or not...so I've been flip-flopping them.
0
 
sirbountyAuthor Commented:
Not sure if that's eliminated my script error, or my change to
form.RaiseEvent("onsubmit")...  
But, running fiddler again, it almost seems like it's only pushing part of the file.  The details of that field don't scroll all the way down as if it's been truncated.  I'm thinking maybe it has something to do with that error I'm seeing repeatedly about Content-length mismatch...
0
 
sirbountyAuthor Commented:
Looking through the working session vs non-working session today.
I see the definition passed for content-type was application/octet-stream, but the
working session shows it as "vnd.ms-excel", so I've changed that in the code.

These other things, I'm unsure of, but pointing out what I see as far as differences:
Obviously these lines are different, but I think they're unique per session:
------------------------------8d183179e024d12
However, I did see the automated version had one additional hyphen, so I shortened that in the code.

The non working session has an empty/line feed at the top.

Both have 'form-data' for defaultDomain, msgFormat, sessionTimeout, identityTimeoutPolicy,
identityTimeout, and identityTimeoutUnit - values all correct.

Removing that, they both have
Content-Disposition: form-data; name="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm_SUBMIT"; (value of 1)

but these are in different places within the session data (not sure if that matters?)

The working session has one additional form-data info, that I don't see in the non-working session:

Content-Disposition: form-data; name="zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:_idcl"

zdmSummaryDetailsSubview:relContentViewpc1:tabZDMService:tabZDMServiceSettings:zdmDetailsForm:saveZDMSessionConfig
-----------------------------7de1684362508--


Finally, this may be nit-picking, but the working session shows this line:
Content-Disposition: form-data; name="javax.faces.ViewState"
The non-working has a trailing semi-colon (;).
0
 
sirbountyAuthor Commented:
Oh, and Fiddler is now down to 2 complaints, instead of 4 about the content length mismatch...
0
 
Bob LearnedCommented:
Just let me know when I can help, because you are outside the boundaries now...
0
 
sirbountyAuthor Commented:
I'll just go ahead and close this one.  You've helped me a lot.  Thanks!
0

Featured Post

NEW Veeam Backup for Microsoft Office 365 1.5

With Office 365, it’s your data and your responsibility to protect it. NEW Veeam Backup for Microsoft Office 365 eliminates the risk of losing access to your Office 365 data.

  • 80
  • 48
Tackle projects and never again get stuck behind a technical roadblock.
Join Now