/// <inheritdoc /> protected async override Task<ModelBindingResult> BindModelCoreAsync( [NotNull] ModelBindingContext bindingContext) { var httpContext = bindingContext.OperationBindingContext.HttpContext; var formatters = bindingContext.OperationBindingContext.InputFormatters; var formatterContext = new InputFormatterContext( httpContext, bindingContext.ModelState, bindingContext.ModelType); var formatter = formatters.FirstOrDefault(f => f.CanRead(formatterContext)); if (formatter == null) { var unsupportedContentType = Resources.FormatUnsupportedContentType( bindingContext.OperationBindingContext.HttpContext.Request.ContentType); bindingContext.ModelState.AddModelError(bindingContext.ModelName, unsupportedContentType); // This model binder is the only handler for the Body binding source. // Always tell the model binding system to skip other model binders i.e. return non-null. return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false); } try { var model = await formatter.ReadAsync(formatterContext); var isTopLevelObject = bindingContext.ModelMetadata.ContainerType == null; // For compatibility with MVC 5.0 for top level object we want to consider an empty key instead of // the parameter name/a custom name. In all other cases (like when binding body to a property) we // consider the entire ModelName as a prefix. var modelBindingKey = isTopLevelObject ? string.Empty : bindingContext.ModelName; var validationNode = new ModelValidationNode(modelBindingKey, bindingContext.ModelMetadata, model) { ValidateAllProperties = true }; return new ModelBindingResult( model, key: modelBindingKey, isModelSet: true, validationNode: validationNode); } catch (Exception ex) { bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex); // This model binder is the only handler for the Body binding source. // Always tell the model binding system to skip other model binders i.e. return non-null. return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false); } }
/// <summary> /// Reads the input XML. /// </summary> /// <param name="context">The input formatter context which contains the body to be read.</param> /// <returns>Task which reads the input.</returns> public async Task ReadAsync(InputFormatterContext context) { var request = context.HttpContext.Request; if (request.ContentLength == 0) { context.Model = GetDefaultValueForType(context.Metadata.ModelType); return; } context.Model = await ReadInternal(context); }
public void CanRead_ReturnsTrueForAnySupportedContentType(string requestContentType, bool expectedCanRead) { // Arrange var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encoding.UTF8.GetBytes("content"); var actionContext = GetActionContext(contentBytes, contentType: requestContentType); var formatterContext = new InputFormatterContext(actionContext, typeof(string)); // Act var result = formatter.CanRead(formatterContext); // Assert Assert.Equal(expectedCanRead, result); }
public void CanRead_ReturnsTrueForAnySupportedContentType(string requestContentType, bool expectedCanRead) { // Arrange var formatter = new XmlSerializerInputFormatter(); var contentBytes = Encoding.UTF8.GetBytes("content"); var modelState = new ModelStateDictionary(); var httpContext = GetHttpContext(contentBytes, contentType: requestContentType); var formatterContext = new InputFormatterContext(httpContext, modelState, typeof(string)); // Act var result = formatter.CanRead(formatterContext); // Assert Assert.Equal(expectedCanRead, result); }
public async Task JsonFormatterReadsSimpleTypes(string content, Type type, object expected) { // Arrange var formatter = new JsonInputFormatter(); var contentBytes = Encoding.UTF8.GetBytes(content); var httpContext = GetHttpContext(contentBytes); var modelState = new ModelStateDictionary(); var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, type); var context = new InputFormatterContext(httpContext, metadata, modelState); // Act await formatter.ReadAsync(context); // Assert Assert.Equal(expected, context.Model); }
public async Task JsonFormatterReadsComplexTypes() { // Arrange var content = "{name: 'Person Name', Age: '30'}"; var formatter = new JsonInputFormatter(); var contentBytes = Encoding.UTF8.GetBytes(content); var httpContext = GetHttpContext(contentBytes); var modelState = new ModelStateDictionary(); var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(User)); var context = new InputFormatterContext(httpContext, metadata, modelState); // Act await formatter.ReadAsync(context); // Assert var model = Assert.IsType<User>(context.Model); Assert.Equal("Person Name", model.Name); Assert.Equal(30, model.Age); }
public void CanRead_ReturnsTrueForAnySupportedContentType(string requestContentType, bool expectedCanRead) { // Arrange var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encoding.UTF8.GetBytes("content"); var modelState = new ModelStateDictionary(); var httpContext = GetHttpContext(contentBytes, contentType: requestContentType); var provider = new EmptyModelMetadataProvider(); var metadata = provider.GetMetadataForType(typeof(string)); var formatterContext = new InputFormatterContext( httpContext, modelName: string.Empty, modelState: modelState, metadata: metadata); // Act var result = formatter.CanRead(formatterContext); // Assert Assert.Equal(expectedCanRead, result); }
/// <inheritdoc /> protected async override Task<ModelBindingResult> BindModelCoreAsync([NotNull] ModelBindingContext bindingContext) { var formatters = _bindingContext.Value.InputFormatters; var formatterContext = new InputFormatterContext(_actionContext, bindingContext.ModelType); var formatter = _formatterSelector.SelectFormatter(formatters.ToList(), formatterContext); if (formatter == null) { var unsupportedContentType = Resources.FormatUnsupportedContentType( bindingContext.OperationBindingContext.HttpContext.Request.ContentType); bindingContext.ModelState.AddModelError(bindingContext.ModelName, unsupportedContentType); // This model binder is the only handler for the Body binding source. // Always tell the model binding system to skip other model binders i.e. return non-null. return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false); } object model = null; try { model = await formatter.ReadAsync(formatterContext); } catch (Exception ex) { model = GetDefaultValueForType(bindingContext.ModelType); bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex); // This model binder is the only handler for the Body binding source. // Always tell the model binding system to skip other model binders i.e. return non-null. return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false); } // Success // key is empty to ensure that the model name is not used as a prefix for validation. return new ModelBindingResult(model, key: string.Empty, isModelSet: true); }
public override Task<object> ReadRequestBodyAsync(InputFormatterContext context) { throw new InvalidOperationException("Your input is bad!"); }
/// <summary> /// Attempts to bind the model using formatters. /// </summary> /// <param name="bindingContext">The <see cref="ModelBindingContext"/>.</param> /// <returns> /// A <see cref="Task{ModelBindingResult}"/> which when completed returns a <see cref="ModelBindingResult"/>. /// </returns> private async Task <ModelBindingResult> BindModelCoreAsync(ModelBindingContext bindingContext) { if (bindingContext == null) { throw new ArgumentNullException(nameof(bindingContext)); } // For compatibility with MVC 5.0 for top level object we want to consider an empty key instead of // the parameter name/a custom name. In all other cases (like when binding body to a property) we // consider the entire ModelName as a prefix. var modelBindingKey = bindingContext.IsTopLevelObject ? string.Empty : bindingContext.ModelName; var httpContext = bindingContext.OperationBindingContext.HttpContext; var formatterContext = new InputFormatterContext( httpContext, modelBindingKey, bindingContext.ModelState, bindingContext.ModelMetadata, _readerFactory); var formatters = bindingContext.OperationBindingContext.InputFormatters; var formatter = formatters.FirstOrDefault(f => f.CanRead(formatterContext)); if (formatter == null) { var unsupportedContentType = Resources.FormatUnsupportedContentType( bindingContext.OperationBindingContext.HttpContext.Request.ContentType); bindingContext.ModelState.AddModelError(modelBindingKey, unsupportedContentType); // This model binder is the only handler for the Body binding source and it cannot run twice. Always // tell the model binding system to skip other model binders and never to fall back i.e. indicate a // fatal error. return(ModelBindingResult.Failed(modelBindingKey)); } try { var previousCount = bindingContext.ModelState.ErrorCount; var result = await formatter.ReadAsync(formatterContext); var model = result.Model; // Ensure a "modelBindingKey" entry exists whether or not formatting was successful. bindingContext.ModelState.SetModelValue(modelBindingKey, rawValue: model, attemptedValue: null); if (result.HasError) { // Formatter encountered an error. Do not use the model it returned. As above, tell the model // binding system to skip other model binders and never to fall back. return(ModelBindingResult.Failed(modelBindingKey)); } return(ModelBindingResult.Success(modelBindingKey, model)); } catch (Exception ex) { bindingContext.ModelState.AddModelError(modelBindingKey, ex, bindingContext.ModelMetadata); // This model binder is the only handler for the Body binding source and it cannot run twice. Always // tell the model binding system to skip other model binders and never to fall back i.e. indicate a // fatal error. return(ModelBindingResult.Failed(modelBindingKey)); } }
public Task <object> ReadAsync(InputFormatterContext context) { return(Task.FromResult <object>(this)); }
public bool CanRead(InputFormatterContext context) { return(_canRead); }
public override Task <object> ReadRequestBodyAsync(InputFormatterContext context) { throw new InvalidOperationException("Your input is bad!"); }
public async Task ReadAsync_AcceptsUTF16Characters() { // Arrange var expectedInt = 10; var expectedString = "TestString"; var expectedDateTime = XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.Utc); var input = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>" + "<TestLevelOne><SampleInt>" + expectedInt + "</SampleInt>" + "<sampleString>" + expectedString + "</sampleString>" + "<SampleDate>" + expectedDateTime + "</SampleDate></TestLevelOne>"; var formatter = new XmlSerializerInputFormatter(); var contentBytes = Encoding.Unicode.GetBytes(input); var modelState = new ModelStateDictionary(); var httpContext = GetHttpContext(contentBytes, contentType: "application/xml; charset=utf-16"); var provider = new EmptyModelMetadataProvider(); var metadata = provider.GetMetadataForType(typeof(TestLevelOne)); var context = new InputFormatterContext( httpContext, modelName: string.Empty, modelState: modelState, metadata: metadata, readerFactory: new TestHttpRequestStreamReaderFactory().CreateReader); // Act var result = await formatter.ReadAsync(context); // Assert Assert.NotNull(result); Assert.False(result.HasError); var model = Assert.IsType<TestLevelOne>(result.Model); Assert.Equal(expectedInt, model.SampleInt); Assert.Equal(expectedString, model.sampleString); Assert.Equal(XmlConvert.ToDateTime(expectedDateTime, XmlDateTimeSerializationMode.Utc), model.SampleDate); }
/// <summary> /// Called during deserialization to get the <see cref="JsonReader"/>. /// </summary> /// <param name="context">The <see cref="InputFormatterContext"/> for the read.</param> /// <param name="readStream">The <see cref="Stream"/> from which to read.</param> /// <param name="effectiveEncoding">The <see cref="Encoding"/> to use when reading.</param> /// <returns>The <see cref="JsonReader"/> used during deserialization.</returns> public virtual JsonReader CreateJsonReader([NotNull] InputFormatterContext context, [NotNull] Stream readStream, [NotNull] Encoding effectiveEncoding) { return(new JsonTextReader(new StreamReader(readStream, effectiveEncoding))); }
/// <inheritdoc /> protected async override Task <ModelBindingResult> BindModelCoreAsync( [NotNull] ModelBindingContext bindingContext) { // For compatibility with MVC 5.0 for top level object we want to consider an empty key instead of // the parameter name/a custom name. In all other cases (like when binding body to a property) we // consider the entire ModelName as a prefix. var modelBindingKey = bindingContext.IsTopLevelObject ? string.Empty : bindingContext.ModelName; var httpContext = bindingContext.OperationBindingContext.HttpContext; var formatterContext = new InputFormatterContext( httpContext, bindingContext.ModelState, bindingContext.ModelType); var formatters = bindingContext.OperationBindingContext.InputFormatters; var formatter = formatters.FirstOrDefault(f => f.CanRead(formatterContext)); if (formatter == null) { var unsupportedContentType = Resources.FormatUnsupportedContentType( bindingContext.OperationBindingContext.HttpContext.Request.ContentType); bindingContext.ModelState.AddModelError(modelBindingKey, unsupportedContentType); // This model binder is the only handler for the Body binding source and it cannot run twice. Always // tell the model binding system to skip other model binders and never to fall back i.e. indicate a // fatal error. return(new ModelBindingResult(modelBindingKey)); } try { var previousCount = bindingContext.ModelState.ErrorCount; var model = await formatter.ReadAsync(formatterContext); if (bindingContext.ModelState.ErrorCount != previousCount) { // Formatter added an error. Do not use the model it returned. As above, tell the model binding // system to skip other model binders and never to fall back. return(new ModelBindingResult(modelBindingKey)); } var valueProviderResult = new ValueProviderResult(rawValue: model); bindingContext.ModelState.SetModelValue(modelBindingKey, valueProviderResult); var validationNode = new ModelValidationNode(modelBindingKey, bindingContext.ModelMetadata, model) { ValidateAllProperties = true }; return(new ModelBindingResult( model, key: modelBindingKey, isModelSet: true, validationNode: validationNode)); } catch (Exception ex) { bindingContext.ModelState.AddModelError(modelBindingKey, ex); // This model binder is the only handler for the Body binding source and it cannot run twice. Always // tell the model binding system to skip other model binders and never to fall back i.e. indicate a // fatal error. return(new ModelBindingResult(modelBindingKey)); } }
public async Task ReadAsync_AcceptsUTF16Characters() { // Arrange var expectedInt = 10; var expectedString = "TestString"; var expectedDateTime = XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.Utc); var input = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>" + "<TestLevelOne><SampleInt>" + expectedInt + "</SampleInt>" + "<sampleString>" + expectedString + "</sampleString>" + "<SampleDate>" + expectedDateTime + "</SampleDate></TestLevelOne>"; var formatter = new XmlSerializerInputFormatter(); var contentBytes = Encodings.UTF16EncodingLittleEndian.GetBytes(input); var modelState = new ModelStateDictionary(); var httpContext = GetHttpContext(contentBytes, contentType: "application/xml; charset=utf-16"); var context = new InputFormatterContext(httpContext, modelState, typeof(TestLevelOne)); // Act var model = await formatter.ReadAsync(context); // Assert Assert.NotNull(model); Assert.IsType<TestLevelOne>(model); var levelOneModel = model as TestLevelOne; Assert.Equal(expectedInt, levelOneModel.SampleInt); Assert.Equal(expectedString, levelOneModel.sampleString); Assert.Equal(XmlConvert.ToDateTime(expectedDateTime, XmlDateTimeSerializationMode.Utc), levelOneModel.SampleDate); }
private Task<object> ReadInternal(InputFormatterContext context) { var type = context.Metadata.ModelType; var request = context.HttpContext.Request; using (var xmlReader = CreateXmlReader(new DelegatingStream(request.Body))) { var xmlSerializer = CreateXmlSerializer(type); return Task.FromResult(xmlSerializer.Deserialize(xmlReader)); } }
public async Task ReadAsync_UsesContentTypeCharSet_ToReadStream() { // Arrange var expectedException = TestPlatformHelper.IsMono ? typeof(InvalidOperationException) : typeof(XmlException); var expectedMessage = TestPlatformHelper.IsMono ? "There is an error in XML document." : "The expected encoding 'utf-16LE' does not match the actual encoding 'utf-8'."; var inputBytes = Encodings.UTF8EncodingWithoutBOM.GetBytes("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<DummyClass><SampleInt>1000</SampleInt></DummyClass>"); var formatter = new XmlSerializerInputFormatter(); var modelState = new ModelStateDictionary(); var httpContext = GetHttpContext(inputBytes, contentType: "application/xml; charset=utf-16"); var context = new InputFormatterContext(httpContext, modelState, typeof(TestLevelOne)); // Act and Assert var ex = await Assert.ThrowsAsync(expectedException, () => formatter.ReadAsync(context)); Assert.Equal(expectedMessage, ex.Message); }
public Task <InputFormatterResult> ReadAsync(InputFormatterContext context) { return(InputFormatterResult.SuccessAsync(this)); }
public async Task ReadAsync_AcceptsUTF16Characters() { // Arrange var expectedInt = 10; var expectedString = "TestString"; var input = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>" + "<TestLevelOne><SampleInt>" + expectedInt + "</SampleInt>" + "<sampleString>" + expectedString + "</sampleString></TestLevelOne>"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encodings.UTF16EncodingLittleEndian.GetBytes(input); var actionContext = GetActionContext(contentBytes, contentType: "application/xml; charset=utf-16"); var context = new InputFormatterContext(actionContext, typeof(TestLevelOne)); // Act var model = await formatter.ReadAsync(context); // Assert Assert.NotNull(model); Assert.IsType<TestLevelOne>(model); var levelOneModel = model as TestLevelOne; Assert.Equal(expectedInt, levelOneModel.SampleInt); Assert.Equal(expectedString, levelOneModel.sampleString); }
public bool CanRead(InputFormatterContext context) { return _canRead; }
public async Task ReadAsync_AcceptsUTF16Characters() { // Arrange var expectedInt = 10; var expectedString = "TestString"; var input = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>" + "<TestLevelOne><SampleInt>" + expectedInt + "</SampleInt>" + "<sampleString>" + expectedString + "</sampleString></TestLevelOne>"; var formatter = new XmlDataContractSerializerInputFormatter(); var contentBytes = Encoding.Unicode.GetBytes(input); var modelState = new ModelStateDictionary(); var httpContext = GetHttpContext(contentBytes, contentType: "application/xml; charset=utf-16"); var context = new InputFormatterContext( httpContext, modelName: string.Empty, modelState: modelState, modelType: typeof(TestLevelOne)); // Act var result = await formatter.ReadAsync(context); // Assert Assert.NotNull(result); Assert.False(result.HasError); var model = Assert.IsType<TestLevelOne>(result.Model); Assert.Equal(expectedInt, model.SampleInt); Assert.Equal(expectedString, model.sampleString); }
public Task<object> ReadAsync(InputFormatterContext context) { return Task.FromResult<object>(this); }
public async Task ReadAsync_ThrowsOnDeserializationErrors() { // Arrange var content = "{name: 'Person Name', Age: 'not-an-age'}"; var formatter = new JsonInputFormatter(); var contentBytes = Encoding.UTF8.GetBytes(content); var httpContext = GetHttpContext(contentBytes); var modelState = new ModelStateDictionary(); var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(User)); var context = new InputFormatterContext(httpContext, metadata, modelState); // Act and Assert await Assert.ThrowsAsync<JsonReaderException>(() => formatter.ReadAsync(context)); }
private Task<object> ReadInternal(InputFormatterContext context, Encoding effectiveEncoding) { var type = context.Metadata.ModelType; var request = context.HttpContext.Request; using (var jsonReader = CreateJsonReader(context, request.Body, effectiveEncoding)) { jsonReader.CloseInput = false; var jsonSerializer = CreateJsonSerializer(); EventHandler<Newtonsoft.Json.Serialization.ErrorEventArgs> errorHandler = null; if (CaptureDeserilizationErrors) { errorHandler = (sender, e) => { var exception = e.ErrorContext.Error; context.ModelState.AddModelError(e.ErrorContext.Path, e.ErrorContext.Error); // Error must always be marked as handled // Failure to do so can cause the exception to be rethrown at every recursive level and // overflow the stack for x64 CLR processes e.ErrorContext.Handled = true; }; jsonSerializer.Error += errorHandler; } try { return Task.FromResult(jsonSerializer.Deserialize(jsonReader, type)); } finally { // Clean up the error handler in case CreateJsonSerializer() reuses a serializer if (errorHandler != null) { jsonSerializer.Error -= errorHandler; } } } }
public async Task ReadAsync_UsesContentTypeCharSet_ToReadStream() { // Arrange var expectedException = TestPlatformHelper.IsMono ? typeof(SerializationException) : typeof(XmlException); var expectedMessage = TestPlatformHelper.IsMono ? "Expected element 'TestLevelTwo' in namespace '', but found Element node 'DummyClass' in namespace ''" : "The expected encoding 'utf-16LE' does not match the actual encoding 'utf-8'."; var inputBytes = Encoding.UTF8.GetBytes("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<DummyClass><SampleInt>1000</SampleInt></DummyClass>"); var formatter = new XmlDataContractSerializerInputFormatter(); var modelState = new ModelStateDictionary(); var httpContext = GetHttpContext(inputBytes, contentType: "application/xml; charset=utf-16"); var context = new InputFormatterContext( httpContext, modelName: string.Empty, modelState: modelState, modelType: typeof(TestLevelOne)); // Act var ex = await Assert.ThrowsAsync(expectedException, () => formatter.ReadAsync(context)); Assert.Equal(expectedMessage, ex.Message); }
/// <inheritdoc /> protected async override Task<ModelBindingResult> BindModelCoreAsync( [NotNull] ModelBindingContext bindingContext) { // For compatibility with MVC 5.0 for top level object we want to consider an empty key instead of // the parameter name/a custom name. In all other cases (like when binding body to a property) we // consider the entire ModelName as a prefix. var modelBindingKey = bindingContext.IsTopLevelObject ? string.Empty : bindingContext.ModelName; var httpContext = bindingContext.OperationBindingContext.HttpContext; var formatterContext = new InputFormatterContext( httpContext, bindingContext.ModelState, bindingContext.ModelType); var formatters = bindingContext.OperationBindingContext.InputFormatters; var formatter = formatters.FirstOrDefault(f => f.CanRead(formatterContext)); if (formatter == null) { var unsupportedContentType = Resources.FormatUnsupportedContentType( bindingContext.OperationBindingContext.HttpContext.Request.ContentType); bindingContext.ModelState.AddModelError(modelBindingKey, unsupportedContentType); // This model binder is the only handler for the Body binding source and it cannot run twice. Always // tell the model binding system to skip other model binders and never to fall back i.e. indicate a // fatal error. return new ModelBindingResult(modelBindingKey); } try { var previousCount = bindingContext.ModelState.ErrorCount; var model = await formatter.ReadAsync(formatterContext); if (bindingContext.ModelState.ErrorCount != previousCount) { // Formatter added an error. Do not use the model it returned. As above, tell the model binding // system to skip other model binders and never to fall back. return new ModelBindingResult(modelBindingKey); } var valueProviderResult = new ValueProviderResult(rawValue: model); bindingContext.ModelState.SetModelValue(modelBindingKey, valueProviderResult); var validationNode = new ModelValidationNode(modelBindingKey, bindingContext.ModelMetadata, model) { ValidateAllProperties = true }; return new ModelBindingResult( model, key: modelBindingKey, isModelSet: true, validationNode: validationNode); } catch (Exception ex) { bindingContext.ModelState.AddModelError(modelBindingKey, ex); // This model binder is the only handler for the Body binding source and it cannot run twice. Always // tell the model binding system to skip other model binders and never to fall back i.e. indicate a // fatal error. return new ModelBindingResult(modelBindingKey); } }
public async Task ReadAsync_AddsModelValidationErrorsToModelState_WhenCaptureErrorsIsSet() { // Arrange var content = "{name: 'Person Name', Age: 'not-an-age'}"; var formatter = new JsonInputFormatter { CaptureDeserilizationErrors = true }; var contentBytes = Encoding.UTF8.GetBytes(content); var httpContext = GetHttpContext(contentBytes); var modelState = new ModelStateDictionary(); var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(User)); var context = new InputFormatterContext(httpContext, metadata, modelState); // Act await formatter.ReadAsync(context); // Assert Assert.Equal("Could not convert string to decimal: not-an-age. Path 'Age', line 1, position 39.", modelState["Age"].Errors[0].Exception.Message); }