I have a test Azure Function end point defined as follows:
public async Task<HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "projects")] HttpRequestData req)
{
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
if (string.IsNullOrWhiteSpace(requestBody))
{
// Return bad request
}
// Do something
}
From the client app (ran via NUnit), if I call
var dtoClient = new DtoClient(p1, p2, etc);
var response = await _httpClient.PostAsJsonAsync("api/MyAzureFunctionPath", dtoClient);
I get a bad request.
If I call
var dtoClient = new DtoClient(p1, p2, etc);
var content = new StringContent(JsonConvert.SerializeObject(dtoClient), System.Text.Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync("api/copilot/projects", content);`
I get a success.
Is PostAsJsonAsync
broken? How is it possible that it does not work within the Microsoft ecosystem? I must be missing something.
I have read here that this is because the httpClient sets the content size to 0. So is this a bug? Should I simply avoid using PostAsJsonAsync
or should I learn how to use it properly?
5
I tried the below HTTP trigger function code with the Test code using PostAsJsonAsync. The test cases passed successfully.
Code :
Function1.cs :
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs;
namespace FunctionApp2
{
public class Function1
{
[FunctionName("projects")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "projects")] HttpRequest req)
{
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
if (string.IsNullOrWhiteSpace(requestBody))
{
return new BadRequestObjectResult("Request body cannot be empty.");
}
var dtoClient = JsonConvert.DeserializeObject<DtoClient>(requestBody);
return new OkObjectResult(dtoClient);
}
}
public class DtoClient
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
}
UnitTest1.cs :
using System.Text;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using System.Net;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Azure.WebJobs;
using Microsoft.AspNetCore.Http;
namespace FunctionApp2.Tests
{
public class Function1Tests : IDisposable
{
private HttpClient _client;
private TestServer _server;
public Function1Tests()
{
var builder = new WebHostBuilder()
.ConfigureServices(services =>
{
services.AddMvc().AddApplicationPart(typeof(Function1).Assembly);
})
.Configure(app =>
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapFunctionRoutes();
});
});
_server = new TestServer(builder);
_client = _server.CreateClient();
}
[Test]
public async Task PostProjects_ReturnsOkResult()
{
var dtoClient = new DtoClient
{
Property1 = "Value1",
Property2 = "Value2"
};
var response = await _client.PostAsJsonAsync("/projects", dtoClient);
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.IsNotNull(response.Content);
}
[TearDown]
public void TearDown()
{
_client.Dispose();
}
public void Dispose()
{
TearDown();
}
}
public static class HttpClientExtensions
{
public static Task<HttpResponseMessage> PostAsJsonAsync<T>(this HttpClient client1, string url1, T data)
{
var json = JsonConvert.SerializeObject(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
return client1.PostAsync(url1, content);
}
}
public static class EndpointRouteBuilderExtensions
{
public static void MapFunctionRoutes(this IEndpointRouteBuilder endpoints)
{
endpoints.MapPost("/projects", async context =>
{
string requestBody;
using (var reader = new StreamReader(context.Request.Body))
{
requestBody = await reader.ReadToEndAsync();
}
if (string.IsNullOrWhiteSpace(requestBody))
{
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
await context.Response.WriteAsync("Request body cannot be empty.");
return;
}
var dtoClient = JsonConvert.DeserializeObject<DtoClient>(requestBody);
context.Response.StatusCode = (int)HttpStatusCode.OK;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(JsonConvert.SerializeObject(dtoClient));
}).WithMetadata(new FunctionNameAttribute("projects"));
}
}
}
Postman Output :
I sent the post request with below json in the Postman as shown below,
{
"Property1": "Value1",
"Property2": "Value2"
}
Terminal Output :
The following HTTP trigger function code ran successfully as below,
Test case Output :
The following Test code ran successfully as below.
1