Here are my notes for my future reference from Jonas Fagerberg's excellent Udemy Course. I would highly recommend you go buy the course: "ASP.NET Core 2.0"
Chapter 3 - MVC
Startup.cs - Let's get wired up!
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using AspNetCoreVideoCourse.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace AspNetCoreVideoCourse { public class Startup { public IConfiguration Configuration { get; set; } public Startup() { Configuration = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .Build(); } public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddSingleton(provider => Configuration); services.AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, IMessageService messageService) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); app.Run(async (context) => { await context.Response.WriteAsync(messageService.GetMessage()); }); } } }
Explicit Attribute Routing
namespace AspNetCoreVideoCourse.Controllers { [Route("[controller]")] public class EmployeeController { [Route("[action]")] public string Name() { return "Jonas"; } [Route("[action]")] public string Country() { return "Sweden"; } [Route("")] [Route("[action]")] public string Index() { return "Hello from Employee"; } } }
Generalized Attribute Routing:
namespace AspNetCoreVideoCourse.Controllers { [Route("company/[controller]/[action]")] public class EmployeeController { public string Name() { return "Jonas"; } public string Country() { return "Sweden"; } [Route("")] public string Index() { return "Hello from Employee"; } } }
To return json data directly to the browser:
public class HomeController : Controller { public ObjectResult Index() { var model = new Video {Id = 1, Title = "Shreck"}; return new ObjectResult(model); } }
To display an IEnumerable in Razor
@model IEnumerable<AspNetCoreVideoCourse.Models.Video> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Video</title> </head> <body> <table> @foreach (var video in Model) { <tr> <td>@video.Id</td> <td>@video.Title</td> </tr> } </table> </body> </html>
Chapter 5: Models
Creating an object through POST Example
Data annotations are found in System.ComponentModel.DataAnnotations.
The most common are:MinLength,MaxLength,Range, RegularExpression, Display, DataType, Required, Compare
Example
in Video.cs public class Video { public int Id { get; set; } [Required, MinLength(3)] [DataType(DataType.Password)] public string Title { get; set; } [Display(Name = "Film Genre")] public Genres Genre { get; set; } } in ViewModels/ViedoEditViewModel.cs: namespace AspNetCoreVideoCourse.ViewModels { public class VideoEditViewModel { public int Id { get; set; } [Required, MinLength(3), MaxLength(80)] public string Title { get; set; } public Genres Genre { get; set; } } } in HomeController.cs: HttpGet] public IActionResult Create() { return View(); } [HttpPost] public IActionResult Create(VideoEditViewModel model) { if (ModelState.IsValid) { var video = new Video { Title = model.Title, Genre = model.Genre }; _videoData.Add(video); return RedirectToAction("Details", new {id = video.Id}); } return View(); } in Views/Home/Create.cshtml: @using AspNetCoreVideoCourse.Models @model AspNetCoreVideoCourse.Entities.Video @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers <h2>Create Video</h2> <form asp-action="Create" method="post"> <div asp-validation-summary="All"></div> <table> <tr> <td><label asp-for="Title"></label></td> <td><input asp-for="Title"/></td> <td><span asp-validation-for="Title"></span></td> </tr> <tr> <td><label asp-for="Genre"></label></td> <td><select asp-for="Genre" asp-items="Html.GetEnumSelectList<Genres>()"></select></td> <td><span asp-validation-for="Genre"></span></td> </tr> </table> <input type="submit" value="Create"/> </form> <div><a asp-action="Index">Back to List</a></div>
Entity Framework
in package manager:
PM> add-Migration cmdlet Add-Migration at command pipeline position 1 Supply values for the following parameters: Name: Initial PM> update-database
Additional Files:
In Startup.cs: public class Startup public IConfiguration Configuration { get; set; } public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: true); if (env.IsDevelopment()) { builder.AddUserSecrets<Startup>(); } Configuration = builder.Build(); } public void ConfigureServices(IServiceCollection services) { var conn = Configuration.GetConnectionString("DefaultConnection"); services.AddDbContext<VideoDbContext>(options => options.UseSqlServer(conn)); services.AddMvc(); services.AddSingleton(provider => Configuration); services.AddSingleton<IMessageService, ConfigurationMessageService>(); services.AddScoped<IVideoData, SqlVideoData>(); } In SqlVideoData.cs: : using System.Collections.Generic; using AspNetCoreVideoCourse.Data; using AspNetCoreVideoCourse.Entities; namespace AspNetCoreVideoCourse.Services { public class SqlVideoData : IVideoData { private VideoDbContext _db; public SqlVideoData(VideoDbContext db) { _db = db; } public IEnumerable<Video> GetAll() { return _db.Videos; } public Video Get(int id) { return _db.Find<Video>(id); } public void Add(Video newVideo) { _db.Add(newVideo); _db.SaveChanges(); } } } in VideoDbContext.cs: using AspNetCoreVideoCourse.Entities; using Microsoft.EntityFrameworkCore; namespace AspNetCoreVideoCourse.Data { public class VideoDbContext : DbContext { public DbSet<Video> Videos { get; set; } public VideoDbContext(DbContextOptions<VideoDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); } } }
To Add an "Edit" View
in Edit.cshtml: <form asp-action="Edit" method="post"> <div asp-validation-summary="All"></div> <table> <tr> <td><label asp-for="Title"></label></td> <td><input asp-for="Title" /></td> <td><span asp-validation-for="Title"></span></td> </tr> <tr> <td><label asp-for="Genre"></label></td> <td><select asp-for="Genre" asp-items="Html.GetEnumSelectList<Genres>()"></select></td> <td><span asp-validation-for="Genre"></span></td> </tr> </table> <input type="submit" value="Edit" /> </form> in HomeController.cs: [HttpGet] public IActionResult Edit(int id) { var video = _videoData.Get(id); if (video == null) { return RedirectToAction("Index"); } return View(video); } [HttpPost] public IActionResult Edit(int id, VideoEditViewModel model) { var video = _videoData.Get(id); if (video == null || !ModelState.IsValid) return View(model); video.Title = model.Title; video.Genre = model.Genre; _videoData.Commit(); return RedirectToAction("Details", new {id = video.Id}); } in SqlVideoData.cs: using System.Collections.Generic; using AspNetCoreVideoCourse.Data; using AspNetCoreVideoCourse.Entities; namespace AspNetCoreVideoCourse.Services { public class SqlVideoData : IVideoData { private VideoDbContext _db; public SqlVideoData(VideoDbContext db) { _db = db; } public IEnumerable<Video> GetAll() { return _db.Videos; } public Video Get(int id) { return _db.Find<Video>(id); } public void Add(Video newVideo) { _db.Add(newVideo); _db.SaveChanges(); } public int Commit() { return _db.SaveChanges(); } } }
Section 7 Razor Views
_ViewStart.cshtml will define variables for all pages in lower directories _ViewImports.cshtml will define import statements for all lower pages
Partial Views
@Html.Partial("_Video", video); @await Html.PartialAsync("_Video", video);
Components
Components allow you to inject html from code.
in Views/Shared/Components/Message/Default.cshtml: using AspNetCoreVideoCourse.Services; using Microsoft.AspNetCore.Mvc; namespace AspNetCoreVideoCourse.ViewComponents { public class Message : ViewComponent { private readonly IMessageService _message; public Message(IMessageService message) { _message = message; } public IViewComponentResult Invoke() { var model = _message.GetMessage(); return View("Default", model); } } } in Views/Shared/_Layout.cs: <footer> @RenderSection("footer",false) @await Component.InvokeAsync("Message") </footer>
Section 8: Forms Authentication / Identity Management
in AccountController: using System.Threading.Tasks; using AspNetCoreVideoCourse.Entities; using AspNetCoreVideoCourse.ViewModels; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; namespace AspNetCoreVideoCourse.Controllers { public class AccountController : Controller { private readonly UserManager<User> _userManager; private readonly SignInManager<User> _signInManager; public AccountController(UserManager<User> userManager, SignInManager<User> signInManager) { _userManager = userManager; _signInManager = signInManager; } [HttpGet] public IActionResult Register() { return View(); } [HttpPost] public async Task<IActionResult> Register(RegisterViewModel model) { if (!ModelState.IsValid) return View(); var user = new User {UserName = model.Username}; var result = await _userManager.CreateAsync(user, model.Password); if (result.Succeeded) { await _signInManager.SignInAsync(user, false); return RedirectToAction("Index", "Home"); } else { foreach (var error in result.Errors) { ModelState.AddModelError("",error.Description); } } return View(); } [HttpPost] public async Task<IActionResult> Logout() { await _signInManager.SignOutAsync(); return RedirectToAction("Index", "Home"); } [HttpGet] public IActionResult Login(string returnUrl = "") { var model = new LoginViewModel {ReturnUrl = returnUrl}; return View(model); } [HttpPost] public async Task<IActionResult> Login(LoginViewModel model) { if (!ModelState.IsValid) return View(model); var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberMe, false); if (result.Succeeded) { if (!string.IsNullOrEmpty(model.ReturnUrl) && Url.IsLocalUrl(model.ReturnUrl)) { return Redirect(model.ReturnUrl); } else { return RedirectToAction("Index", "Home"); } } ModelState.AddModelError("","Login failed"); return View(model); } } } in Views/Account/Login: @model LoginViewModel @{ ViewBag.Title = "Login";} <h2>Login</h2> <form method="post" asp-controller="Account" asp-action="Login" asp-route-returnurl="@Model.ReturnUrl"> <div asp-validation-summary="ModelOnly"></div> <div> <label asp-for="Username"></label> <input asp-for="Username"/> <span asp-validation-for="Username"></span> </div> <div> <label asp-for="Password"></label> <input asp-for="Password"/> <span asp-validation-for="Password"></span> </div> <div> <label asp-for="RememberMe"></label> <input asp-for="RememberMe"/> <span asp-validation-for="RememberMe"></span> </div> <div> <input type="submit" value="Register"/> </div> </form> in Views/Account/Register: @model RegisterViewModel @{ ViewBag.Title = "Register";} <h1>Register</h1> <form method="post" asp-controller="Account" asp-action="Register"> <div asp-validation-summary="ModelOnly"></div> <div> <label asp-for="Username"></label> <input asp-for="Username"/> <span asp-validation-for="Username"></span> </div> <div> <label asp-for="Password"></label> <input asp-for="Password"/> <span asp-validation-for="Password"></span> </div> <div> <label asp-for="ConfirmPassword"></label> <input asp-for="ConfirmPassword"/> <span asp-validation-for="ConfirmPassword"></span> </div> <div> <input type="submit" value="Register"/> </div> </form> in ViewModels/LoginViewModel.cs: using System.ComponentModel.DataAnnotations; namespace AspNetCoreVideoCourse.ViewModels { public class LoginViewModel { [Required] public string Username { get; set; } [Required, DataType(DataType.Password)] public string Password { get; set; } public string ReturnUrl { get; set; } [Display(Name = "Remember Me")] public bool RememberMe { get; set; } } } in ViewModels/RegisterViewModel.cs: using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; namespace AspNetCoreVideoCourse.ViewModels { public class RegisterViewModel { [Required, MaxLength(255)] public string Username { get; set; } [Required, DataType(DataType.Password)] public string Password { get; set; } [Required, DataType(DataType.Password), Compare(nameof(Password))] public string ConfirmPassword { get; set; } } } in Views/Shared/_LoginLinks.cshtml: @using Microsoft.AspNetCore.Identity @inject SignInManager<User> SignInManager @inject UserManager<User> UserManger @if (SignInManager.IsSignedIn(User)) { <div>@User.Identity.Name</div> <form method="post" asp-controller="Account" asp-action="Logout"> <input type="submit" value="Logout"/> </form> } else { <a asp-controller="Account" asp-action="Login">Login</a> <a asp-controller="Account" asp-action="Register">Register</a> }
No comments:
Post a Comment