0

I coded the handler:

using System;
using System.Net;
using System.Web;

namespace Teste
{
    public class Exemplo : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            context.Response.Clear();
            context.Response.StatusCode = (int)HttpStatusCode.OK;

            string boundary = CreateFormDataBoundary();
            context.Response.ContentType = "multipart/form-data; boundary=" + boundary;
            //context.Response.ContentType = "plain/text";
            context.Response.ContentEncoding = System.Text.Encoding.UTF8;

            context.Response.Headers.Add("X-data", "21-08-2017");
            context.Response.Headers.Add("X-numberfiles", "2");
            context.Response.Headers.Add("X-Id", "45625625EFA22AD");

            string[] files = new string[] { @"C:\Exemplo\Ficheiros\Fich1.txt", @"C:\Exemplo\Ficheiros\Fich2.txt" };

            string result = "";
            foreach (string f in files)
            {
                result = result + WriteFilePart(boundary, f);
            }
            result = result + Environment.NewLine + "--" + boundary;
            context.Response.Write(result);
        }
        private string CreateFormDataBoundary()
        {
            return "---------------------------" + DateTime.Now.Ticks.ToString("x");
        }
        private string WriteFilePart(string boundary, string FileName)
        {
            //Write boundary with file multipart header.
            string Tosend = "";
            Tosend = Tosend + Environment.NewLine + "--" + boundary + Environment.NewLine;
            Tosend = Tosend + "Content-Type: " + "text/plain" + "" + Environment.NewLine;
            Tosend = Tosend + "Content-Location: " + FileName + "" + Environment.NewLine;
            Tosend = Tosend + "Content-Disposition: attachment; filename=\"" + FileName + "\"" + Environment.NewLine;
            Tosend = Tosend + "Content-ID: " + FileName + "" + Environment.NewLine;
            Tosend = Tosend + Environment.NewLine;

            Tosend = Tosend + Environment.NewLine;
            var reader = new System.IO.StreamReader(FileName);
            var data = reader.ReadToEnd();
            var dataBinary = System.Text.Encoding.UTF8.GetBytes(data);
            Tosend = Tosend + System.Text.Encoding.UTF8.GetString(dataBinary);
            Tosend = Tosend + Environment.NewLine;

            return Tosend;
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

If i use context.Response.ContentType = "multipart/form-data; boundary=" + boundary; which is what is supposed to happen i get fiddler response (fiddler says that there is no response body):

    HTTP/1.1 200 OK
Cache-Control: private
Content-Type: multipart/form-data; boundary=---------------------------8d5bf0fdc7ec8f6; charset=utf-8
Server: Microsoft-IIS/10.0
X-data: 21-08-2017
X-numberfiles: 2
X-Id: 45625625EFA22AD
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcQ2VydGlmaWNhw6fDo29TQVBcQ2VydGlmaWNhY2FvU0FQX3YxXFNBUENlcnRcVGVzdGUxXEV4ZW1wbG8uYXNoeA==?=
X-Powered-By: ASP.NET
Date: Mon, 21 May 2018 10:41:58 GMT
Content-Length: 581

If i use context.Response.ContentType = "plain/text" i get fiddler response that would expect to receive with multipart:

    HTTP/1.1 200 OK
Cache-Control: private
Content-Type: plain/text; charset=utf-8
Server: Microsoft-IIS/10.0
X-data: 21-08-2017
X-numberfiles: 2
X-Id: 45625625EFA22AD
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcQ2VydGlmaWNhw6fDo29TQVBcQ2VydGlmaWNhY2FvU0FQX3YxXFNBUENlcnRcVGVzdGUxXEV4ZW1wbG8uYXNoeA==?=
X-Powered-By: ASP.NET
Date: Mon, 21 May 2018 10:40:37 GMT
Content-Length: 581


-----------------------------8d5bf0fac25e36f
Content-Type: text/plain
Content-Location: C:\Exemplo\Ficheiros\Fich1.txt
Content-Disposition: attachment; filename="C:\Exemplo\Ficheiros\Fich1.txt"
Content-ID: C:\Exemplo\Ficheiros\Fich1.txt


Nome:joao
Idade:53

-----------------------------8d5bf0fac25e36f
Content-Type: text/plain
Content-Location: C:\Exemplo\Ficheiros\Fich2.txt
Content-Disposition: attachment; filename="C:\Exemplo\Ficheiros\Fich2.txt"
Content-ID: C:\Exemplo\Ficheiros\Fich2.txt


Dados Adicionais

-----------------------------8d5bf0fac25e36f

The specification clearly says that the response should be multipart/form-data. Why can't i obtain the body when use multipart/form-data? The final result should be the response obtained with plain/text but with context.Response.ContentType = "multipart/form-data;. What am i doing wrong?

Tkx

When i tried to use System.Net.Http.MultipartFormDataContent as content in context.Response.Write(result); fiddler shows System.Net.Http.MultipartFormDataContent as the body

Following Liam suggestion changed the code for:

        public void ProcessRequest(HttpContext context)
    {
        context.Response.Clear();
        context.Response.StatusCode = (int)HttpStatusCode.OK;

        string boundary = CreateFormDataBoundary();
        context.Response.ContentType = "multipart/mixed; boundary=" + boundary;
        //context.Response.ContentType = "plain/text";
        context.Response.ContentEncoding = System.Text.Encoding.UTF8;

        context.Response.Headers.Add("X-data", "21-08-2017");
        context.Response.Headers.Add("X-numberfiles", "2");
        context.Response.Headers.Add("X-Id", "45625625EFA22AD");

        string[] files = new string[] { @"C:\Exemplo\Ficheiros\Fich1.txt", @"C:\Exemplo\Ficheiros\Fich2.txt" };

        //string result = "";
        //foreach (string f in files)
        //{
        //    result = result + WriteFilePart(boundary, f);
        //}
        //result = result + Environment.NewLine + "--" + boundary;
        //StringContent a = (result);

        //HttpContent stringContent = new StringContent(result);
        ProcessRequestM(context);
        //context.Response.Write();
    }
    public void ProcessRequestM(HttpContext context)
    {
        Stream fileStream1 = File.OpenRead(@"C:\Exemplo\Ficheiros\Fich1.txt");
        Stream fileStream2 = File.OpenRead(@"C:\Exemplo\Ficheiros\Fich2.txt");

        HttpContent stringContent = new StringContent("parametro");
        HttpContent fileStreamContent1 = new StreamContent(fileStream1);
        HttpContent fileStreamContent2 = new StreamContent(fileStream2);
        //HttpContent bytesContent = new ByteArrayContent(paramFileBytes);
        using (var client = new HttpClient())
        using (var formData = new MultipartFormDataContent())
        {
            formData.Add(stringContent, "param1", "param1");
            formData.Add(fileStreamContent1, "file1", "file1");
            formData.Add(stringContent, "param2", "param2");
            formData.Add(stringContent, "param2", "param2");
            formData.Add(fileStreamContent2, "file2", "file2");
            context.Response.Write(formData);
        }
    }

Fiddler response:

    HTTP/1.1 200 OK
Cache-Control: private
Content-Type: multipart/mixed; boundary=---------------------------8d5bf354c77d23a; charset=utf-8
Server: Microsoft-IIS/10.0
X-data: 21-08-2017
X-numberfiles: 2
X-Id: 45625625EFA22AD
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcQ2VydGlmaWNhw6fDo29TQVBcQ2VydGlmaWNhY2FvU0FQX3YxXFNBUENlcnRcVGVzdGUxXEV4ZW1wbG8uYXNoeA==?=
X-Powered-By: ASP.NET
Date: Mon, 21 May 2018 15:09:57 GMT
Content-Length: 40

System.Net.Http.MultipartFormDataContent

Getting desperate

Henrique
  • 51
  • 1
  • 7
  • Possible duplicate of [Send a file via HTTP POST with C#](https://stackoverflow.com/questions/1131425/send-a-file-via-http-post-with-c-sharp) – Liam May 21 '18 at 11:06
  • 1
    `MultipartFormDataContent` and `HttpClient` will do all this for you without trying to handcraft the HTTP content as a string – Liam May 21 '18 at 11:07
  • Hi, Liam, Why doesn't this approach works? How should i use MultipartFormDataContent – Henrique May 21 '18 at 12:31
  • What exactly are you trying to achieve here? Showing the string representation of your HTTP and just saying this is wrong, isn't very helpful. HTTP can be pretty complicated and unforgiving protocol. I'm guessing there's more to this than just wanting to [send a file using HTTP](https://stackoverflow.com/a/1131432/542251)? Did you see the ["more complex" example in that answer](https://stackoverflow.com/a/2996904/542251)? – Liam May 21 '18 at 15:26
  • Don't forget that what you see in fiddler is just part of the picture, HTTP is wrapped in TCP packets, can be chunked, etc. It's not just a string that gets sentz over the internetz – Liam May 21 '18 at 15:28
  • It's an external application that requests the files. I have no control or knowledge over this. The only specification i have is to responde (via httphandler) as a multipart message. There is a header in the message and some extra fields with the files (as you can see in the example). If Fiddler can be incomplete how can i see the whole message? – Henrique May 21 '18 at 15:42
  • Wait up, your writing `context.Response.Write(formData);` that's wrong, read the [duplicate again](https://stackoverflow.com/a/19664927/542251), `client.PostAsync(actionUrl, formData)` you can't just write the `formdata` **object** to the response, that just calls `ToString()` on it, hence the string `System.Net.Http.MultipartFormDataContent`. You really need to stop trying to write a HTTP string, you need to **stream** the file into the HTTP – Liam May 21 '18 at 15:49
  • Some more info [How does HTTP file upload work?](https://stackoverflow.com/questions/8659808/how-does-http-file-upload-work) – Liam May 21 '18 at 15:53
  • I get from client http://blablabla/example.ashx?Files=2&id=1111&id=4444 – Henrique May 21 '18 at 17:39
  • I get from client http://blablabla/example.ashx?Files=2&id=1111&id=4444. I go to Database, get files and values and want to post to client. From what i understand (i'm sql server. no experience in ashx) i'm returning an invalid format to the client. I need to create a request in the ProcessRequest method?? Can i Just convert formData to a stream?? I shouldn't be using context.Response.Write()? – Henrique May 21 '18 at 17:49

2 Answers2

1

What i was unable to explain is that i am the server. I only see the request i do not create it so the methods sugested do not apply. How i did it:

        public resp(HttpContext context)
    {
        context.Response.Clear();
        context.Response.StatusCode = (int)HttpStatusCode.OK;

        string formDataBoundary = String.Format("----------{0:N}", DateTime.Now.Ticks.ToString("x"));
        context.Response.ContentType = "multipart/form-data; boundary=" + formDataBoundary;
        context.Response.ContentEncoding = System.Text.Encoding.UTF8;

        context.Response.Headers.Add("X-data", "21-08-2017");
        context.Response.Headers.Add("X-numberfiles", "2");
        context.Response.Headers.Add("X-Id", "45625625EFA22AD");

        string[] files = new string[] { @"C:\Exemplo\Ficheiros\Fich1.txt", @"C:\Exemplo\Ficheiros\Fich2.txt" };
        Stream memStream = new MemoryStream();
        var boundarybytes = System.Text.Encoding.UTF8.GetBytes("--" + formDataBoundary + "\r\n");
        var endBoundaryBytes = System.Text.Encoding.UTF8.GetBytes("\r\n--" + formDataBoundary + "--");

        foreach (var FileName in files)
        {
            WriteFilePart(context, FileName, boundarybytes, memStream);
            boundarybytes = System.Text.Encoding.UTF8.GetBytes("\r\n--" + formDataBoundary + "\r\n");
        }

        memStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);

        using (Stream ResponseStream = context.Response.OutputStream)
        {
            memStream.Position = 0;
            byte[] tempBuffer = new byte[memStream.Length];
            memStream.Read(tempBuffer, 0, tempBuffer.Length);
            memStream.Close();
            ResponseStream.Write(tempBuffer, 0, tempBuffer.Length);
        }


    }
    private string WriteFilePart(HttpContext context, string FileName, byte[] boundarybytes, Stream memStream)
        {

            string Tosend = "";
            Tosend = Tosend + "Content-Type: " + "text/plain" + "" + Environment.NewLine;
            Tosend = Tosend + "Content-Location: " + FileName + "" + Environment.NewLine;
            Tosend = Tosend + "Content-Disposition: attachment; filename=\"" + FileName + "\"" + Environment.NewLine;
            Tosend = Tosend + "Content-ID: " + FileName + "" + Environment.NewLine;
            Tosend = Tosend + Environment.NewLine;

            memStream.Write(boundarybytes, 0, boundarybytes.Length);
            var headerbytes = System.Text.Encoding.UTF8.GetBytes(Tosend);
            memStream.Write(headerbytes, 0, headerbytes.Length);

            var filebyte = MultipartParser.Parse.FileToByteArray(FileName);  //converts file to byte[]
            memStream.Write(filebyte, 0, filebyte.Length);

        }
Henrique
  • 51
  • 1
  • 7
0
    public async Task SendMultiPart()
    {
        string formDataBoundary = String.Format("----------{0:N}", DateTime.Now.Ticks.ToString("x"));
        HttpContext.Response.ContentType = "multipart/form-data; boundary=" + formDataBoundary;

        var mp = GetMultipart(formDataBoundary);
        await mp.CopyToAsync(HttpContext.Response.Body);
    }

    public MultipartFormDataContent GetMultipart(string formDataBoundary)
    {
        var file_bytes = System.IO.File.ReadAllBytes(Path.Combine("files", "file.txt"));

        var formData = new MultipartFormDataContent(formDataBoundary);
        formData.Add(new StringContent("Ahalay"), "username");
        formData.Add(new ByteArrayContent(file_bytes, 0, file_bytes.Length), "profile_pic", "free.png");
        return formData;
    }
KhanKhad
  • 1
  • 1