Skip to content

Commit

Permalink
Merge pull request #39 from galvesribeiro/multi-media-types
Browse files Browse the repository at this point in the history
Allow a MediaTypeHandler to support multiple media types.
  • Loading branch information
galvesribeiro authored Jan 20, 2020
2 parents 6708c0e + e4bf15c commit 9a343e3
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/Orleans.Http.Abstractions/IMediaTypeHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Orleans.Http.Abstractions
{
public interface IMediaTypeHandler
{
string MediaType { get; }
string[] MediaTypes { get; }
ValueTask Serialize(object obj, PipeWriter writer);
ValueTask<object> Deserialize(PipeReader reader, Type type, CancellationToken cancellationToken);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Orleans.Http.MediaTypes.Protobuf
{
internal sealed class ProtobufMediaTypeHandler : IMediaTypeHandler
{
public string MediaType => "application/protobuf";
public string[] MediaTypes => new[] { "application/protobuf" };

public ValueTask<object> Deserialize(PipeReader reader, Type type, CancellationToken cancellationToken)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Orleans.Http/FormsMediaTypeHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Orleans.Http
internal sealed class FormsMediaTypeHandler : IMediaTypeHandler
{
private static readonly Type _dicType = typeof(Dictionary<string, string>);
public string MediaType => "application/x-www-form-urlencoded";
public string[] MediaTypes => new[] { "application/x-www-form-urlencoded" };

public async ValueTask<object> Deserialize(PipeReader reader, Type type, CancellationToken cancellationToken)
{
Expand Down
3 changes: 1 addition & 2 deletions src/Orleans.Http/JsonMediaTypeHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ namespace Orleans.Http
{
internal sealed class JsonMediaTypeHandler : IMediaTypeHandler
{
private const string MEDIA_TYPE = "application/json";
private readonly JsonSerializerOptions _options;
public string MediaType => MEDIA_TYPE;
public string[] MediaTypes => new[] { "application/json; charset=utf-8", "application/json;charset=utf-8", "application/json" };

public JsonMediaTypeHandler(JsonSerializerOptions options)
{
Expand Down
20 changes: 16 additions & 4 deletions src/Orleans.Http/MediaTypeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,23 @@ internal sealed class MediaTypeManager
public MediaTypeManager(IServiceProvider serviceProvider)
{
this._logger = serviceProvider.GetRequiredService<ILoggerFactory>().CreateLogger<MediaTypeManager>();
this._handlers = serviceProvider.GetServices<IMediaTypeHandler>()?.ToDictionary(h => h.MediaType, h => h, StringComparer.InvariantCultureIgnoreCase);
if (this._handlers == null || this._handlers.Count == 0)
this._handlers = new Dictionary<string, IMediaTypeHandler>(StringComparer.InvariantCultureIgnoreCase);

var handlersRegistered = serviceProvider.GetServices<IMediaTypeHandler>();
if (handlersRegistered != null)
{
foreach (var handler in handlersRegistered)
{
foreach (var mediaType in handler.MediaTypes)
{
this._handlers[mediaType] = handler;
}
}
}

if (this._handlers.Count == 0)
{
this._logger.LogWarning("There are no IMediaTypeHandlers registered! Request body will be ignored.");
this._handlers = new Dictionary<string, IMediaTypeHandler>();
}
}

Expand All @@ -40,7 +52,7 @@ public async ValueTask<bool> Serialize(string mediaType, object obj, PipeWriter
}
catch (Exception exc)
{
this._logger.LogWarning(exc, $"Failure to serialize body into '{handler.MediaType}' using {handler.GetType().FullName}: {exc.Message}.");
this._logger.LogWarning(exc, $"Failure to serialize body into '{mediaType}' using {handler.GetType().FullName}: {exc.Message}.");
}

return false;
Expand Down
2 changes: 1 addition & 1 deletion src/Orleans.Http/XMLMediaTypeHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Orleans.Http
internal sealed class XMLMediaTypeHandler : IMediaTypeHandler
{
private readonly ConcurrentDictionary<string, XmlSerializer> _serializers = new ConcurrentDictionary<string, XmlSerializer>();
public string MediaType => "application/xml";
public string[] MediaTypes => new[] { "application/xml" };

public ValueTask<object> Deserialize(PipeReader reader, Type type, CancellationToken cancellationToken)
{
Expand Down
14 changes: 13 additions & 1 deletion test/Orleans.Http.Test/HttpTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,24 @@ public async Task RouteTest()
}

[Fact]
public async Task FormsTest()
public async Task JsonTest()
{
var payload = new TestPayload();
payload.Number = 12340000;
payload.Text = "Test text";

var url = "/grains/test/00000000-0000-0000-0000-000000000000/JsonTest";
var response = await this._http.PostAsync(url, new StringContent(JsonSerializer.Serialize(payload, typeof(TestPayload)), Encoding.UTF8, TestExtensions.JSON));
Assert.True(response.IsSuccessStatusCode);
var stream = await response.Content.ReadAsStreamAsync();
var resp = await JsonSerializer.DeserializeAsync<TestPayload>(stream);
Assert.True(payload.Number == resp.Number);
Assert.True(payload.Text == resp.Text);
}

[Fact]
public async Task FormsTest()
{
var url = "/grains/test/00000000-0000-0000-0000-000000000000/FormTest";
var dic = new Dictionary<string, string>();
dic["Test"] = "testing dic";
Expand Down
16 changes: 16 additions & 0 deletions test/Orleans.Http.Test/TestGrain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Orleans.Http.Abstractions;
using ProtoBuf;
using System.Collections.Generic;
using System.Text.Json.Serialization;

namespace Orleans.Http.Test
{
Expand Down Expand Up @@ -82,14 +83,19 @@ public interface ITestGrain : IGrainWithGuidKey

[HttpPost("{grainId}/FormTest")]
Task FormTest([FromBody]Dictionary<string, string> payload);

[HttpPost("{grainId}/JsonTest")]
Task<TestPayload> JsonTest([FromBody]TestPayload payload);
}

[ProtoContract]
public class TestPayload
{
[ProtoMember(1)]
[JsonPropertyName("number")]
public int Number { get; set; }
[ProtoMember(2)]
[JsonPropertyName("text")]
public string Text { get; set; }
}

Expand Down Expand Up @@ -196,6 +202,16 @@ public Task FormTest(Dictionary<string, string> payload)

throw new ArgumentException(nameof(payload));
}

public Task<TestPayload> JsonTest(TestPayload payload)
{
if (payload != null && payload.Number == 12340000 && payload.Text == "Test text")
{
return Task.FromResult(payload);
}

throw new ArgumentException(nameof(payload));
}
}

public class RandomGuidRouteGrainProvider : IRouteGrainProvider
Expand Down

0 comments on commit 9a343e3

Please sign in to comment.