Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 9 additions & 24 deletions extensions/Worker.Extensions.CosmosDB/src/CosmosDBConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
using Microsoft.Azure.Functions.Worker.Extensions.Abstractions;
using Microsoft.Azure.Functions.Worker.Extensions;

namespace Microsoft.Azure.Functions.Worker
{
/// <summary>
/// Converter to bind Cosmos DB type parameters.
/// Converter to bind CosmosDB type parameters.
/// </summary>
[SupportsDeferredBinding]
internal class CosmosDBConverter : IInputConverter
Expand All @@ -42,46 +43,30 @@ public async ValueTask<ConversionResult> ConvertAsync(ConverterContext context)

private async ValueTask<ConversionResult> ConvertFromBindingDataAsync(ConverterContext context, ModelBindingData modelBindingData)
{
if (!IsCosmosExtension(modelBindingData))
{
return ConversionResult.Unhandled();
}

try
{
if (modelBindingData.Source is not Constants.CosmosExtensionName)
{
throw new InvalidBindingSourceException(Constants.CosmosExtensionName);
}

var cosmosAttribute = GetBindingDataContent(modelBindingData);
object result = await ToTargetTypeAsync(context.TargetType, cosmosAttribute);

if (result is not null)
{
return ConversionResult.Success(result);
}
return ConversionResult.Success(result);
}
catch (Exception ex)
{
return ConversionResult.Failed(ex);
}

return ConversionResult.Unhandled();
}

private bool IsCosmosExtension(ModelBindingData bindingData)
{
if (bindingData?.Source is not Constants.CosmosExtensionName)
{
_logger.LogTrace("Source '{source}' is not supported by {converter}", bindingData?.Source, nameof(CosmosDBConverter));
return false;
}

return true;
}

private CosmosDBInputAttribute GetBindingDataContent(ModelBindingData bindingData)
{
return bindingData?.ContentType switch
{
Constants.JsonContentType => bindingData.Content.ToObjectFromJson<CosmosDBInputAttribute>(),
_ => throw new NotSupportedException($"Unexpected content-type. Currently only '{Constants.JsonContentType}' is supported.")
_ => throw new InvalidContentTypeException(Constants.JsonContentType)
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,76 +3,43 @@

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Azure.Functions.Worker.Converters;

namespace Microsoft.Azure.Functions.Worker.Extensions.EventGrid.TypeConverters
{
/// <summary>
/// Converter to bind to BinaryData or BinaryData[] parameter.
/// Converter to bind to <see cref="BinaryData" /> or <see cref="BinaryData[]" /> type parameters.
/// </summary>
[SupportedConverterType(typeof(BinaryData))]
[SupportedConverterType(typeof(BinaryData[]))]
internal class EventGridBinaryDataConverter : IInputConverter
internal class EventGridBinaryDataConverter : EventGridConverterBase
{
public ValueTask<ConversionResult> ConvertAsync(ConverterContext context)
protected override ConversionResult ConvertCore(Type targetType, string json)
{
try
object result = targetType switch
{
if (context is null)
Type t when t == typeof(BinaryData) => ConvertToBinaryData(json),
Type t when t == typeof(BinaryData[]) => () =>
{
throw new ArgumentNullException(nameof(context));
}
var data = JsonSerializer.Deserialize(json, typeof(List<object>)) as List<object>;
return data.Select(d => ConvertToBinaryData(d.ToString())).ToArray();
},
_ => ConversionResult.Unhandled()
};

if (context.Source is not string contextSource)
{
return new(ConversionResult.Failed(new InvalidOperationException("Context source must be a non-null string. Current type of context source is " + context?.Source?.GetType())));
}

var targetType = context.TargetType;

switch (targetType)
{
case Type t when t == typeof(BinaryData):
return new(ConversionResult.Success((BinaryData.FromString(contextSource))));
case Type t when t == typeof(BinaryData[]):
return new(ConversionResult.Success(ConvertToBinaryDataArray(contextSource)));
}
}
catch (JsonException ex)
{
string msg = String.Format(CultureInfo.CurrentCulture,
@"Binding parameters to complex objects uses JSON serialization.
1. Bind the parameter type as 'string' instead to get the raw values and avoid JSON deserialization, or
2. Change the event payload to be valid json.");

return new(ConversionResult.Failed(new InvalidOperationException(msg, ex)));
}
catch (Exception ex)
{
return new(ConversionResult.Failed(ex));
}

return new(ConversionResult.Unhandled());
return ConversionResult.Success(result);
}

private BinaryData?[]? ConvertToBinaryDataArray(string contextSource)
private BinaryData ConvertToBinaryData(string item)
{
var jsonData = JsonSerializer.Deserialize(contextSource, typeof(List<object>)) as List<object>;
List<BinaryData?> binaryDataList = new List<BinaryData?>();

if (jsonData is not null)
if (item is null)
{
foreach (var item in jsonData)
{
var binaryData = item == null? null: BinaryData.FromString(item.ToString());
binaryDataList.Add(binaryData);
}
throw new ArgumentNullException(nameof(item));
}

return binaryDataList.ToArray();
return BinaryData.FromString(item);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,27 @@
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Threading.Tasks;
using System.Text.Json;
using Azure.Messaging;
using Microsoft.Azure.Functions.Worker.Converters;

namespace Microsoft.Azure.Functions.Worker.Extensions.EventGrid.TypeConverters
{
/// <summary>
/// Converter to bind to CloudEvent or CloudEvent[] parameter.
/// Converter to bind to <see cref="CloudEvent" /> or <see cref="CloudEvent[]" /> type parameters.
/// </summary>
[SupportedConverterType(typeof(CloudEvent))]
[SupportedConverterType(typeof(CloudEvent[]))]
internal class EventGridCloudEventConverter: IInputConverter
internal class EventGridCloudEventConverter: EventGridConverterBase
{
public ValueTask<ConversionResult> ConvertAsync(ConverterContext context)
protected override ConversionResult ConvertCore(Type targetType, string json)
{
if (context is null)
if (targetType != typeof(CloudEvent) && targetType != typeof(CloudEvent[]))
{
return new(ConversionResult.Failed(new ArgumentNullException(nameof(context))));
return ConversionResult.Unhandled();
}

if (context.TargetType != typeof(CloudEvent) && context.TargetType != typeof(CloudEvent[]))
{
return new(ConversionResult.Unhandled());
}

return EventGridHelper.DeserializeToTargetType(context);
return ConversionResult.Success(JsonSerializer.Deserialize(json, targetType)!);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Globalization;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Azure.Functions.Worker.Converters;

namespace Microsoft.Azure.Functions.Worker
{
internal abstract class EventGridConverterBase : IInputConverter
{
public EventGridConverterBase() { }

public ValueTask<ConversionResult> ConvertAsync(ConverterContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}

try
{
if (context.Source is not string json)
{
throw new InvalidOperationException($"Context source must be a non-null string. Current type of context source is '{context.Source.GetType()}'");
}

var result = ConvertCore(context.TargetType, json);
return new ValueTask<ConversionResult>(result);
}
catch (JsonException ex)
{
string msg = String.Format(CultureInfo.CurrentCulture,
@"Binding parameters to complex objects uses JSON serialization.
1. Bind the parameter type as 'string' instead to get the raw values and avoid JSON deserialization, or
2. Change the queue payload to be valid json.");

return new ValueTask<ConversionResult>(ConversionResult.Failed(new InvalidOperationException(msg, ex)));
}
catch (Exception ex)
{
return new ValueTask<ConversionResult>(ConversionResult.Failed(ex));
}
}

protected abstract ConversionResult ConvertCore(Type targetType, string json);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,27 @@
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Threading.Tasks;
using System.Text.Json;
using Azure.Messaging.EventGrid;
using Microsoft.Azure.Functions.Worker.Converters;

namespace Microsoft.Azure.Functions.Worker.Extensions.EventGrid.TypeConverters
{
/// <summary>
/// Converter to bind to EventGridEvent or EventGridEvent[] parameter.
/// Converter to bind to <see cref="EventGridEvent" /> or <see cref="EventGridEvent[]" /> type parameters.
/// </summary>
[SupportedConverterType(typeof(EventGridEvent))]
[SupportedConverterType(typeof(EventGridEvent[]))]
internal class EventGridEventConverter : IInputConverter
internal class EventGridEventConverter : EventGridConverterBase
{
public ValueTask<ConversionResult> ConvertAsync(ConverterContext context)
protected override ConversionResult ConvertCore(Type targetType, string json)
{
if (context is null)
if (targetType != typeof(EventGridEvent) && targetType != typeof(EventGridEvent[]))
{
return new(ConversionResult.Failed(new ArgumentNullException(nameof(context))));
return ConversionResult.Unhandled();
}

if (context?.TargetType != typeof(EventGridEvent) && context?.TargetType != typeof(EventGridEvent[]))
{
return new(ConversionResult.Unhandled());
}

return EventGridHelper.DeserializeToTargetType(context);
return ConversionResult.Success(JsonSerializer.Deserialize(json, targetType)!);
}
}
}

This file was deleted.

Loading