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