1

I'm developing an ASP.NET Web Api 2 with C# and .NET Framework 4.7.

I'm trying to upload a file to the web api using a HttpClient instance.

I have added this to Web.Config:

<httpRuntime targetFramework="4.7" maxRequestLength="1048576" />

[ ... ]

<location path="ProductionOrderApi">
  <system.web>
    <httpRuntime executionTimeout="120" maxRequestLength="81920" />
  </system.web>
</location>

[ ... ]

<security>
  <requestFiltering>
    <requestLimits maxAllowedContentLength="1073741824" />
  </requestFiltering>
</security>

This is the web api method:

[HttpPost]
[Route("api/ProductionOrder/{productionOrderName}/Processed")]
public HttpResponseMessage UploadProductionOrderProcessed(
    string productionOrderName,
    byte[] jsonData)
{
    HttpResponseMessage response = null;

    try
    {
        Data.ProductionOrder po = repository
            .SearchFor(p => string.Equals(p.Name, productionOrderName) &&
                        p.Phase == (byte)Phase.Processed)
            .FirstOrDefault();

        if (po == null)
            response = Request.CreateResponse(HttpStatusCode.InternalServerError);
        else
        {
            string json = Encoding.ASCII.GetString(jsonData);

            StoredProcedureErrors error = 
                StoredProcedures.LoadProcessedBatch(connectionString, json);

            if (error == StoredProcedureErrors.NoError)
                response = Request.CreateResponse(HttpStatusCode.Created);
            else
            {
                response = Request.CreateResponse(HttpStatusCode.InternalServerError);

                exceptionLogger.LogMessage(
                    this.GetType().Name,
                    System.Reflection.MethodBase.GetCurrentMethod().Name,
                    "Database error: " + error);
            }
        }
    }
    catch (Exception ex)
    {
        exceptionLogger.LogCompleteException(
            this.GetType().Name,
            System.Reflection.MethodBase.GetCurrentMethod().Name,
            ex);

        response = Request.CreateResponse(HttpStatusCode.InternalServerError);
    }

    return response;
}

This is client to make the call:

public bool UploadProcessedBatch(string productionOrderName, byte[] jsonData)
{
    string completeUri = string.Format(UploadProcessedBatchUri, productionOrderName);

    return Post<byte[]>(completeUri, jsonData);
}

protected bool Post<T>(string completeUri, T dataToPost)
{
    if (EqualityComparer<T>.Default.Equals(dataToPost, default(T)))
        throw new ArgumentNullException("dataToPost");

    bool result = false;

    using (var client = new HttpClient())
    {
        client.BaseAddress = new Uri(_webApiHost);
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        HttpContent content = new StringContent(JsonConvert.SerializeObject(dataToPost), Encoding.UTF8, "application/json");
        Task<HttpResponseMessage> response = client.PostAsync(completeUri, content);
        HttpResponseMessage message = response.Result;

        result = (message.StatusCode == HttpStatusCode.Created);

        LatestStatusCode = message.StatusCode;
        ReasonPhrase = message.ReasonPhrase;
    }

    return result;
}

If I make a call with PostMan without posting any jsonData it receives the call, but when I make a call with any jsonData it doesn't call it (I have a breakpoint at first line in Web Api method): I get an exception saying "Cancelled task" with anything else useful.

The file I'm trying to upload it is big (more than 7 MB).

Any idea about what is it happening?

I think the problem is how I sending the data. All the examples that I have found are about sending the data with a Html form but I haven't found anything about how to send it with a HttpClient.

VansFannel
  • 45,055
  • 107
  • 359
  • 626
  • "it doesn't call it" - but what is the response? There should be some error response (404 or something else). – Evk Mar 02 '18 at 12:37
  • @Evk I get an exception saying "Cancelled task" with anything else useful. – VansFannel Mar 02 '18 at 12:44
  • It's not very efficient to send files like this. Better use multipart content or pass some parameters in url (like `productionOrderName`) and pass file in response body. – Evk Mar 02 '18 at 13:57

1 Answers1

1

Edit:

So since Web Api 2.1 it is possible to use BSON, a "JSON-like" Format, which is able to send binary formatted data. In the linked Article you'll even find an example using HttpClient.

Before the Introduction of BSON a common way around the limitation of JSON has been to encode the binary as base64.

Orig:

The short of it is you can't simply send a byte[] as a Json Property.

Possible work-arounds are:

  1. Base64 parsing at Client/Server
  2. Another possibility that i haven't been aware of until now is BSON. Look at the official Docs and this Thread for more info.

Maybe someone else has something to add to that list.

Cheers,

Severin Jaeschke
  • 661
  • 7
  • 22
  • Yes, I think the problem is how I sending the data. All the examples that I have found are about sending the data with a Html form but I haven't found anything about how to send it with a HttpClient. Thanks. – VansFannel Mar 02 '18 at 13:01
  • Then looking into BSON might be interesting for you. As pointed out I wasn't aware about that and only now looking it up. On the other hand base64 is a widely used encoding which you can use moreoften than not 'out-of-the-box'. It's easy to use but has a lot of overhead. – Severin Jaeschke Mar 02 '18 at 13:05