Azure Functions 3 和 [FromBody] 模型绑定



我正在使用 Azure Functions 版本 3 创建一个后端点。在 Asp.net 使用[FromBody]标签获取post对象非常方便,模型绑定将发生魔术。 有没有办法在 Azure Functions v3 中使用 FromBody 标记?

是的,你可以这样做,

public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "post")][FromBody] User user, ILogger log, ExecutionContext context)

下面是一个示例

Microsoft.Azure.Functions.Worker

版本1.7.0-preview1 使自定义输入转换成为可能。 下面HttpRequestData.Body将通过将流转换为字节数组,然后将字节数组传递回正常的输入转换器过程(由内置JsonPocoConverter转换(。 它依赖于反射,因为在将流转换为字节数组后委托转换所需的服务是internal的,因此它可能会在某个时候中断。

转炉:

internal class FromHttpRequestDataBodyConverter : IInputConverter
{
public async ValueTask<ConversionResult> ConvertAsync(ConverterContext context)
{
if (context.Source is null
|| context.Source is not HttpRequestData req
|| context.TargetType.IsAssignableFrom(typeof(HttpRequestData)))
{
return ConversionResult.Unhandled();
}

var newContext = new MyConverterContext(
context,
await ReadStream(req.Body));
return await ConvertAsync(newContext);
}
private static async Task<ReadOnlyMemory<byte>> ReadStream(Stream source)
{
var byteArray = new byte[source.Length];
using (var memStream = new MemoryStream(byteArray))
{
await source.CopyToAsync(memStream);
}
return byteArray.AsMemory();
}
private static ValueTask<ConversionResult> ConvertAsync(MyConverterContext context)
{
// find the IInputConversionFeature service
var feature = context.FunctionContext
.Features
.First(f => f.Key == InputConvertionFeatureType)
.Value;
// run the default conversion
return (ValueTask<ConversionResult>)(ConvertAsyncMethodInfo.Invoke(feature, new[] { context })!);
}
#region Reflection Helpers
private static Assembly? _afWorkerCoreAssembly = null;
private static Assembly AFWorkerCoreAssembly => _afWorkerCoreAssembly
??= AssemblyLoadContext.Default
.LoadFromAssemblyName(
Assembly.GetExecutingAssembly()
.GetReferencedAssemblies()
.Single(an => an.Name == "Microsoft.Azure.Functions.Worker.Core"))
?? throw new InvalidOperationException();
private static Type? _inputConversionFeatureType = null;
private static Type InputConvertionFeatureType => _inputConversionFeatureType
??= AFWorkerCoreAssembly
.GetType("Microsoft.Azure.Functions.Worker.Context.Features.IInputConversionFeature", true)
?? throw new InvalidOperationException();
private static MethodInfo? _convertAsyncMethodInfo = null;
private static MethodInfo ConvertAsyncMethodInfo => _convertAsyncMethodInfo
??= InputConvertionFeatureType.GetMethod("ConvertAsync")
?? throw new InvalidOperationException();
#endregion
}

混凝土ConverterContext类:

internal sealed class MyConverterContext : ConverterContext
{
public MyConverterContext(Type targetType, object? source, FunctionContext context, IReadOnlyDictionary<string, object> properties)
{
TargetType = targetType ?? throw new ArgumentNullException(nameof(context));
Source = source;
FunctionContext = context ?? throw new ArgumentNullException(nameof(context));
Properties = properties ?? throw new ArgumentNullException(nameof(properties));
}
public MyConverterContext(ConverterContext context, object? source = null)
{
TargetType = context.TargetType;
Source = source ?? context.Source;
FunctionContext = context.FunctionContext;
Properties = context.Properties;
}
public override Type TargetType { get; }
public override object? Source { get; }
public override FunctionContext FunctionContext { get; }
public override IReadOnlyDictionary<string, object> Properties { get; }
}

服务配置:

public class Program
{
public static void Main()
{
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(services =>
{
services.Configure<WorkerOptions>((workerOptions) =>
{
workerOptions.InputConverters.Register<Converters.FromHttpRequestDataBodyConverter>();
});
})
.Build();
host.Run();
}
}

最新更新