2

I've build a very simple, vanilla minimal API with .NET 6. All I'm trying to do for now is prove that I can receive HTTP POST requests and log them. Hopefully if I can get this working I'll start doing something more interesting, but even this vanilla out of the box functionality isn't working.

Some things I've tried:

  • Changing my logMessage to a record
  • Adding a default constructor to the logMessage

My full code is posted below, can anyone see what is wrong with this? Or how to fix it?

My minimal API:

using Microsoft.AspNetCore.Http.Json;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// NOTE: tried the below but it made no difference. Commented back out.
// builder.Services.Configure<JsonOptions>(options =>
// {
//     options.SerializerOptions.IncludeFields = true;
// });


var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

var summaries = new[]
{
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

app.MapGet("/weatherforecast", () =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
       new WeatherForecast
       (
           DateTime.Now.AddDays(index),
           Random.Shared.Next(-20, 55),
           summaries[Random.Shared.Next(summaries.Length)]
       ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast");

app.MapPost("/", (logMessage message) => 
{
    Console.WriteLine($"[{DateTime.Now.ToShortDateString()}] Received message:");
    Console.WriteLine(message.LogMessage);
    return Results.Accepted;
});

app.Run("http://localhost:5025");

internal record WeatherForecast(DateTime Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

public class logMessage
{
    public string? LogMessage {get;set;}
}

My post message (testing from Postman, but also tried sending from various other places):

{
    "LogMessage":"test"
}

The result:

System.NotSupportedException: Serialization and deserialization of 'System.Type' instances are not supported. Path: $.Method.ReturnParameter.Member.DeclaringType.
 ---> System.NotSupportedException: Serialization and deserialization of 'System.Type' instances are not supported.
   at System.Text.Json.Serialization.Converters.UnsupportedTypeConverter`1.Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
   at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.JsonConverter`1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
   --- End of inner exception stack trace ---
   at System.Text.Json.ThrowHelper.ThrowNotSupportedException(WriteStack& state, NotSupportedException ex)
   at System.Text.Json.Serialization.JsonConverter`1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.JsonConverter`1.WriteCoreAsObject(Utf8JsonWriter writer, Object value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.JsonSerializer.WriteCore[TValue](JsonConverter jsonConverter, Utf8JsonWriter writer, TValue& value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.JsonSerializer.WriteStreamAsync[TValue](Stream utf8Json, TValue value, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
   at System.Text.Json.JsonSerializer.WriteStreamAsync[TValue](Stream utf8Json, TValue value, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
   at System.Text.Json.JsonSerializer.WriteStreamAsync[TValue](Stream utf8Json, TValue value, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.HttpResponseJsonExtensions.WriteAsJsonAsyncSlow[TValue](Stream body, TValue value, JsonSerializerOptions options, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.RequestDelegateFactory.<>c__DisplayClass46_3.<<HandleRequestBodyAndCompileRequestDelegate>b__2>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Same result if I try from the Swagger page.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
Matt G
  • 444
  • 5
  • 23

2 Answers2

10

Results.Accepted is a method so you need to invoke it:

app.MapPost("/", (logMessage message) => 
{
    ...
    return Results.Accepted();
});

Otherwise it is converted to delegate (Func<string, object, IResult> in this case) which can not be serialized (so you see the exception in question).

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • 1
    Is this addressing the actual problem of the question, or is it a separate observation that won't be relevant until they fix the first problem? – Logarr Feb 07 '22 at 22:18
  • 4
    @Logarr yes, it is addressing the actual problem. – Guru Stron Feb 07 '22 at 22:20
  • Just spent 4 hours fighting this. Why isn't it a compiler error? – Spivonious May 15 '23 at 20:20
  • 1
    @Spivonious because it is so called method group conversion to delegate (see for example [this SO question](https://stackoverflow.com/questions/886822/what-is-a-method-group-in-c)). In short `Results.Accepted` is converted by compiler into a delegate (something similar to `Func myFunc = Results.Accepted;`) which can't be serialized by the System.Text.Json. I can't go into complete explanation (i.e. with reference to specs), but this comes from the rules of type inference. – Guru Stron May 15 '23 at 20:26
0

This is how I changed your code and now it works

app.MapPost("/", (logMessage message) =>
 {
   Console.WriteLine($"[{DateTime.Now.ToShortDateString()}] Received 
   message:");
   Console.WriteLine(message.LogMessage);
   return logMessage.GetResult();
});

And then

 public class logMessage
  {
    public static IResult GetResult()
    {
      return Results.Accepted("");
    }
    public string? LogMessage { get; set; }
  }


 
Iman
  • 717
  • 15
  • 32