5

I have a web application project to support file transfer operations to vendor product backend. It's composed of 2 HTTPHandler files compiled into a website on a Win2003 server with IIS 6.0:

  • UploadHandler.ashx
  • DownloadHandler.ashx

These files get "POSTed to" from a ColdFusion website that exposes the user interface. In a way, my job is done because these handlers work and have to be called from ColdFusion.

Yet, I am very frustrated with my inability to get my own "test UI" (default.aspx) to use in my testing/refinement independent of ColdFusion.

<asp:Button ID="DownloadButton" PostBackUrl="~/DownloadHandler.ashx"  runat="server" Text="Download"/>

Using a PostBackUrl for Download works nicely - when the DownloadHandler.ashx is entered, it finds its key input value in context.Request.Form["txtRecordNumber"];

But I cannot use this technique for Upload because I have to do some processing (somehow read the bytes from the chosen fileupload1.postedfile into a FORM variable so my UploadHandler.ashx file can obtain its input from Request.Form as with Download).

My first approach tried using HTTPWebRequest which seemed overly complex and I could never get to work. Symptoms began with a HTTP 401 status code and then morphed into a 302 status code so I researched other ideas.

Here is my latest code snippet from my default.aspx:

protected void UploadHandlerButton_Click(object sender, EventArgs e)
{
    if (FileUpload1.HasFile)
    {
        try
        {
            BuildFormData();
            //Server.Transfer("UploadHandler.ashx", true);
            Response.Redirect("~/UploadHandler.ashx");
        }
        catch (Exception someError)
        {
            LogText("FAILURE: " + someError.Message);
        }
    }
}
protected void BuildFormData()
{
    BinaryReader b = new BinaryReader(FileUpload1.PostedFile.InputStream);
    int numBytes = FileUpload1.PostedFile.ContentLength;
    byte[] fileContent = b.ReadBytes(numBytes);
    objBinaryData.Text = System.Text.Encoding.UTF8.GetString(fileContent);
    b64fileName.Text = FileUpload1.PostedFile.FileName;
    // create arbitrary MetaData in a string
    strMetaData.Text = "recAuthorLoc=anyname1~udf:OPEAnalyst=anyname2~udf:Grant Number=0102030405";
}

Attempts to use Server.Transfer (above) to my .ashx file result in an error: error executing child request for UploadHandler.ashx

Attempts to use Response.Redirect (above) to my .ashx file result in GET (not POST) and Trace.axd of course shows nothing in the Form collection so that seems wrong too.

I even tried clone-ing my .ashx file and created UploadPage.aspx (a webform with no HTML elements) and then tried:

Server.Transfer("UploadPage.aspx", true);
//Response.Redirect("~/UploadPage.aspx");

Neither of those allow me to see the form data I need to see in Request.Form within my code that processes the Upload request. I am clearly missing something here...thanks in advance for helping.

EDIT-UPDATE: I think I can clarify my problem. When the UploadHandler.ashx is posted from ColdFusion, all of the input it needs is available in the FORM collection (e.g. Request.Form["fileData"] etc.)

But when I use this control it generates a postback to my launching web page (i.e. default.aspx). This enables me to refer to the content by means of FileUpload1.PostedFile as in:

protected void BuildFormData()
{
    BinaryReader b = new BinaryReader(FileUpload1.PostedFile.InputStream);
    int numBytes = FileUpload1.PostedFile.ContentLength;
    byte[] fileContent = b.ReadBytes(numBytes);
    objBinaryData.Text = System.Text.Encoding.UTF8.GetString(fileContent);
    b64fileName.Text = FileUpload1.PostedFile.FileName;
}

Yet I am not using the FileUpload1.PostedFile.SaveAs method to save the file somewhere on my web server. I need to somehow - forgive the language here - "re-post" this data to an entirely different file - namely, my UploadHandler.ashx handler. All the goofy techniques I've tried above fail to accomplish what I need.

EDIT-UPDATE (20 Aug 2009) - my final SOLUTION using Javascript:

