MVC EF如何同时添加图像和其他数据库的值
MVC EF如何同时添加图像和其他数据库的值
我正在寻求在将图像(作为字节!)上传到数据库时的支持,同时还要上传其他属性。我必须承认,作为一个编程新手,我在完成这个任务时遇到了一些困难,但是我基本上搞定了。现在我的问题是,每当我尝试利用这个模型时,它就会停止工作,并弹出以下错误消息:
输入不是有效的Base-64字符串,因为它包含一个非Base-64字符,超过两个填充字符,或在填充字符中包含非法字符。
ViewModel:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Data.Entity; using System.Data.Entity.ModelConfiguration.Conventions; using System.ComponentModel.DataAnnotations; namespace errandomWeb.Models { public class PhotoCompetition { public int ID { get; set; } public string UserID { get; set; } public string FirstName { get; set; } public string Email { get; set; } public byte[] CompetitionPicture { get; set; } //[Required] [Display(Name = "通过勾选此框,我接受条款和条件")] //[CheckBoxRequired(ErrorMessage = "请接受我们的条款和条件参与活动。")] public bool TermsAndConditionsAccepted { get; set; } public DateTime TimeStamp { get; set; } } }
View:
@model errandomWeb.Models.PhotoCompetition
@{
ViewBag.Title = "成为我们的模特";
}
@ViewBag.Title
你好
@Html.TextBoxFor(m => m.FirstName, new { @id = "photoCompetitionHeaderUserName", @class = "manageHeaderUserName", @placeholder = "陌生人", @disabled = true })
@Html.Partial("_ProfileLogout")
想成为我们的模特吗?
@Html.ValidationSummary("", new { @id = "photoCompetitionValidation", @class = "manageValidation" })
@using (Html.BeginForm("UploadCompetitionPicture", "errandom", FormMethod.Post, new { @id = "photoCompetitionForm", @class = "form-horizontal", @role = "form", @enctype = "multipart/form-data" }))
{
@Html.AntiForgeryToken()
上传您的照片并成为我们的模特!
@Html.HiddenFor(m => m.UserID)
@Html.HiddenFor(m => m.Email)
@Html.HiddenFor(m => m.FirstName)
@Html.HiddenFor(m => m.TimeStamp)
@Html.LabelFor(m => m.CompetitionPicture, new { @id = "photoCompetitionProfilePictureLabel", @class = "manageLabel col-xs-offset-1 col-xs-10 col-sm-offset-1 col-sm-10 col-md-offset-1 col-md-3 col-lg-offset-1 col-lg-4" })
选择文件...
@Html.TextBoxFor(m => m.CompetitionPicture, new { @id = "photoCompetitionProfilePictureField", @class = "manageField col-xs-offset-1 col-xs-10 col-sm-offset-1 col-sm-10 col-md-offset-0 col-md-7 col-lg-offset-0 col-lg-6", @type = "file", @style = "display: none" })
@Html.CheckBoxFor(m => m.TermsAndConditionsAccepted, new { @id = "photoCompetitionTermsAndConditionsField", @class = "photoCompetitionTermsAndConditionsField" })
@Html.LabelFor(m => m.TermsAndConditionsAccepted, new { @id = "photoCompetitionTermsAndConditionsLabel", @class = "photoCompetitionTermsAndConditionsLabel" })
@Html.ValidationMessageFor(m => m.TermsAndConditionsAccepted, "", new { @id = "photoCompetitionTermsAndConditionsValidation", @class = "manageValidation col-xs-offset-1 col-xs-10 col-sm-offset-1 col-sm-10 col-md-offset-4 col-md-7 col-lg-offset-5 col-lg-6" })
jQuery("#photoCompetitionProfilePictureSelectionButton").click(function () {
$("#photoCompetitionProfilePictureField").click();
});
$("#photoCompetitionProfilePictureField").change(function () {
var fullFileName = $("#photoCompetitionProfilePictureField").val()
$("#photoCompetitionProfilePictureSelectionButton").html(fullFileName.substr(fullFileName.lastIndexOf('\\') + 1));
});
}
@Html.ActionLink("返回菜单", "Index", "", htmlAttributes: new { @id = "photoCompetitionReturnToMenuButton", @class = "manageReturnToMenuButton" })
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
$(function () {
if ($('#photoCompetitionCroppingArea').width() > 700) {
$('#photoCompetitionProfilePictureField').change(function () {
$('#photoCompetitionOriginal').hide();
var reader = new FileReader();
reader.onload = function (e) {
$('#photoCompetitionOriginal').show();
$('#photoCompetitionOriginal').attr("src", e.target.result);
$('#photoCompetitionOriginal').Jcrop({
onChange: SetCoordinates,
onSelect: SetCoordinates,
aspectRatio: 1,
boxWidth: 600,
addClass: 'photoCompetitionCropping'
});
}
reader.readAsDataURL($(this)[0].files[0]);
});
}
else {
$('#photoCompetitionProfilePictureField').change(function () {
$('#photoCompetitionOriginal').hide();
var reader = new FileReader();
reader.onload = function (e) {
$('#photoCompetitionOriginal').show();
$('#photoCompetitionOriginal').attr("src", e.target.result);
$('#photoCompetitionOriginal').Jcrop({
onChange: SetCoordinates,
onSelect: SetCoordinates,
aspectRatio: 1,
boxWidth: 250,
addClass: 'photoCompetitionCropping'
});
}
reader.readAsDataURL($(this)[0].files[0]);
});
}
$('#photoCompetitionButtonCrop').click(function () {
var x1 = $('#photoCompetitionCropX').val();
var y1 = $('#photoCompetitionCropY').val();
var height = $('#photoCompetitionCropH').val();
var width = $('#photoCompetitionCropW').val();
var canvas = $("#photoCompetitionCropped")[0];
var context = canvas.getContext('2d');
var img = new Image();
img.onload = function () {
canvas.height = height;
canvas.width = width;
context.drawImage(img, x1, y1, width, height, 0, 0, width, height);
$('#photoCompetitionCroppedPicture').val(canvas.toDataURL());
$('#photoCompetitionButtonUpload').show();
$('#photoCompetitionCropped').hide();
$('#photoCompetitionButtonCrop').hide();
};
img.src = $('#photoCompetitionOriginal').attr("src");
});
});
function SetCoordinates(c) {
$('#photoCompetitionCropX').val(c.x);
$('#photoCompetitionCropY').val(c.y);
$('#photoCompetitionCropW').val(c.w);
$('#photoCompetitionCropH').val(c.h);
$('#photoCompetitionButtonCrop').show();
};
}
Controller:
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity; using System.IO; using System.Linq; using System.Net; using System.Threading.Tasks; using System.Web; using System.Web.Mvc; using errandomWeb.Models; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.Owin; namespace errandomWeb.Controllers { [Authorize] public class errandomController : Controller { private ApplicationDbContext DB = new ApplicationDbContext(); // GET: /errandom/PhotoCompetition public ActionResult PhotoCompetition() { var model = new PhotoCompetition { UserID = User.Identity.GetUserId(), Email = User.Identity.GetUserName(), FirstName = User.Identity.Name, TimeStamp = DateTime.UtcNow.ToUniversalTime() }; return View(model); } // POST: /errandom/PhotoCompetition // To protect from overposting attacks, please enable the specific properties you want to bind to, for // more details see https://go.microsoft.com/fwlink/?LinkId=317598. [HttpPost] [ValidateAntiForgeryToken] public ActionResult UploadCompetitionPicture() { string croppedImage = Request.Form["photoCompetitionCroppedPicture"]; byte[] imageBytes = Convert.FromBase64String(croppedImage.Split(',')[1]); var userId = User.Identity.GetUserId(); var participation = new PhotoCompetition { CompetitionPicture = imageBytes, UserID = User.Identity.GetUserId(), FirstName = "testcase", Email = User.Identity.GetUserName(), TermsAndConditionsAccepted = false, TimeStamp = DateTime.UtcNow.ToUniversalTime(), }; DB.PhotoCompetition.Add(participation); DB.SaveChanges(); return View("Edit"); } } }
我想包含
TermsAndConditionsAccepted = model.TermsAndConditionsAccepted
所以该值实际上是从用户填写的表单中获取的,但由于上述原因,我遇到了问题。
非常感谢在这里得到的任何帮助,谢谢!
问题的原因是在上传图片和其他数据库值时遇到了困难。问题最终通过在控制器代码中对图片进行排除,然后分别添加其他字段和图片来解决。
解决方法是使用不同的类来作为视图模型和实体框架数据模型,并使用数据传输对象(DTO)。在DTO中,将CompetitionPicture属性定义为字符串而不是字节数组,并在设置模型的CompetitionPicture值时进行转换。这种设计更好,因为不需要将内部模型细节暴露给视图。
使用DTO的一些好处可以参考:[learn.microsoft.com/en-us/aspnet/web-api/overview/data/using-web-api-with-entity-framework/part-5](https://learn.microsoft.com/en-us/aspnet/web-api/overview/data/using-web-api-with-entity-framework/part-5)
问题出现的原因是在使用模型时,尝试将图像保存到数据库时发生了错误。在使用模型时,控制器中的Convert
方法调用的Split
方法返回了错误的结果,导致无法解码base64字符串。问题可能出在客户端javascript代码中生成base64字符串的函数toDataURL()
,该函数返回的值包含了一个前缀,取决于图像的格式。默认情况下,toDataURL()
函数使用png格式,返回的值的前缀类似于data:image/png;base64,...
。实际的值位于前缀之后,通过逗号分隔,因此需要使用split
方法将其读取到控制器中。可能是由于接收到的格式前缀不同,导致split
方法无法正确获取值。可以通过在客户端使用console.log(canvas.toDataURL())
来调试并查看实际的值。可能会发现服务器接收到的值与客户端生成的值不同(可能被截断)。可以比较客户端中值的控制台输出和服务器中变量croppedImage
的内容或Split
后的值。建议使用正则表达式来移除base64值中不需要的前缀,这样更安全。在链接中可以找到一些示例正则表达式的用法。如果使用模型时出现问题,而不使用模型时可以正常工作,建议检查一下在控制器中变量croppedImage
的值,在更改模型时是否有任何不同。可以将croppedImage
的值(或至少字符串的开头部分)粘贴在这里,以便查看发生了什么。目前没有想到与EF相关的原因会导致这个异常,因为异常是由Convert.FromBase64String
引起的。