Skip to content

Commit

Permalink
Serialization provider now always looks at the object type to find th…
Browse files Browse the repository at this point in the history
…e correct serializer
  • Loading branch information
cwe1ss committed Mar 1, 2019
1 parent 20955ad commit 6e8f755
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 70 deletions.
4 changes: 3 additions & 1 deletion src/Meceqs.AspNetCore/Receiving/DefaultHttpRequestReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ public Envelope ConvertToEnvelope(HttpContext httpContext, Type messageType)
var requestHeaders = httpContext.Request.GetTypedHeaders();
string contentType = requestHeaders.ContentType.MediaType.ToString();

object message = _serializationProvider.Deserialize(contentType, messageType, httpContext.Request.Body);
var serializer = _serializationProvider.GetSerializer(messageType, contentType);

object message = serializer.Deserialize(messageType, httpContext.Request.Body);

Guid messageId = GetGuidHeader(requestHeaders.Headers, TransportHeaderNames.MessageId) ?? Guid.NewGuid();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public void WriteResponse(object response, HttpContext httpContext)

IEnumerable<string> supportedContentTypes = GetSupportedContentTypes(httpContext);

ISerializer serializer = _serializationProvider.GetSerializer(supportedContentTypes);
ISerializer serializer = _serializationProvider.GetSerializer(response.GetType(), supportedContentTypes);

