public async Task FormFileModelBinder_UsesFieldNameForTopLevelObject(bool isTopLevel, string expected) { // Arrange var formFiles = new FormFileCollection { GetMockFormFile("FieldName", "file1.txt"), GetMockFormFile("ModelName", "file1.txt") }; var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles)); var bindingContext = GetBindingContext(typeof(IFormFile), httpContext); bindingContext.IsTopLevelObject = isTopLevel; bindingContext.FieldName = "FieldName"; bindingContext.ModelName = "ModelName"; var binder = new FormFileModelBinder(NullLoggerFactory.Instance); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.True(bindingContext.Result.IsModelSet); var file = Assert.IsAssignableFrom <IFormFile>(bindingContext.Result.Model); Assert.Equal(expected, file.Name); }
public async Task BindModelAsync(ModelBindingContext bindingContext) { //绑定 对象部分 if (bindingContext == null) { throw new ArgumentNullException(nameof(bindingContext)); } // Retrieve the form part containing the JSON var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.FieldName); if (valueResult == ValueProviderResult.None) { // The JSON was not found var message = bindingContext.ModelMetadata.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(bindingContext.FieldName); bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, message); return; } var rawValue = valueResult.FirstValue; // Deserialize the JSON var model = JsonConvert.DeserializeObject(rawValue, bindingContext.ModelType, _jsonOptions.Value.SerializerSettings); // Now, bind each of the IFormFile properties from the other form parts foreach (var property in bindingContext.ModelMetadata.Properties) { //if (property.ModelType != typeof(IFormFile)) if (property.ModelType != typeof(IFormFile)) { continue; } var fieldName = property.BinderModelName ?? property.PropertyName; var modelName = fieldName; var propertyModel = bindingContext.ValueProvider.GetValue(fieldName); //var propertyModel = property.PropertyGetter(bindingContext.Model); ModelBindingResult propertyResult; using (bindingContext.EnterNestedScope(property, fieldName, modelName, propertyModel)) { await _formFileModelBinder.BindModelAsync(bindingContext); propertyResult = bindingContext.Result; } if (propertyResult.IsModelSet) { // The IFormFile was sucessfully bound, assign it to the corresponding property of the model property.PropertySetter(model, propertyResult.Model); } else if (property.IsBindingRequired) { var message = property.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(fieldName); bindingContext.ModelState.TryAddModelError(modelName, message); } } // Set the successfully constructed model as the result of the model binding bindingContext.Result = ModelBindingResult.Success(model); }
public async Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) { throw new ArgumentNullException(paramName: nameof(bindingContext)); } //recupere a parte do formulario que contem o JSon var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.FieldName); if (valueResult == ValueProviderResult.None) { // O JSon não foi encontrado var message = bindingContext.ModelMetadata.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(bindingContext.FieldName); bindingContext.ModelState.TryAddModelError(key: bindingContext.ModelName, message); return; } var rawValue = valueResult.FirstValue; // desserializar o modelo JSON var model = JsonConvert.DeserializeObject(rawValue, bindingContext.ModelType, _jsonOptions.Value.SerializerSettings); //Agora, vincule cada uma das propriedades IFormFile das outras partes do formulário foreach (var property in bindingContext.ModelMetadata.Properties) { if (property.ModelType != typeof(IFormFile)) { continue; } var fieldName = property.BinderModelName ?? property.PropertyName; var modelName = fieldName; var propertyModel = property.PropertyGetter(bindingContext.Model); ModelBindingResult propertyResult; using (bindingContext.EnterNestedScope(property, fieldName, modelName, propertyModel)) { await _formFileModelBinder.BindModelAsync(bindingContext); propertyResult = bindingContext.Result; } if (propertyResult.IsModelSet) { // O IFormFile foi vinculado com sucesso, atribua - o à propriedade correspondente da propriedade do modelo PropertySetter property.PropertySetter(model, propertyResult.Model); } else if (property.IsBindingRequired) { var message = property.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(fieldName); bindingContext.ModelState.TryAddModelError(key: modelName, message); } } //Defina o modelo construído com sucesso como resultado do modelo binding bindingContext.Result = ModelBindingResult.Success(model); }
public async Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) { throw new ArgumentNullException(nameof(bindingContext)); } var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.FieldName); if (valueResult == ValueProviderResult.None) { string message = bindingContext.ModelMetadata.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(bindingContext.FieldName); bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, message); return; } string rawValue = valueResult.FirstValue; object model = JsonSerializer.Deserialize(rawValue, bindingContext.ModelType); foreach (var property in bindingContext.ModelMetadata.Properties) { if (property.ModelType != typeof(IFormFile)) { continue; } string fieldName = property.BinderModelName ?? property.PropertyName; string modelName = fieldName; object propertyModel = property.PropertyGetter(bindingContext.Model); ModelBindingResult propertyResult; using (bindingContext.EnterNestedScope(property, fieldName, modelName, propertyModel)) { await _formFileModelBinder.BindModelAsync(bindingContext); propertyResult = bindingContext.Result; } if (propertyResult.IsModelSet) { property.PropertySetter(model, propertyResult.Model); } else if (property.IsBindingRequired) { string message = property.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(fieldName); bindingContext.ModelState.TryAddModelError(modelName, message); } } bindingContext.Result = ModelBindingResult.Success(model); }
public async Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) { throw new ArgumentNullException(nameof(bindingContext)); } var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.FieldName); if (valueResult == ValueProviderResult.None) { var message = bindingContext.ModelMetadata.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(bindingContext.FieldName); bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, message); return; } var rawValue = valueResult.FirstValue; var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; var model = JsonSerializer.Deserialize(rawValue, bindingContext.ModelType, options); foreach (ModelMetadata property in bindingContext.ModelMetadata.Properties) { if (property.ModelType != typeof(IFormFile) && property.ModelType != typeof(IFormFile[]) && property.ModelType != typeof(List <IFormFile>)) { continue; } var fieldName = property.BinderModelName ?? property.PropertyName; var modelName = fieldName; var propertyModel = property.PropertyGetter(bindingContext.Model); ModelBindingResult propertyResult; using (bindingContext.EnterNestedScope(property, fieldName, modelName, propertyModel)) { await formFileModelBinder.BindModelAsync(bindingContext).ConfigureAwait(false); propertyResult = bindingContext.Result; } if (propertyResult.IsModelSet) { property.PropertySetter(model, propertyResult.Model); } else if (property.IsBindingRequired) { var message = property.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(fieldName); bindingContext.ModelState.TryAddModelError(modelName, message); } } bindingContext.Result = ModelBindingResult.Success(model); }
public async Task FormFileModelBinder_ReturnsResult_ForReadOnlyDestination() { // Arrange var binder = new FormFileModelBinder(NullLoggerFactory.Instance); var formFiles = GetTwoFiles(); var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles)); var bindingContext = GetBindingContextForReadOnlyArray(httpContext); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.True(bindingContext.Result.IsModelSet); Assert.NotNull(bindingContext.Result.Model); }
public async Task FormFileModelBinder_ReturnsFailedResult_ForCollectionsItCannotCreate() { // Arrange var binder = new FormFileModelBinder(NullLoggerFactory.Instance); var formFiles = GetTwoFiles(); var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles)); var bindingContext = GetBindingContext(typeof(ISet <IFormFile>), httpContext); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.False(bindingContext.Result.IsModelSet); Assert.Null(bindingContext.Result.Model); }
public async Task FormFileModelBinder_BindsFiles_ForCollectionsItCanCreate(Type destinationType) { // Arrange var binder = new FormFileModelBinder(NullLoggerFactory.Instance); var formFiles = GetTwoFiles(); var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles)); var bindingContext = GetBindingContext(destinationType, httpContext); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.True(bindingContext.Result.IsModelSet); Assert.IsAssignableFrom(destinationType, bindingContext.Result.Model); Assert.Equal(formFiles, bindingContext.Result.Model as IEnumerable <IFormFile>); }
public async Task FormFileModelBinder_ExpectSingleFile_BindFirstFile() { // Arrange var formFiles = GetTwoFiles(); var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles)); var bindingContext = GetBindingContext(typeof(IFormFile), httpContext); var binder = new FormFileModelBinder(NullLoggerFactory.Instance); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.True(bindingContext.Result.IsModelSet); var file = Assert.IsAssignableFrom <IFormFile>(bindingContext.Result.Model); Assert.Equal("file1.txt", file.FileName); }
public async Task FormFileModelBinder_ReturnsFailedResult_WithNoFileNameAndZeroLength() { // Arrange var formFiles = new FormFileCollection { GetMockFormFile("file", "") }; var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles)); var bindingContext = GetBindingContext(typeof(IFormFile), httpContext); var binder = new FormFileModelBinder(NullLoggerFactory.Instance); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.False(bindingContext.Result.IsModelSet); Assert.Null(bindingContext.Result.Model); }
public async Task FormFileModelBinder_ReturnsFailedResult_WhenNamesDoNotMatch() { // Arrange var formFiles = new FormFileCollection { GetMockFormFile("different name", "file1.txt") }; var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles)); var bindingContext = GetBindingContext(typeof(IFormFile), httpContext); var binder = new FormFileModelBinder(NullLoggerFactory.Instance); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.False(bindingContext.Result.IsModelSet); Assert.Null(bindingContext.Result.Model); }
public async Task FormFileModelBinder_ReturnsFailedResult_WithEmptyContentDisposition() { // Arrange var formFiles = new FormFileCollection { new Mock <IFormFile>().Object }; var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles)); var bindingContext = GetBindingContext(typeof(IFormFile), httpContext); var binder = new FormFileModelBinder(NullLoggerFactory.Instance); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.False(bindingContext.Result.IsModelSet); Assert.Null(bindingContext.Result.Model); }
public async Task FormFileModelBinder_SingleFileWithinTopLevelPoco_BindSuccessfully_WithShortenedModelName() { // Arrange const string propertyName = nameof(NestedFormFiles.Files); var formFiles = new FormFileCollection { GetMockFormFile($"FileList.{propertyName}", "file1.txt") }; var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles)); var binder = new FormFileModelBinder(NullLoggerFactory.Instance); // Mimic ParameterBinder overwriting ModelName on top level model then ComplexTypeModelBinder entering a // nested context for the NestedFormFiles property. In this non-top-level binding case, FormFileModelBinder // tries ModelName then falls back to add an (OriginalModelName + ".") prefix. var propertyInfo = typeof(NestedFormFiles).GetProperty(propertyName); var metadata = new EmptyModelMetadataProvider().GetMetadataForProperty( propertyInfo, propertyInfo.PropertyType); var bindingContext = DefaultModelBindingContext.CreateBindingContext( new ActionContext { HttpContext = httpContext }, Mock.Of <IValueProvider>(), metadata, bindingInfo: null, modelName: "FileList"); bindingContext.IsTopLevelObject = false; bindingContext.Model = new FileList(); bindingContext.ModelName = propertyName; // Act await binder.BindModelAsync(bindingContext); // Assert Assert.True(bindingContext.Result.IsModelSet); var entry = bindingContext.ValidationState[bindingContext.Result.Model]; Assert.False(entry.SuppressValidation); Assert.Equal($"FileList.{propertyName}", entry.Key); Assert.Null(entry.Metadata); }
public async Task FormFileModelBinder_SingleFileWithinTopLevelPoco_BindSuccessfully() { // Arrange const string propertyName = nameof(NestedFormFiles.Files); var formFiles = new FormFileCollection { GetMockFormFile($"{propertyName}", "file1.txt") }; var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles)); var binder = new FormFileModelBinder(NullLoggerFactory.Instance); // In this non-top-level binding case, FormFileModelBinder tries ModelName and succeeds. var propertyInfo = typeof(NestedFormFiles).GetProperty(propertyName); var metadata = new EmptyModelMetadataProvider().GetMetadataForProperty( propertyInfo, propertyInfo.PropertyType); var bindingContext = DefaultModelBindingContext.CreateBindingContext( new ActionContext { HttpContext = httpContext }, Mock.Of <IValueProvider>(), metadata, bindingInfo: null, modelName: "FileList"); bindingContext.IsTopLevelObject = false; bindingContext.Model = new FileList(); bindingContext.ModelName = propertyName; // Act await binder.BindModelAsync(bindingContext); // Assert Assert.True(bindingContext.Result.IsModelSet); var entry = bindingContext.ValidationState[bindingContext.Result.Model]; Assert.False(entry.SuppressValidation); Assert.Equal($"{propertyName}", entry.Key); Assert.Null(entry.Metadata); }
public async Task FormFileModelBinder_SingleFileWithinTopLevelDictionary_BindSuccessfully_WithShortenedModelName() { // Arrange var formFiles = new FormFileCollection { GetMockFormFile("FileDictionary[myFile]", "file1.txt") }; var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles)); var binder = new FormFileModelBinder(NullLoggerFactory.Instance); // Mimic ParameterBinder overwriting ModelName on top level model then DictionaryModelBinder entering a // nested context for the KeyValuePair.Value property. In this non-top-level binding case, // FormFileModelBinder tries ModelName then falls back to add an OriginalModelName prefix. var bindingContext = DefaultModelBindingContext.CreateBindingContext( new ActionContext { HttpContext = httpContext }, Mock.Of <IValueProvider>(), new EmptyModelMetadataProvider().GetMetadataForType(typeof(IFormFile)), bindingInfo: null, modelName: "FileDictionary"); bindingContext.IsTopLevelObject = false; bindingContext.ModelName = "[myFile]"; // Act await binder.BindModelAsync(bindingContext); // Assert Assert.True(bindingContext.Result.IsModelSet); var entry = bindingContext.ValidationState[bindingContext.Result.Model]; Assert.False(entry.SuppressValidation); Assert.Equal("FileDictionary[myFile]", entry.Key); Assert.Null(entry.Metadata); }
public async Task FormFileModelBinder_SingleFile_BindSuccessful() { // Arrange var formFiles = new FormFileCollection { GetMockFormFile("file", "file1.txt") }; var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles)); var bindingContext = GetBindingContext(typeof(IEnumerable <IFormFile>), httpContext); var binder = new FormFileModelBinder(NullLoggerFactory.Instance); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.True(bindingContext.Result.IsModelSet); var entry = bindingContext.ValidationState[bindingContext.Result.Model]; Assert.False(entry.SuppressValidation); Assert.Equal("file", entry.Key); Assert.Null(entry.Metadata); }
public async Task FormFileModelBinder_SingleFileAtTopLevel_BindSuccessfully_WithEmptyModelName() { // Arrange var formFiles = new FormFileCollection { GetMockFormFile("file", "file1.txt") }; var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles)); var binder = new FormFileModelBinder(NullLoggerFactory.Instance); // Mimic ParameterBinder overwriting ModelName on top level model. In this top-level binding case, // FormFileModelBinder uses FieldName from the get-go. (OriginalModelName will be checked but ignored.) var bindingContext = DefaultModelBindingContext.CreateBindingContext( new ActionContext { HttpContext = httpContext }, Mock.Of <IValueProvider>(), new EmptyModelMetadataProvider().GetMetadataForType(typeof(IFormFile)), bindingInfo: null, modelName: "file"); bindingContext.ModelName = string.Empty; // Act await binder.BindModelAsync(bindingContext); // Assert Assert.True(bindingContext.Result.IsModelSet); var entry = bindingContext.ValidationState[bindingContext.Result.Model]; Assert.False(entry.SuppressValidation); Assert.Equal("file", entry.Key); Assert.Null(entry.Metadata); }
public async Task FormFileModelBinder_SingleFileWithinTopLevelDictionary_BindSuccessfully() { // Arrange var formFiles = new FormFileCollection { GetMockFormFile("[myFile]", "file1.txt") }; var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles)); var binder = new FormFileModelBinder(NullLoggerFactory.Instance); // In this non-top-level binding case, FormFileModelBinder tries ModelName and succeeds. var bindingContext = DefaultModelBindingContext.CreateBindingContext( new ActionContext { HttpContext = httpContext }, Mock.Of <IValueProvider>(), new EmptyModelMetadataProvider().GetMetadataForType(typeof(IFormFile)), bindingInfo: null, modelName: "FileDictionary"); bindingContext.IsTopLevelObject = false; bindingContext.ModelName = "[myFile]"; // Act await binder.BindModelAsync(bindingContext); // Assert Assert.True(bindingContext.Result.IsModelSet); var entry = bindingContext.ValidationState[bindingContext.Result.Model]; Assert.False(entry.SuppressValidation); Assert.Equal("[myFile]", entry.Key); Assert.Null(entry.Metadata); }
public async Task FormFileModelBinder_ExpectMultipleFiles_BindSuccessful() { // Arrange var formFiles = GetTwoFiles(); var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles)); var bindingContext = GetBindingContext(typeof(IEnumerable <IFormFile>), httpContext); var binder = new FormFileModelBinder(NullLoggerFactory.Instance); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.True(bindingContext.Result.IsModelSet); var entry = bindingContext.ValidationState[bindingContext.Result.Model]; Assert.False(entry.SuppressValidation); Assert.Equal("file", entry.Key); Assert.Null(entry.Metadata); var files = Assert.IsAssignableFrom <IList <IFormFile> >(bindingContext.Result.Model); Assert.Equal(2, files.Count); }
public async Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) { throw new ArgumentNullException(nameof(bindingContext)); } // Retrieve the form part containing the JSON var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.FieldName); if (valueResult == ValueProviderResult.None) { // The JSON was not found var message = bindingContext.ModelMetadata.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(bindingContext.FieldName); bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, message); var initialBody = bindingContext.HttpContext.Request.Body; // Workaround bindingContext.HttpContext.Request.EnableBuffering(); var buffer = new byte[Convert.ToInt32(bindingContext.HttpContext.Request.ContentLength)]; await bindingContext.HttpContext.Request.Body.ReadAsync(buffer, 0, buffer.Length); var json = Encoding.UTF8.GetString(buffer); bindingContext.HttpContext.Request.Body = initialBody; var modelFromBody = JsonConvert.DeserializeObject(json, bindingContext.ModelType, _jsonOptions.Value.SerializerSettings); bindingContext.Result = ModelBindingResult.Success(modelFromBody); return; } var rawValue = valueResult.FirstValue; // Deserialize the JSON var model = JsonConvert.DeserializeObject(rawValue, bindingContext.ModelType, _jsonOptions.Value.SerializerSettings); // Now, bind each of the IFormFile properties from the other form parts foreach (var property in bindingContext.ModelMetadata.Properties) { if (property.ModelType != typeof(IFormFile) && property.ModelType != typeof(ICollection <IFormFile>) && property.ModelType != typeof(IEnumerable <IFormFile>)) { continue; } var fieldName = property.BinderModelName ?? property.PropertyName; var modelName = fieldName; var propertyModel = property.PropertyGetter(bindingContext.Model); ModelBindingResult propertyResult; using (bindingContext.EnterNestedScope(property, fieldName, modelName, propertyModel)) { await _formFileModelBinder.BindModelAsync(bindingContext); propertyResult = bindingContext.Result; } if (propertyResult.IsModelSet) { // The IFormFile was sucessfully bound, assign it to the corresponding property of the model property.PropertySetter(model, propertyResult.Model); } else if (property.IsBindingRequired) { var message = property.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(fieldName); bindingContext.ModelState.TryAddModelError(modelName, message); } } // Set the successfully constructed model as the result of the model binding bindingContext.Result = ModelBindingResult.Success(model); }