in src/Microsoft.Azure.WebJobs.Host/Bindings/BindingProviders/BindToStreamBindingProvider.cs [282:406]
public static IBinding TryBuild<TUserType>(
BindToStreamBindingProvider<TAttribute> parent,
BindingProviderContext context)
{
// Allowed Param types:
// Stream
// any T with a Stream --> T conversion
// out T, with a Out<Stream,T> --> void conversion
var parameter = context.Parameter;
var parameterType = parameter.ParameterType;
var attributeSource = TypeUtility.GetResolvedAttribute<TAttribute>(parameter);
// Stream is either way; all other types are known.
FileAccess? declaredAccess = GetFileAccessFromAttribute(attributeSource);
Type argHelperType;
bool isRead;
IConverterManager cm = parent._converterManager;
INameResolver nm = parent._nameResolver;
IConfiguration config = parent._configuration;
object converterParam = null;
{
if (parameter.IsOut)
{
var outConverter = cm.GetConverter<ApplyConversion<TUserType, Stream>, object, TAttribute>();
if (outConverter != null)
{
converterParam = outConverter;
isRead = false;
argHelperType = typeof(OutArgBaseValueProvider<>).MakeGenericType(typeof(TAttribute), typeof(TUserType));
}
else
{
throw new InvalidOperationException($"No stream converter to handle {typeof(TUserType).FullName}.");
}
}
else
{
var converter = cm.GetConverter<Stream, TUserType, TAttribute>();
if (converter != null)
{
converterParam = converter;
if (parameterType == typeof(Stream))
{
if (!declaredAccess.HasValue)
{
throw new InvalidOperationException("When binding to Stream, the attribute must specify a FileAccess direction.");
}
switch (declaredAccess.Value)
{
case FileAccess.Read:
isRead = true;
break;
case FileAccess.Write:
isRead = false;
break;
default:
throw new NotImplementedException("ReadWrite access is not supported. Pick either Read or Write.");
}
}
else
{
// For backwards compat, we recognize TextWriter as write;
// anything else should explicitly set the FileAccess flag.
if (typeof(TextWriter).IsAssignableFrom(typeof(TUserType)))
{
isRead = false;
}
else
{
isRead = true;
}
}
argHelperType = typeof(ValueProvider<>).MakeGenericType(typeof(TAttribute), typeof(TUserType));
}
else
{
// This rule can't bind.
// Let another try.
context.BindingErrors.Add(String.Format(Resource.BindingAssemblyConflictMessage, typeof(Stream).AssemblyQualifiedName, typeof(TUserType).AssemblyQualifiedName));
return null;
}
}
}
VerifyAccessOrThrow(declaredAccess, isRead);
if (!parent.IsSupportedByRule(isRead))
{
return null;
}
var cloner = new AttributeCloner<TAttribute>(attributeSource, context.BindingDataContract, config, nm);
ParameterDescriptor param;
if (parent.BuildParameterDescriptor != null)
{
param = parent.BuildParameterDescriptor(attributeSource, parameter, nm);
}
else
{
param = new ParameterDescriptor
{
Name = parameter.Name,
DisplayHints = new ParameterDisplayHints
{
Description = isRead ? "Read Stream" : "Write Stream"
}
};
}
var fileAccess = isRead ? FileAccess.Read : FileAccess.Write;
IBinding binding = new StreamBinding(cloner, param, parent, argHelperType, parameterType, fileAccess, converterParam);
return binding;
}