httpContext.Response.ContentType = serializer.ContentType;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public EventData ConvertToEventData(Envelope envelope)
{
Guard.NotNull(envelope, nameof(envelope));

ISerializer serializer = _serializationProvider.GetSerializer(envelope.Message.GetType());
ISerializer serializer = _serializationProvider.GetSerializer(envelope.GetType());

byte[] serializedEnvelope = serializer.SerializeToByteArray(envelope);

Expand All @@ -47,10 +47,11 @@ public Envelope ConvertToEnvelope(EventData eventData)
string messageType = (string)eventData.Properties[TransportHeaderNames.MessageType];

Type envelopeType = _envelopeTypeLoader.LoadEnvelopeType(messageType);
ISerializer serializer = _serializationProvider.GetSerializer(envelopeType, contentType);

using (var envelopeStream = new MemoryStream(eventData.Body.Array))
{
return (Envelope)_serializationProvider.Deserialize(contentType, envelopeType, envelopeStream);
return (Envelope)serializer.Deserialize(envelopeType, envelopeStream);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public Message ConvertToServiceBusMessage(Envelope envelope)
{
Guard.NotNull(envelope, nameof(envelope));

ISerializer serializer = _serializationProvider.GetSerializer(envelope.Message.GetType());
ISerializer serializer = _serializationProvider.GetSerializer(envelope.GetType());

byte[] serializedEnvelope = serializer.SerializeToByteArray(envelope);

Expand All @@ -50,15 +50,15 @@ public Envelope ConvertToEnvelope(Message serviceBusMessage)
{
Guard.NotNull(serviceBusMessage, nameof(serviceBusMessage));

// TODO @cweiss validations?
string contentType = serviceBusMessage.ContentType ?? (string)serviceBusMessage.UserProperties[TransportHeaderNames.ContentType];
string messageType = (string)serviceBusMessage.UserProperties[TransportHeaderNames.MessageType];

Type envelopeType = _envelopeTypeLoader.LoadEnvelopeType(messageType);
ISerializer serializer = _serializationProvider.GetSerializer(envelopeType, contentType);

using (var envelopeStream = new MemoryStream(serviceBusMessage.Body))
{
return (Envelope)_serializationProvider.Deserialize(contentType, envelopeType, envelopeStream);
return (Envelope)serializer.Deserialize(envelopeType, envelopeStream);
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/Meceqs.HttpSender/HttpSenderMiddleware.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
Expand Down Expand Up @@ -65,10 +66,9 @@ public async Task Invoke(MessageContext context)
string contentType = response.Content.Headers.ContentType?.ToString();
if (!string.IsNullOrEmpty(contentType))
{
if (!_serializationProvider.TryGetSerializer(contentType, out ISerializer serializer))
{
throw new NotSupportedException($"ContentType '{contentType}' is not supported.");
}
var contentTypeList = new List<string> { contentType };

var serializer = _serializationProvider.GetSerializer(context.ExpectedResponseType, contentTypeList);

context.Response = serializer.Deserialize(context.ExpectedResponseType, await response.Content.ReadAsStreamAsync());
}
Expand Down
106 changes: 52 additions & 54 deletions src/Meceqs/Serialization/DefaultSerializationProvider.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Extensions.Options;

namespace Meceqs.Serialization
{
public class DefaultSerializationProvider : ISerializationProvider
{
private static readonly IEnumerable<string> EmptyContentTypes = new List<string>().AsReadOnly();

private readonly IReadOnlyList<ISerializer> _serializers;
private readonly IReadOnlyList<string> _supportedContentTypes;

Expand All @@ -24,43 +26,6 @@ public DefaultSerializationProvider(IOptions<SerializationOptions> options)
_supportedContentTypes = GetSupportedContentTypes(_serializers);
}

public ISerializer GetSerializer(Type objectType)
{
Guard.NotNull(objectType, nameof(objectType));

foreach (var serializer in _serializers)
{
if (serializer.CanSerializeType(objectType))
return serializer;
}

throw new InvalidOperationException($"No serializer found that can handle the type '{objectType.FullName}'.");
}

public ISerializer GetSerializer(IEnumerable<string> supportedContentTypes)
{
Guard.NotNull(supportedContentTypes, nameof(supportedContentTypes));

bool hasItems = false;
foreach (var supportedContentType in supportedContentTypes)
{
hasItems = true;
if (TryGetSerializer(supportedContentType, out ISerializer serializer))
{
return serializer;
}
}

if (hasItems)
{
throw new InvalidOperationException($"No serializer matching content types '{string.Join(",", supportedContentTypes)}'.");
}
else
{
throw new ArgumentException("The list may not be empty", nameof(supportedContentTypes));
}
}

public IReadOnlyList<string> GetSupportedContentTypes(Type objectType = null)
{
if (objectType == null)
Expand All @@ -80,36 +45,69 @@ public IReadOnlyList<string> GetSupportedContentTypes(Type objectType = null)
return supportedContentTypes;
}

public bool TryGetSerializer(string contentType, out ISerializer serializer)
public ISerializer GetSerializer(Type objectType)
{
return GetSerializer(objectType, EmptyContentTypes);
}

public ISerializer GetSerializer(Type objectType, string supportedContentType)
{
Guard.NotNull(contentType, nameof(contentType));
Guard.NotNullOrWhiteSpace(supportedContentType, nameof(supportedContentType));

serializer = null;
return GetSerializer(objectType, new List<string> { supportedContentType });
}

foreach (var supportedSerializer in _serializers)
public ISerializer GetSerializer(Type objectType, IEnumerable<string> supportedContentTypes)
{
if (!TryGetSerializer(objectType, supportedContentTypes, out var serializer))
{
if (supportedSerializer.ContentType == contentType)
{
serializer = supportedSerializer;
return true;
}
throw new InvalidOperationException(
$"No serializer matches object type '{objectType.FullName}' " +
$"and content types '{string.Join(",", supportedContentTypes)}'.");
}

return false;
return serializer;
}

public object Deserialize(string contentType, Type objectType, Stream serializedObject)
public bool TryGetSerializer(Type objectType, out ISerializer serializer)
{
return TryGetSerializer(objectType, EmptyContentTypes, out serializer);
}

public bool TryGetSerializer(Type objectType, string supportedContentType, out ISerializer serializer)
{
Guard.NotNullOrWhiteSpace(supportedContentType, nameof(supportedContentType));

return TryGetSerializer(objectType, new List<string> { supportedContentType }, out serializer);
}

public bool TryGetSerializer(Type objectType, IEnumerable<string> supportedContentTypes, out ISerializer serializer)
{
Guard.NotNull(contentType, nameof(contentType));
Guard.NotNull(objectType, nameof(objectType));
Guard.NotNull(serializedObject, nameof(serializedObject));
Guard.NotNull(supportedContentTypes, nameof(supportedContentTypes));

if (!TryGetSerializer(contentType, out var serializer))
foreach (var existingSerializer in _serializers)
{
throw new NotSupportedException($"ContentType '{contentType}' is not supported.");
if (existingSerializer.CanSerializeType(objectType))
{
if (!supportedContentTypes.Any())
{
// The client doesn't have any preference regarding the content type
// so we can return the "best" (= the first that matches)
serializer = existingSerializer;
return true;
}

if (supportedContentTypes.Any(x => string.Equals(x, existingSerializer.ContentType, StringComparison.OrdinalIgnoreCase)))
{
serializer = existingSerializer;
return true;
}
}
}

return serializer.Deserialize(objectType, serializedObject);
serializer = null;
return false;
}

private static IReadOnlyList<string> GetSupportedContentTypes(IEnumerable<ISerializer> serializers)
Expand Down
13 changes: 8 additions & 5 deletions src/Meceqs/Serialization/ISerializationProvider.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
using System;
using System.Collections.Generic;
using System.IO;

namespace Meceqs.Serialization
{
public interface ISerializationProvider
{
bool TryGetSerializer(string contentType, out ISerializer serializer);
IReadOnlyList<string> GetSupportedContentTypes(Type objectType = null);

ISerializer GetSerializer(Type objectType);

ISerializer GetSerializer(IEnumerable<string> supportedContentTypes);
ISerializer GetSerializer(Type objectType, string supportedContentType);

IReadOnlyList<string> GetSupportedContentTypes(Type objectType = null);
ISerializer GetSerializer(Type objectType, IEnumerable<string> supportedContentTypes);

bool TryGetSerializer(Type objectType, out ISerializer serializer);

bool TryGetSerializer(Type objectType, string supportedContentType, out ISerializer serializer);

object Deserialize(string contentType, Type objectType, Stream serializedObject);
bool TryGetSerializer(Type objectType, IEnumerable<string> supportedContentTypes, out ISerializer serializer);
}
}

0 comments on commit 6e8f755

Please sign in to comment.