dapr / dotnet-sdk

Dapr SDK for .NET
Apache License 2.0
1.11k stars 336 forks source link

Expected a supported JSON media type but got "application/octet-stream". #1088

Open akorkiatupa opened 1 year ago

akorkiatupa commented 1 year ago

Expected Behavior

When publishing and receiving events through pubsub component using rawPayload=true, receiving subscriber endpoint should be able to deserialize response body into a valid object.

Actual Behavior

When receiving events from topic subscriber where enableRawPayload=true and message was sent with rawPayload=true with Content-Type of application/json, the receiving end throws an exception from the useCloudEvents middleware.

Microsoft.AspNetCore.Http.BadHttpRequestException: Expected a supported JSON media type but got "application/octet-stream". at Microsoft.AspNetCore.Http.RequestDelegateFactory.Log.UnexpectedJsonContentType(HttpContext httpContext, String contentType, Boolean shouldThrow) at Microsoft.AspNetCore.Http.RequestDelegateFactory.gTryReadBodyAsync|90_0(HttpContext httpContext, Type bodyType, String parameterTypeName, String parameterName, Boolean allowEmptyRequestBody, Boolean throwOnBadRequest) at Microsoft.AspNetCore.Http.RequestDelegateFactory.<>c__DisplayClass90_2.<b2>d.MoveNext() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Dapr.CloudEventsMiddleware.ProcessBodyAsync(HttpContext httpContext, String charSet) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

Or when the app.UseCloudEvents() middleware is completely removed the source binding binds the data as null. When using streamReader to read the request.Body it is:

{ "data_base64": "ew0KICAgICJvcmRlcklkIjogIjMiLA0KICAgICJyZXF1ZXN0SWQiOiAiMSIsDQogICAgImZvb2JhcnMiOiBbDQogICAgICAgIHsNCiAgICAgICAgICAgICJuYW1lIjogIkZvbyIsDQogICAgICAgICAgICAibGFzdG5hbWUiOiAiQmFyIg0KICAgICAgICB9DQogICAgXQ0KfQ\u003d\u003d", "datacontenttype": "application/octet-stream", "id": "60071be7-1379-45c4-8f3a-fea2202b8b89", "pubsubname": "servicebus-pubsub", "source": "Dapr", "specversion": "1.0", "topic": "sbt-foo-bar-topic", "type": "com.dapr.event.sent" }

Steps to Reproduce the Problem

Configure startup with app.UseCloudEvents(); Publish messages where rawPayload=true set up a subscriber with enableRawPayload = true.

Questions

How raw payloads should be deserialized? There is so little information about how to use pubsub without CloudEvents as rawPayload messages, especially for the AspNetCore SDK. I am starting to feel like using ServiceBus SDK to receive messages outside of dapr cluster.

halspang commented 1 year ago

The UseCloudEvents middleware is strongly tied to the event actually being the exact format of CloudEvent that Dapr sends. When I've used raw messages in the past, what I've done is just have the endpoint take an object that the data can be deserialzied into and accessed data in the handler and done the deserialization there. You could do this with your own middleware too if you want a slightly nicer experience.

akorkiatupa commented 1 year ago

Ok, thanks for the tip. That's what I thought, ended up writing custom handler with ServiceBus SDK so we can have indented communication between Dapr instances using pubsub with CloudEvents utilizing UseCloudEvents middleware.

As a developer It would be nice if UseCloudEvents could co-exist with endpoints using rawPayloads. Then you would have the flexibility to use rawPayloads with some lecagy brokers without known json schema and CloudEvents normally if you don't explicitly tell to Dapr SDK to listen topic subscription with rawPayload.

halspang commented 1 year ago

Yeah, it's something I've thought about as well. I don't think it'd be that hard to add an optional filter into the UseCloudEvents middleware to skip parsing certain topics.