I'm working on part of my project which allows users to upload photos and add an entity to the database. This part of the schema is a one-to-many relationship where one user has many uploads. This was created using code first with the model shown below.
User Model:
public class UserModel
{
public int Id { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required]
public string DisplayName { get; set; }
public virtual ICollection<PetPhotoModel> Uploads
{ get; set; }
public virtual ICollection<RatingModel> Ratings { get; set; }
}
In Controler this method is called just after the user uploads a photo:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> UploadPhoto([Bind("Id,PetName,Title,Description,ImageFile")] PetPhotoModel petPhotoModel)
{
if (ModelState.IsValid)
{
//Save image to wwwroot/image
string wwwRootPath = _hostEnvironment.WebRootPath;
string fileName = Path.GetFileNameWithoutExtension(petPhotoModel.ImageFile.FileName);
string extension = Path.GetExtension(petPhotoModel.ImageFile.FileName);
petPhotoModel.ImageName = fileName = fileName + DateTime.Now.ToString("yymmssfff") + extension;
var folderPath = wwwRootPath + "\\UploadedPhotos\\";
CreateFolderIfNotExist(folderPath);
string path = Path.Combine(folderPath, fileName);
using (var fileStream = new FileStream(path, FileMode.Create))
{
await petPhotoModel.ImageFile.CopyToAsync(fileStream);
}
//GetLoggedInUser() gets the current user by id from the db context
var user = GetLoggedInUser();
user.Uploads.SetDefaultsAndAdd(petPhotoModel);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(petPhotoModel);
}
}
I have also written an generic extension method which instantiates a new List<T>
if the ICollection
property is null, converts the nulls in the object to something usable and adds it to the collection. In this case it would instantiate a List<PetPhotoModel>
to the UserModel
's Uploads
property and add the PetPhotoModel object passed in from the contoler. I have debugged through this method and appears to work correctly with the end result of the list containing the model with correct data.
Extension Method:
public static void SetDefaultsAndAdd<T>(this ICollection<T> collection, T model)
{
if (collection == null)
collection = new List<T>();
PropertyInfo[] properties = typeof(T).GetProperties();
foreach (var info in properties)
{
// if a string and null, set to String.Empty
if (info.PropertyType == typeof(string) &&
info.GetValue(model) == null)
{
info.SetValue(model, String.Empty);
}
if (info.PropertyType == typeof(double) &&
info.GetValue(model) == null)
{
info.SetValue(model, 0);
}
}
collection.Add(model);
}
}
GetLoggedInUser() in ControllerBase:
protected UserModel GetLoggedInUser()
{
var userId = HttpContext.Session.GetInt32("Id");
return _context.Users.FirstOrDefault(u => u.Id == userId);
}
This property is null when get despite data existing with the matching user Id
This property is still null when changed by the extension method