Search code examples
c#uploadwebrequest

How to upload a pdf with a multipart-HTML-Post in C#?


Here Upload pdf via multipart-HTML-Post does change file I created some code for uploading a pdf with a multipart-HTML-Post in vba.

This is the code I use:

Public Function sap_addTest(ByVal par_objectID As String, ByVal par_description As String, ByVal par_filename As String) As Integer

  Dim ls_param As String
  Dim text As String
  Dim line As String
  Dim url As String
  Dim web As MSXML2.XMLHTTP60
  url = "http://someurl.xml"


  Set web = CreateObject("MSXML2.XMLHTTP")

  Call web.Open("POST", url, False)
  Const Boundary As String = "AaB03x"
  Call web.setRequestHeader("content-type", "multipart/form-data;boundary=" & Boundary)
  Call web.setRequestHeader("ws-callingapplication", sys_db)
  Call web.setRequestHeader("Connection", "Keep-Alive")
  Call web.setRequestHeader("cache-control", "no-cache")

  Dim baBuffer() As Byte

  Dim bytData
  Dim bytPayLoad

  With CreateObject("ADODB.Stream")
       .Type = 1
       .Mode = 3
       .Open
       .LoadFromFile par_filename
       bytData = .Read
   End With

   With CreateObject("ADODB.Stream")
      .Mode = 3
      .Charset = "Windows-1252"
      .Open
      .Type = 2
      .WriteText vbNewLine & "--" & Boundary & vbNewLine & "Content-Disposition: form-data; name=""object_id""" & vbNewLine & vbNewLine & par_objectID
      .WriteText vbNewLine & "--" & Boundary & vbNewLine & "Content-Disposition: form-data; name=""description""" & vbNewLine & vbNewLine & par_description
      .WriteText vbNewLine & "--" & Boundary & vbNewLine & "Content-Disposition: form-data; name=""file""; filename=""" & par_filename & """" & vbNewLine
      .WriteText vbNewLine
      .Position = 0
      .Type = 1
      .Position = .Size
      .Write bytData
      .Position = 0
      .Type = 2
      .Position = .Size
      .WriteText vbNewLine & vbNewLine & "--" & Boundary & "--" & vbNewLine
      .Position = 0
      .Type = 1
      bytPayLoad = .Read
  End With

  Call web.Send(bytPayLoad)

  'Debug.Print web.status
  'Debug.Print web.responseText

End Function

But now I have to do the same thing in C#. I probably use HttpWebRequest instead of XMLHTTP. But my problem is how to replace the ADODB.Stream? System.IO.Stream does not seem to have the functions/properties I use (Mode, Type, WriteText, charset). This is the code I use right now:

public void Upload(ICommandLineInfo info)
{
    var webRequest = HttpWebRequest.Create(info.Url) as HttpWebRequest;
    const string HTTPBoundary = "AaB03x";
    webRequest.ContentType = "multipart/form-data;boundary=" + HTTPBoundary;
    const string HTTPHeaderCallingApplicationName = "ws-callingapplication";

    webRequest.Headers.Add(HTTPHeaderCallingApplicationName, info.CallingApplication);
    webRequest.KeepAlive = true;

    const string HTTPHeaderCacheControlName = "cache-control";
    const string HTTPHeaderValueCacheControlNo = "no-cache";
    webRequest.Headers.Add(HTTPHeaderCacheControlName, HTTPHeaderValueCacheControlNo);
    webRequest.Method = "POST";

    using (Stream requestStream = webRequest.GetRequestStream())
    {
        //Here I dont know how to write my file into the Request stream
        //requestStream.Write(bytes, 0, bytes.Length); ?
        requestStream.Close();
    }


    var response = (HttpWebResponse)webRequest.GetResponse();   
}

I found this multipart post -- uploading a file to, but the code is Java and there are several pieces missing in C# (like HttpPost, MultipartEntityBuilder and so on)

So how to build the byte array for the request stream?

Update:

This is the code I use currently:

public void Upload(ICommandLineInfo info)
{
    var webRequest = HttpWebRequest.Create(info.Url) as HttpWebRequest;
    const string HTTPBoundary = "AaB03x";
    webRequest.ContentType = "multipart/form-data;boundary=" + HTTPBoundary;
    const string HTTPHeaderCallingApplicationName = "ws-callingapplication";

    webRequest.Headers.Add(HTTPHeaderCallingApplicationName, info.CallingApplication);
    webRequest.KeepAlive = true;

    webRequest.UseDefaultCredentials = true;
    webRequest.PreAuthenticate = true;
    webRequest.Credentials = CredentialCache.DefaultCredentials;

    const string HTTPHeaderCacheControlName = "cache-control";
    const string HTTPHeaderValueCacheControlNo = "no-cache";
    webRequest.Headers.Add(HTTPHeaderCacheControlName, HTTPHeaderValueCacheControlNo);
    webRequest.Method = "POST";

    Stream requestStream = webRequest.GetRequestStream();
    string stringInfo = "";
    stringInfo = stringInfo + Environment.NewLine + "--" + HTTPBoundary + Environment.NewLine + "Content-Disposition: form-data; name=\"itemName\"" + Environment.NewLine + Path.GetFileName(info.Filename);
    stringInfo = stringInfo + Environment.NewLine + "--" + HTTPBoundary + Environment.NewLine + "Content-Disposition: form-data; name=\"parentNickname\"" + Environment.NewLine + info.ParentNickname;
    stringInfo = stringInfo + Environment.NewLine + "--" + HTTPBoundary + Environment.NewLine + "Content-Disposition: form-data; name=\"file\"; filename=\"" + info.Filename + "\"" + Environment.NewLine + Environment.NewLine;
    var stringBytes = Encoding.ASCII.GetBytes(stringInfo);
    requestStream.Write(stringBytes, 0, stringBytes.Length);

    var fileBytes = File.ReadAllBytes(info.Filename);

    requestStream.Write(stringBytes, 0, stringBytes.Length);

    string endInfo = Environment.NewLine+ Environment.NewLine + "--" + HTTPBoundary + "--" + Environment.NewLine;

    var endBytes = Encoding.ASCII.GetBytes(endInfo);
    requestStream.Write(endBytes, 0, endBytes.Length);
    requestStream.Flush();
    requestStream.Close();

    var response = (HttpWebResponse)webRequest.GetResponse();

}

unfortunately webRequest.GetResponse() throws an exception:

The remoteserver returned an error. 500: Internal server error

My college - who is responsible for the serverpart - tells me that he gets an "unexpected end of stream"-error.


Solution

  • It seems like there is a ADODB Stream in c# also. In the Reference: "ADODB". So my final Code lookes like this:

    public void Upload(ICommandLineInfo info)
    {
        var webRequest = HttpWebRequest.Create(info.Url) as HttpWebRequest;
        const string HTTPBoundary = "AaB03x";
        webRequest.ContentType = "multipart/form-data;boundary=" + HTTPBoundary;
        const string HTTPHeaderCallingApplicationName = "ws-callingapplication";
    
        webRequest.Headers.Add(HTTPHeaderCallingApplicationName, info.CallingApplication);
        webRequest.KeepAlive = true;
    
        webRequest.UseDefaultCredentials = true;
        webRequest.PreAuthenticate = true;
        webRequest.Credentials = CredentialCache.DefaultCredentials;
    
        const string HTTPHeaderCacheControlName = "cache-control";
        const string HTTPHeaderValueCacheControlNo = "no-cache";
        webRequest.Headers.Add(HTTPHeaderCacheControlName, HTTPHeaderValueCacheControlNo);
        webRequest.Method = "POST";
    
        ADODB.Stream fileStream = new ADODB.Stream();
        fileStream.Type = ADODB.StreamTypeEnum.adTypeBinary;
        fileStream.Mode = ADODB.ConnectModeEnum.adModeReadWrite;
        fileStream.Open();
        fileStream.LoadFromFile(info.Filename);
        var byteData = fileStream.Read();
        fileStream.Close();
    
        ADODB.Stream mixedStream = new ADODB.Stream();
        mixedStream.Mode = ADODB.ConnectModeEnum.adModeReadWrite;
        mixedStream.Charset = "utf-8";
        mixedStream.Open();
        mixedStream.Type = ADODB.StreamTypeEnum.adTypeText;
        mixedStream.WriteText(Environment.NewLine + "--" + HTTPBoundary + Environment.NewLine + "Content-Disposition: form-data; name=\"itemName\"" + Environment.NewLine + Environment.NewLine + Path.GetFileName(info.Filename));
        mixedStream.WriteText(Environment.NewLine + "--" + HTTPBoundary + Environment.NewLine + "Content-Disposition: form-data; name=\"parentNickname\"" + Environment.NewLine + Environment.NewLine + info.ParentNickname);
        mixedStream.WriteText(Environment.NewLine + "--" + HTTPBoundary + Environment.NewLine + "Content-Disposition: form-data; name=\"file\"; filename=\"" + info.Filename + "\"" + Environment.NewLine);
        mixedStream.WriteText(Environment.NewLine);
        mixedStream.Position = 0;
        mixedStream.Type = ADODB.StreamTypeEnum.adTypeBinary;
        mixedStream.Position = mixedStream.Size;
        mixedStream.Write(byteData);
        byteData = null;
        mixedStream.Position = 0;
        mixedStream.Type = ADODB.StreamTypeEnum.adTypeText;
        mixedStream.Position = mixedStream.Size;
        mixedStream.WriteText(Environment.NewLine + Environment.NewLine + "--" + HTTPBoundary + "--" + Environment.NewLine);
        mixedStream.Position = 0;
        mixedStream.Type = ADODB.StreamTypeEnum.adTypeBinary;
    
        var read = mixedStream.Read();
        webRequest.ContentLength = read.Length;
        Stream requestStream = webRequest.GetRequestStream();
    
        requestStream.Write(read, 0, read.Length);
        requestStream.Close();
        try
        {
            var response = (HttpWebResponse)webRequest.GetResponse();
        }
        catch (WebException exception)
        {
            using (var reader = new System.IO.StreamReader(exception.Response.GetResponseStream()))
            {
                string responseText = reader.ReadToEnd();
            }
        }
    }
    

    This seems to be not the perfect way to do this in C# but it works.