AnneP
AnneP

Reputation: 53

Flask server - C# client - Post image

I'm building a very simple application using Flask as server and C# as client. The server receive an image via HTTP POST request and process it. My server seems to work fine because I tested it both with Postman and a python client. However the POST request with image attached from my C# client cannot be passed to server. I've tested with HttpClient and Restsharp but none worked, the server complains there's no image attached.

Here are my server code:

from flask import Flask, jsonify
from flask import abort
from flask import make_response
from flask import request, Response
from flask import url_for
from werkzeug.utils import secure_filename
import jsonpickle
import numpy as np
import cv2
import os
import json
import io

app = Flask(__name__)
UPLOAD_FOLDER = os.path.basename('uploads')
ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif', 'mp4', '3gp', 'mov'])
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16 MB

@app.route('/upload', methods=['POST'])
def upload():

file = request.files['file']
filename = secure_filename(file.filename)

in_memory_file = io.BytesIO()
file.save(in_memory_file)
data = np.fromstring(in_memory_file.getvalue(), dtype=np.uint8)
color_image_flag = 1
img = cv2.imdecode(data, color_image_flag)

cv2.imwrite("uploads\\" + file.filename, img)

and here are my client code using Restsharp

public void Test()
    {
        var client = new RestClient("http://127.0.0.1:5000/upload");
        var request = new RestRequest(Method.POST);
        request.AddHeader("content-type", "multipart/form-data; boundary=----Boundary");
        request.AddParameter("multipart/form-data; boundary=----Boundary", "------Boundary\r\nContent-Disposition: form-data; name=\"file\"; filename=\"path\"\r\nContent-Type: image/jpeg\r\n\r\n\r\n------Boundary--", ParameterType.RequestBody);
        IRestResponse response = client.Execute(request);
    }

here is client code using HttpClient

public void Upload()
    {
        string path = "path";
        FileInfo fi = new FileInfo(path);
        string fileName = fi.Name;
        byte[] fileContents = File.ReadAllBytes(fi.FullName);

        Uri webService = new Uri(@"http://127.0.0.1:5000/upload");
        HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, webService);
        requestMessage.Headers.ExpectContinue = false;

        MultipartFormDataContent multiPartContent = new MultipartFormDataContent("----MyGreatBoundary");
        ByteArrayContent byteArrayContent = new ByteArrayContent(fileContents);
        byteArrayContent.Headers.Add("Content-Type", "application/octet-stream");
        multiPartContent.Add(byteArrayContent, "this is the name of the content", fileName);
        requestMessage.Content = multiPartContent;

        HttpClient httpClient = new HttpClient();
        Task<HttpResponseMessage> httpRequest = httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseContentRead, CancellationToken.None);
        HttpResponseMessage httpResponse = httpRequest.Result;
    }

Upvotes: 1

Views: 3993

Answers (2)

AnneP
AnneP

Reputation: 53

For those who made the same mistakes, I had to change name argument to file (as Marius suggests) and change byteArrayContent.Headers.Add("Content-Type", "application/octet-stream"); to byteArrayContent.Headers.Add("Content-Type", "multipart/form-data");

Upvotes: 0

Marius
Marius

Reputation: 1679

You need to set the name argument to "file" instead of "this is the name of the content" in your C# code.

multiPartContent.Add(byteArrayContent, "file", "image.jpg");

Here is a stripped down method that does the trick:

public Task<HttpResponseMessage> UploadAsFormDataContent(string url, byte[] image)
{
    MultipartFormDataContent form = new MultipartFormDataContent
    {
        { new ByteArrayContent(image, 0, image.Length), "file", "pic.jpeg" }
    };

    HttpClient client = new HttpClient();
    return client.PostAsync(url, form);
}

Upvotes: 4

Related Questions