ASP.NET中Change事件下从View向Controller传递IFormFile模型值的问题及相关技术咨询
Let's break down your problems one by one and fix them step by step:
1. Fixing the null ViewModel issue in Controller
The main reason your DailySelectedProductViewModel is coming through as null is twofold: you're not correctly retrieving the ProductId from the UI, and you're sending a plain JavaScript object instead of properly structured FormData (required for file uploads in ASP.NET). Here's how to resolve this:
Step 1: Correctly fetch ProductId from the DOM
Your current code var product_Id = (this.ProductId); doesn't actually grab the ProductId value. Instead, pull it from the hidden input in the same list item as the file uploader:
// Get the parent list item containing the current upload component var listItem = $(this).closest("li"); // Retrieve ProductId from the hidden input field var product_Id = listItem.find("input[type='hidden'][name*='ProductId']").val();
Step 2: Properly construct and send FormData
File uploads require using FormData to package data correctly, and you need to match the keys in FormData to the property names in your ViewModel. Update your AJAX code like this:
$(".uploadFile").on('change', function () { console.log('new file uploaded'); var listItem = $(this).closest("li"); var file_data = $(this).find(".productImage").prop("files")[0]; var files = event.target.files; // Update preview image $(this).find(".imageViewer").attr("src", window.URL.createObjectURL(files[0])); // Initialize FormData and append values matching ViewModel properties var form_data = new FormData(); form_data.append("ProductId", product_Id); form_data.append("ProductImage", file_data); $.ajax({ url: "/DailyMenuPlanner/AddPhoto", cache: false, contentType: false, processData: false, data: form_data, // Send FormData instead of a plain object type: 'post', success: function (result) { alert(result.success ? "success!" : "fail!"); }, error: function(xhr) { console.log("Error details:", xhr.responseText); // Add debug logging for issues } }); });
Step 3: Verify your ViewModel structure
Ensure your DailySelectedProductViewModel has public getters and setters (required for ASP.NET model binding):
public class DailySelectedProductViewModel { public int ProductId { get; set; } public IFormFile ProductImage { get; set; } // Add other properties as needed }
Note: You can remove the redundant asp-for-ProductId attribute from your file input in the HTML—asp-for="@Model.Products[i].ProductImage" already generates the correct name attribute for binding.
2. Converting IFormFile to a byte array
Your existing conversion code is valid, but we can refine it to add error handling and ensure proper resource disposal:
[HttpPost] public async Task<JsonResult> AddPhoto(DailySelectedProductViewModel dataModel) { // Validate input first if (dataModel.ProductImage == null || dataModel.ProductImage.Length == 0) { return Json(new { success = false, message = "No file was uploaded" }); } byte[] imageAsArray; // Use using statements to ensure streams are disposed properly using (var memoryStream = new MemoryStream()) { await dataModel.ProductImage.CopyToAsync(memoryStream); imageAsArray = memoryStream.ToArray(); } // Use imageAsArray for storage or further processing here return Json(new { success = true, fileName = dataModel.ProductImage.FileName }); }
An alternative, more direct approach:
using (var fileStream = dataModel.ProductImage.OpenReadStream()) using (var memoryStream = new MemoryStream()) { await fileStream.CopyToAsync(memoryStream); imageAsArray = memoryStream.ToArray(); }
3. Storing file data in SQL Server
- About the
imagetype: While SQL Server'simagetype can technically store byte array data, it's deprecated (since SQL Server 2005). Microsoft strongly recommends usingVARBINARY(MAX)instead—it's designed specifically for large binary data like images, documents, etc., and supports modern features. - Storing the byte array: You can directly save the byte array to a
VARBINARY(MAX)column in your table. If using Entity Framework, your entity class would have a property likepublic byte[] ProductImageData { get; set; }, which automatically maps to theVARBINARY(MAX)column.
内容的提问来源于stack exchange,提问作者Paul