protected void UploadHandlerButton_Click(object sender, EventArgs e)
{
    if (FileUpload1.HasFile)
    {
        try
        {
            ctlForm.Text = BuildFormData();
            String strJS = InjectJS("_xclick");
            ctlPostScript.Text = strJS;
        }
        catch (Exception someError)
        {
            LogText("FAILURE: " + someError.Message);
        }
    }
}
private String InjectJS(String strFormId)
{
    StringBuilder strScript = new StringBuilder();
    strScript.Append("<script language='javascript'>");
    strScript.Append("var ctlForm1 = document.forms.namedItem('{0}');");
    strScript.Append("ctlForm1.submit();");
    strScript.Append("</script>");
    return String.Format(strScript.ToString(), strFormId);
}
protected string BuildFormData()
{
    BinaryReader b = new BinaryReader(FileUpload1.PostedFile.InputStream);
    int numBytes = FileUpload1.PostedFile.ContentLength;
    byte[] fileContent = b.ReadBytes(numBytes);
    // Convert the binary input into Base64 UUEncoded output.
    string base64String;
    base64String =
           System.Convert.ToBase64String(fileContent,
                                         0,
                                         fileContent.Length);
    objBinaryData.Text = base64String;
    b64fileName.Text = FileUpload1.PostedFile.FileName;
    // create arbitrary MetaData in a string
    strMetaData.Text = "recAuthorLoc=Patterson, Fred~udf:OPEAnalyst=Tiger Woods~udf:Grant Number=0102030405";

    StringBuilder strForm = new StringBuilder();
    strForm.Append("<form id=\"_xclick\" name=\"_xclick\" target=\"_self\" action=\"http://localhost/HTTPHandleTRIM/UploadHandler.ashx\" method=\"post\">");
    strForm.Append("<input type=\"hidden\" name=\"strTrimURL\"    value=\"{0}\" />");
    strForm.Append("<input type=\"hidden\" name=\"objBinaryData\" value=\"{1}\" />");
    strForm.Append("<input type=\"hidden\" name=\"b64fileName\"   value=\"{2}\" />");
    strForm.Append("<input type=\"hidden\" name=\"strDocument\"   value=\"{3}\" />");
    strForm.Append("<input type=\"hidden\" name=\"strMetaData\"   value=\"{4}\" />");
    strForm.Append("</form>");
    return String.Format(strForm.ToString()
        , txtTrimURL.Text
        , objBinaryData.Text
        , b64fileName.Text
        , txtTrimRecordType.Text
        , strMetaData.Text);
}
Community
  • 1
  • 1
John Adams
  • 4,773
  • 25
  • 91
  • 131
  • If I understand correctly, you're using the ASP.NET file upload control (which makes a postback). But is it *required* that you use that control? Wouldn't the approach shown in my answer work for your test-page? – M4N Aug 19 '09 at 19:27
  • @Martin - It might work but using the FileUpload control is apparently the "newer" way of doing things and I did not want to rework techniques I already had in place for my original ASP.NET web app. This was an attempt to extend the original web client with an additional BUTTON that would effect the call to the UploadHandler.ashx in the same manner as when POSTed from ColdFusion. I hope that makes sense. Besides, I never learned the "old fashioned way" of uploading without the FileUpload control. – John Adams Aug 20 '09 at 20:42

3 Answers3

0

Sorry if I'm missing something, but can't you simply use a plain HTML form to upload files to your handler:

<form action="UploadHandler.ashx" method="post" enctype="multipart/form-data">
  Choose file to upload:
  <input name="file" type="file" size="50">
</form>
M4N
  • 94,805
  • 45
  • 217
  • 260
  • @Martin - Thanks. I recall trying that some time back but because of this control I could not get the simpler approach you suggest to work (i.e. the FileUpload web control seems to require a postback to itself to set the FileUpload1.PostedFile properties): – John Adams Aug 18 '09 at 23:32
  • Please see my EDIT-UPDATE in the original post. – John Adams Aug 19 '09 at 16:27
  • I'm having difficulty providing a succinct comment but I think this is more complicated than your suggested answer. See the EDIT-UPDATE I made and the answer from Cleiton and my comments. It has to do with this need to "re-POST". – John Adams Aug 19 '09 at 19:44
0

John Galt,

The only way to do what you want is using HttpWebRequest.

Here is good example of a Class that do what you want. I've made to send image and form values to picassa serve sometime ago (I know I could use Picassa API, but I did it for fun).

You only need to pay attention to the 'SendPhoto' function to get hints on what you have to do to make HttpWebRequest to do the work.

Cleiton
  • 17,663
  • 13
  • 46
  • 59
  • @Cleiton - thanks for your input. I followed your link and I see your example. Meanwhile, I think I've also concluded (via another example) that a similar technique of injecting a new form and some Javascript might also work - see: http://www.netomatix.com/Development/PostRequestForm.aspx – John Adams Aug 19 '09 at 19:40
0

What worked for me was to inject a new FORM and some Javascript to submit the FORM to the UploadHandler.ashx. This (for me) was easier to grasp than the HTTPWebRequest technique.

John Adams
  • 4,773
  • 25
  • 91
  • 131