/// <inheritdoc/> public override async Task <object> ReadAsync(BodyParserContext context) { var operation = context.Instance; var properties = context.OperationContext.Descriptor.Properties; var form = await context.HttpContext.Request.ReadFormAsync(); foreach (var item in form) { WriteStringValues(operation, properties, item.Key, item.Value, exception => throw _invalidForm.Create(exception.Message)); } if (form.Files.Any()) { var props = properties.Where(x => x.PropertyType.IsAssignableFrom(typeof(IFormFile))).ToList(); foreach (var file in form.Files) { var propertyToWrite = props.SingleOrDefault(x => string.Equals(x.Name, file.Name, StringComparison.OrdinalIgnoreCase)); if (propertyToWrite == null) { continue; } propertyToWrite.SetValue(operation, file); } } // We have populated the object given to us, return as-is. return(operation); }
/// <inheritdoc /> protected sealed override async Task <object> ReadRequestBodyAsync( BodyParserContext context, Encoding encoding) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (encoding == null) { throw new ArgumentNullException(nameof(encoding)); } var httpContext = context.HttpContext; var(inputStream, usesTranscodingStream) = this.GetInputStream(httpContext, encoding); try { // This is copied from JsonConvert.PopulateObject to avoid creating a new JsonSerializer on each // execution. using var stringReader = new StreamReader(inputStream); using var jsonReader = new JsonTextReader(stringReader) { CloseInput = false }; try { this._bodyJsonSerializer.Populate(jsonReader, context.Instance); } catch (JsonException e) { throw _invalidJson.Create(e.Message); } if (await jsonReader.ReadAsync() && jsonReader.TokenType != JsonToken.Comment) { throw _invalidJson.Create("Additional text found in JSON"); } } finally { if (usesTranscodingStream) { // TODO: When we target .net 5.0 can make use of built-in transcoding Stream with async Dispose // await inputStream.DisposeAsync(); } } // We have populated the object given to us, return as-is. return(context.Instance); }
/// <inheritdoc /> protected sealed override async Task <object> ReadRequestBodyAsync( BodyParserContext context, Encoding encoding) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (encoding == null) { throw new ArgumentNullException(nameof(encoding)); } var httpContext = context.HttpContext; var(inputStream, usesTranscodingStream) = this.GetInputStream(httpContext, encoding); try { return(await JsonSerializer.DeserializeAsync(inputStream, context.BodyType, this._serializerOptions)); } catch (JsonException jsonException) { throw _invalidJson.Create(jsonException.Message); } catch (Exception exception) when(exception is FormatException || exception is OverflowException) { // The code in System.Text.Json never throws these exceptions. However a custom converter could produce these errors for instance when // parsing a value. These error messages are considered safe to report to users throw _invalidJson.Create(exception.Message); } finally { if (usesTranscodingStream) { // TODO: When we target .net 5.0 can make use of built-in transcoding Stream with async Dispose // await inputStream.DisposeAsync(); } } }
/// <inheritdoc /> public virtual bool CanRead(BodyParserContext context) { if (this.SupportedMediaTypes.Count == 0) { throw new InvalidOperationException($"{this.GetType().FullName} does not specify any support media types. Ensure that {nameof(this.SupportedMediaTypes)} has been populated with at least one value"); } if (!this.CanReadType(context.BodyType)) { return(false); } var contentType = context.HttpContext.Request.ContentType; if (string.IsNullOrEmpty(contentType)) { return(false); } // Confirm the request's content type is more specific than a media type this formatter supports e.g. OK if // client sent "text/plain" data and this formatter supports "text/*". return(this.IsSubsetOfAnySupportedContentType(contentType)); }
/// <inheritdoc/> public abstract Task <object> ReadAsync(BodyParserContext context);