1

I am trying to create a POST request with Content-Type: Multipart/mixed in C# .NET
Refer this

So far I have tried to build a POST req of HttpRequestMessage type and add it to a MultipartContent instance, but MultipartContent.add() method does not accept HttpRequestMessage type

How do I add http requests to multipart/mixed request in .NET 5.0.0 preview-7?

Anant_Kumar
  • 764
  • 1
  • 7
  • 23
  • Does this answer your question? [C# HttpClient 4.5 multipart/form-data upload](https://stackoverflow.com/questions/16416601/c-sharp-httpclient-4-5-multipart-form-data-upload) – Neil Aug 18 '20 at 21:10

1 Answers1

4

I think it can look like this but I can't test because I don't have a suitable server.

C# 8.0, .NET Core 3.1 Console App (compartible with .NET 5)

class Program
{
    private static readonly HttpClient client = new HttpClient();

    static async Task Main(string[] args)
    {
        string textPlain = "Hello World!";
        string textJson = "{ \"message\" : \"Hello World!\" }";

        using MixedContentList contentList = new MixedContentList
        {
            new StringContent(textPlain, Encoding.UTF8, "text/plain"),
            new StringContent(textJson, Encoding.UTF8, "application/json")
        };

        using Stream fileStream = File.OpenRead("pic1.jpg");
        HttpContent streamContent = new StreamContent(fileStream);
        streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { FileName = "pic1.jpg" };
        streamContent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
        contentList.Add(streamContent);

        try
        {
            string result = await PostMixedContentAsync("https://myserver.url", contentList);
            // success, handle result
            Console.WriteLine(result);
        }
        catch (Exception ex)
        {
            // failure
            Console.WriteLine(ex.Message);
        }
        Console.ReadKey();
    }

    private static async Task<string> PostMixedContentAsync(string url, MixedContentList contentList)
    {
        using MultipartContent mixedContent = new MultipartContent();
        foreach (HttpContent content in contentList)
        {
            mixedContent.Add(content);
        }
        using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url);
        request.Content = mixedContent;

        //Console.WriteLine(request.ToString());
        //Console.WriteLine(await mixedContent.ReadAsStringAsync());
        //return "ok";

        using HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadAsStringAsync();
    }
}

public class MixedContentList : List<HttpContent>, IDisposable
{
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private bool disposed;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                foreach (HttpContent content in this)
                {
                    content?.Dispose();
                }
                Clear();
            }
            disposed = true;
        }
    }
}

Output with uncommented debug code

Method: POST, RequestUri: 'https://myserver.url/', Version: 1.1, Content: System.Net.Http.MultipartContent, Headers:
{
  Content-Type: multipart/mixed; boundary="3e48b0d7-82c0-4d64-9946-b6eadae9c7d6"
}
--3e48b0d7-82c0-4d64-9946-b6eadae9c7d6
Content-Type: text/plain; charset=utf-8

Hello World!
--3e48b0d7-82c0-4d64-9946-b6eadae9c7d6
Content-Type: application/json; charset=utf-8

{ "message" : "Hello World!" }
--3e48b0d7-82c0-4d64-9946-b6eadae9c7d6
Content-Disposition: form-data; filename=pic1.jpg
Content-Type: image/jpeg

<JPEG BINARY DATA HERE>
--3e48b0d7-82c0-4d64-9946-b6eadae9c7d6--

Update

As MultipartContent doesn't support application/http, you may implement own Content derived from HttpContent e.g. named BatchContent, that can produce application/http consisting of MultipartContent. The target is get the desired ReadAsStringAsync() output.

Note that the Batch can bind you to HTTP/1.1 and will not support HTTP/2. Or think about it in advance.

aepot
  • 4,558
  • 2
  • 12
  • 24
  • the `multipart/mixed` request you built does not contain another Http request in the body like the link provided in the question – Anant_Kumar Aug 19 '20 at 06:14
  • 1
    @Anant_Kumar ah, sorry. I've missed that. Looks like that's not possible. But you may implement your own [`HttpRequestMessage`](https://github.com/dotnet/runtime/blob/master/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestMessage.cs) that accepts multiple request messages. But why not send those `POST` requests separately? – aepot Aug 19 '20 at 07:28
  • If you could update the answer that Http request is not possible in MultipartContent, I would accept it as answer. I want to bundle multiple Http requests in one batch (check link in question) – Anant_Kumar Aug 19 '20 at 07:39
  • @Anant_Kumar I have the better idea, not implement `HttpRequestMessage`, it may be too complicated but `HttpContent` e.g. named `BatchContent`, that accepts `application/http` type consisting of `MultipartContent`. The target is get the desired `ReadAsStringAsync()` output. – aepot Aug 19 '20 at 07:49
  • @Anant_Kumar _I want to bundle multiple Http requests in one batch (check link in question)_ I see that but why do you need that? – aepot Aug 19 '20 at 07:57
  • 1
    I want to bundle multiple operations into a single request so that the CDS make them as an atomic transaction – Anant_Kumar Aug 19 '20 at 08:03
  • @Anant_Kumar makes sense. You may also create JSON request model containing multiple operations, bundling requests inside the json, not as `multipart`. Then it can be sent as a single POST request. – aepot Aug 19 '20 at 08:09
  • 1
    @Anant_Kumar Note that the Batch can bind you to `HTTP/1.1` and will not support `HTTP/2`. Or think about it in advance. – aepot Aug 19 '20 at 08:18