I am trying to add an editing function to a DB record that a user submitted. The thing is, that there is a picture (as byte) in the mix. The picture has previously been cropped (mainly for styling reasons) and of course, a user would need to have the option to a) keep the existing picture or b) select and crop a new picture. The following code works fine if a user submits a new picture, but in case there is no new picture, it would override the existing one instead of keeping the one the user previously uploaded.
Here's my controller:
// POST: EditErrand
public ActionResult UpdateErrand([Bind(Exclude = "Picture")]EditErrandsViewModel model)
{
string newPic = Request.Form["editErrandCroppedPicture"];
byte[] imageBytes = Convert.FromBase64String(newPic);
var userId = User.Identity.GetUserId();
var errand = new EditErrandsViewModel
{
ID = model.ID,
UserID = User.Identity.GetUserId(),
FirstName = UserManager.FindById(userId).FirstName,
Email = UserManager.FindById(userId).Email,
Phone = UserManager.FindById(userId).PhoneNumber,
Hometown = UserManager.FindById(userId).Hometown,
Rating = model.Rating,
Category = model.Category,
SubCategory = model.SubCategory,
Title = model.Title,
Description = model.Description,
Location = model.Location,
ASAP = model.ASAP,
StartDateTime = model.StartDateTime,
DurationInHours = model.DurationInHours,
EndDateTime = model.EndDateTime,
DateTimePosted = DateTime.UtcNow.ToUniversalTime(),
Currency = model.Currency,
Offering = model.Offering,
Price = model.Price,
errandTax = model.errandTax,
PaymentMethod = model.PaymentMethod,
LatitudePosted = model.LatitudePosted,
LongitudePosted = model.LongitudePosted,
LocationPosted = model.LocationPosted,
UserActivityLatitude = model.LatitudePosted,
UserActivityLongitude = model.LongitudePosted,
UserActivityLocation = model.LocationPosted,
Published = false
};
if (imageBytes.Length > 2)
{
errand.Picture = imageBytes;
}
DB.Entry(errand).State = EntityState.Modified;
DB.SaveChanges();
var Success = new UserActivities
{
ActivityName = "EditErrand_Success",
UserID = User.Identity.GetUserId(),
ActivityTimeStamp = DateTime.Now.ToUniversalTime(),
ActivityLatitude = model.UserActivityLatitude,
ActivityLongitude = model.UserActivityLongitude,
ActivityLocation = model.UserActivityLocation
};
DB.UserActivityList.Add(Success);
DB.SaveChanges();
return RedirectToAction("errandPreview");
}
The controller has the following statement in there because if a user does not upload a file, it would still write 0x to the DB.
if (imageBytes.Length > 2)
{
errand.Picture = imageBytes;
}
For the sake of completeness I have added the relevant part of the view as well, so you get an idea on how cropping (using JCrop) is done:
<div id="editErrandPictureDisplay" class="errandomDisplay 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">
<img id="editErrandPicture" class="editErrandPicture" src="@Url.Action("errandPicture", "errandom")" />
</div>
<div id="editErrandPictureArea" class="manageArea row">
@Html.LabelFor(m => m.Picture, new { @id = "editErrandPictureLabel", @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" })
<a id="editErrandPictureSelectionButton" 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" href="#">
select a file...
</a>
@Html.TextBoxFor(m => m.Picture, new { @id = "editErrandPictureField", @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" })
</div>
<hr />
<script>
jQuery("#editErrandPictureSelectionButton").click(function () {
$("#editErrandPictureField").click();
$("#editErrandCroppingArea").show();
});
</script>
<script>
$("#editErrandPictureField").change(function () {
var fullFileName = $("#editErrandPictureField").val()
$("#editErrandPictureSelectionButton").html(fullFileName.substr(fullFileName.lastIndexOf('\\') + 1));
});
</script>
<div id="editErrandCroppingArea" class="manageArea row" style="display: none">
<img id="editErrandOriginal" class="editErrandImage" src="" alt="" style="display: none" />
<canvas id="editErrandCropped" class="editErrandImage" height="5" width="5"></canvas>
<input id="editErrandButtonCrop" class="manageButton col-xs-offset-1 col-xs-10 col-sm-offset-1 col-sm-10 col-md-offset-1 col-md-10 col-lg-offset-1 col-lg-10" type="button" value="Crop" />
<input id="editErrandCropX" class="editErrandData" name="editErrandCropX" type="hidden" />
<input id="editErrandCropY" class="editErrandData" name="editErrandCropY" type="hidden" />
<input id="editErrandCropW" class="editErrandData" name="editErrandCropW" type="hidden" />
<input id="editErrandCropH" class="editErrandData" name="editErrandCropH" type="hidden" />
<input id="editErrandCroppedPicture" class="editErrandData" name="editErrandCroppedPicture" type="hidden" />
</div>
<script type="text/javascript">
$(function () {
if ($('#editErrandCroppingArea').width() > 500) {
$('#editErrandPictureField').change(function () {
$('#editErrandOriginal').hide();
var reader = new FileReader();
reader.onload = function (e) {
$('#editErrandOriginal').show();
$('#editErrandOriginal').attr("src", e.target.result);
$('#editErrandOriginal').Jcrop({
onChange: SetCoordinates,
onSelect: SetCoordinates,
aspectRatio: 1,
boxWidth: 450,
addClass: 'editErrandCropping'
});
}
reader.readAsDataURL($(this)[0].files[0]);
});
}
else {
$('#editErrandPictureField').change(function () {
$('#editErrandOriginal').hide();
var reader = new FileReader();
reader.onload = function (e) {
$('#editErrandOriginal').show();
$('#editErrandOriginal').attr("src", e.target.result);
$('#editErrandOriginal').Jcrop({
onChange: SetCoordinates,
onSelect: SetCoordinates,
aspectRatio: 1,
boxWidth: 250,
addClass: 'editErrandCropping'
});
}
reader.readAsDataURL($(this)[0].files[0]);
});
}
$('#editErrandButtonCrop').click(function () {
var x1 = $('#editErrandCropX').val();
var y1 = $('#editErrandCropY').val();
var height = $('#editErrandCropH').val();
var width = $('#editErrandCropW').val();
var canvas = $("#editErrandCropped")[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);
var image = canvas.toDataURL().replace(/^data:image\/[a-z]+;base64,/, "");
$('#editErrandCroppedPicture').val(image);
//$('#editErrandButtonUpload').show();
$('#editErrandCropped').hide();
$('#editErrandButtonCrop').hide();
};
img.src = $('#editErrandOriginal').attr("src");
});
});
function SetCoordinates(c) {
$('#editErrandCropX').val(c.x);
$('#editErrandCropY').val(c.y);
$('#editErrandCropW').val(c.w);
$('#editErrandCropH').val(c.h);
$('#editErrandButtonCrop').show();
};
</script>
So ultimately my question is: How can I update the picture if a user selects a new one (which works fine) AND make sure the previously uploaded picture is not overridden if a user does not select a new picture? Right now, all values would be updated except for the picture (unless a new picture is selected and cropped).
Now after adding a View Model, I get the following error:
The entity type EditErrandViewModel is not part of the model for the current context. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details:
System.InvalidOperationException: The entity type EditErrandViewModel is not part of the model for the current context.
Source Error:
Line 348: errand.Picture = imageBytes;
Line 349: }
Line 350: DB.Entry(errand).State = EntityState.Modified;
Line 351: DB.SaveChanges();
Line 352: var Success = new UserActivities