[1/6] Become a Full Stack .NET Developer: Saving Data
Before implementing saving of data from our form, we need to limit access to the add a gig form to logged in users only. This was done simply by adding a Data Annotation [Authorize] to the Create() method found in the GigsController. So any non-logged in users are automatically redirected to the Login form when trying to add a gig.
Back in our Create.CSHTML file (from the previous module) we replaced the opening form element with @using (HTML.BeginForm("Create", "Gigs")) which is the MVC5 way of targeting forms to their respective Controllers.
Next we implemented the Create action in the GigsController and gave it a parameter named GigFormViewModel. Proceeding to decorate this method with [Authorize] (only authenticated users can call this action) and [HttpPost] (only HttpPost methods can call this action) Data Annotations.
This viewModel would then needed to be converted to our Gig Object and added to our context. To set the artist an Application Object from the database would need to be retrieved. We used a lambda expression to do this. The application object returned as an artist could then be associated with this particular gig.
The date of a gig was implemented by the user inputting a string into the form and parsing that out to a DateTime Object.
The Genre object was implemented similarly to the artist object, expect the Genre in the viewModel would be an integer (the value of the currently selected form object).
While doing all this, we were not concerned with validation (the user inputting incorrect data). That would be tackled in the next module.
Finally our Gig Object was added at the end to our _context, so it could be tracked by Entity Framework and save changes. At this point, Entity Framework will generate a SQL statement and execute it against our database.
As discussed in the initial planning phase of the app, when a user has entered details for a gig they should be returned automatically to the Home Page (in a future iteration this will eventually be replaced by going to a All Upcoming Gigs page instead). This was achieved by adding a RedirectToAction at the end of the code.
[Authorize] [HttpPost] public ActionResult Create (GigFormViewModel viewModel) { var artist = _context.Users.Single(u => u.Id == User.Identity.GetUSerId(); var genre = _context.Genres.Single(g => g.Id == viewModel.Genre); var gig = new Gig { Artist = artist, DateTime = DateTime.Parse(string.Format(" "), viewModel.Date, viewModel.Time)), Genre = genre, Venue = viewModel.Venue }; _context.Gigs.Add(gig); _context.SaveChanges(); return RedirectToAction("Index", "Home"); }
Upon testing out this code by trying to add a gig we were greeted by a Server Error. The cause of the exception was that Entity Framework could not execute the Lambda expression highlighted properly because it does not know what User and Identity are. This is purely C# code that does not have a direct analogy in SQL.
The solution to this error was to extract the Lambda expression for artist and store its value into a separate variable.
var artistId = User.Identity.GetUserId(); var artist = _context.Users.Single(u => u.Id == artistsId);
The final thing we considered in this module was applying the idea of separation of concerns to our code, namely in regards to how the DateTime object was being implemented. Up to now, we were making the Controller responsible for parsing the string value entered into a DateTime object. This should not be the responsibility of the Controller class (which should only co-ordinate for application logic without actually performing that logic itself).
We need to create a new property in the viewModel named DateTime and feed this into the Controller instead of what we currently have.
namespace GigHub.ViewModels { public class GigFormViewModel { public DateTime DateTime { get {return DateTime.PArse(string.Format(" "), Date, Time));} } } }
After doing this little bit of refactoring, we proceeding to commit our code to the repository which signified the end of this particular module.