Exemplo n.º 1
0
        /// <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);
            }
        }
Exemplo n.º 2
0
        /// <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);
        }
Exemplo n.º 5
0
        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);
        }
Exemplo n.º 6
0
        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);
        }
Exemplo n.º 8
0
        /// <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);
        }
Exemplo n.º 9
0
 public override Task<object> ReadRequestBodyAsync(InputFormatterContext context)
 {
     throw new InvalidOperationException("Your input is bad!");
 }
Exemplo n.º 10
0
        /// <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));
            }
        }
Exemplo n.º 11
0
 public Task <object> ReadAsync(InputFormatterContext context)
 {
     return(Task.FromResult <object>(this));
 }
Exemplo n.º 12
0
 public bool CanRead(InputFormatterContext context)
 {
     return(_canRead);
 }
Exemplo n.º 13
0
 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);
        }
Exemplo n.º 15
0
 /// <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)));
 }
Exemplo n.º 16
0
        /// <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);
        }
Exemplo n.º 18
0
        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);
        }
Exemplo n.º 20
0
 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);
        }
Exemplo n.º 22
0
 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);
        }
Exemplo n.º 24
0
 public Task<object> ReadAsync(InputFormatterContext context)
 {
     return Task.FromResult<object>(this);
 }
Exemplo n.º 25
0
        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));
        }
Exemplo n.º 26
0
        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);
        }
Exemplo n.º 28
0
        /// <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);
            }
        }
Exemplo n.º 29
0
        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);
        }