download source code here
Create project via Cli
-
Install .net core sdk, .net core runtime at https://www.microsoft.com/net/learn/get-started/windows or https://www.microsoft.com/net/download/windows
in Feb, 2018, .net core sdk is v2.1.4, .net core runtime is v 2.0.5
-
open console,
dotnet new --help
to check templates -
create webapi project,
dotnet new webapi -o myApi
-
run the app,
dotnet run
-
install entity framework core package.
dotnet add Microsoft.EntityFrameworkCore.SqlServer
other commands:
dotnet add package
: Adds a package reference to the project file, then runsdotnet restore
to install the package.dotnet remove
package: Removes a package reference from the project filedotnet restore
: Restores the dependencies and tools of a project.dotnet nuget locals
: Clears or lists local NuGet resources such as the http-request cache, the temporary cache, and the machine-wide global packages folder.
Create project via Visual Studio
we got
If this webapi project references other libaries, make sure to choose the compatible .net framework version
ctrl + f5 to run,
nuget > install Microsoft.EntityFrameworkCore.SqlServer package
Create a simple demo
-
add models
Models > TodoItem.cs:
namespace Models { public class TodoItem { public long Id { get; set; } public string Name { get; set; } public bool IsComplete { get; set; } } }
-
add data
Data > TodoContext.cs:
using Microsoft.EntityFrameworkCore; using Models; namespace TodoApi.Models { public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } } }
-
register db context in dependency injection container. Here we specify an in-memory database is injected into the service container.
update Startup.cs
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddDbContext<TodoContext>(opt => opt.UseInMemoryDatabase("TodoList")); services.AddMvc(); } ... }
-
Create a controller: TodoController.cs
using Microsoft.AspNetCore.Mvc; using Models; using Data; using System.Linq; namespace TodoApi.Controllers { [Route("api/[controller]")] public class TodoController : Controller { private readonly TodoContext _context; public TodoController(TodoContext context) { _context = context; if (_context.TodoItems.Count() == 0) { _context.TodoItems.Add(new TodoItem { Name = "Item1" }); _context.SaveChanges(); } } } }
-
Add get endpoints
[HttpGet] public IEnumerable<TodoItem> GetAll() { return _context.TodoItems.ToList(); } [HttpGet("{id}", Name = "GetTodo")] public IActionResult GetById(long id) { var item = _context.TodoItems.FirstOrDefault(t => t.Id == id); if (item == null) { return NotFound(); } return new ObjectResult(item); }
-
Add create endpoint
[HttpPost] public IActionResult Create([FromBody] TodoItem item) { if (item == null) { return BadRequest(); } _context.TodoItems.Add(item); _context.SaveChanges(); return CreatedAtRoute("GetTodo", new { id = item.Id }, item); }
-
Add update endpoint
[HttpPut("{id}")] public IActionResult Update(long id, [FromBody] TodoItem item) { if (item == null || item.Id != id) { return BadRequest(); } var todo = _context.TodoItems.FirstOrDefault(t => t.Id == id); if (todo == null) { return NotFound(); } todo.IsComplete = item.IsComplete; todo.Name = item.Name; _context.TodoItems.Update(todo); _context.SaveChanges(); return new NoContentResult(); }
-
add delete endpoint
[HttpDelete("{id}")] public IActionResult Delete(long id) { var todo = _context.TodoItems.FirstOrDefault(t => t.Id == id); if (todo == null) { return NotFound(); } _context.TodoItems.Remove(todo); _context.SaveChanges(); return new NoContentResult(); }
Enable cors
-
Install package
Microsoft.AspNetCore.Cors
either via nuget in visual studio or command line -
Enable cors
-
way1, enable in middleware. modify Startup.cs
public void ConfigureServices(IServiceCollection services) { services.AddCors(); }
-
way2, enable in controller
-
Add lazy loading
-
Install package
Microsoft.EntityFrameworkCore.Proxies
-
Suppose we have a database
EmployeeManagement
, we use database first to generate model classes:Scaffold-DbContext "Server=(local);Database=EmployeeManagement;Integrated Security=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Entities
A folder Entities will be created with entities and dbcontext in it
-
Open entity classes, manually set all navigation properties as virtual:
-
Enable lazy loading,
Startup.cs
``` ... public void ConfigureServices(IServiceCollection services) { // add db optoins var connection = @"Server=(local);Database=EmployeeManagement;Integrated Security=true;"; services.AddDbContext<EmployeeManagementContext>(opt => { opt.UseLazyLoadingProxies().UseSqlServer(connection); } ); //services.AddEntityFrameworkProxies(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); } ```
Test
-
run via
dotnet run
-
navigate to
http://localhost:5000/api/todo
-
post a json data
{ “id”: 2, “name”: “Item2”, “isComplete”: true }
Add database first entities
- Add nuget libraries:
Microsoft.EntityFrameworkCore.SqlServer EntityFrameworkCore.Tools EntityFrameworkCore.SqlServer.Design
-
nuget command console
Scaffold-DbContext "Server=(local)\SQLEXPRESS;Database=EFCoreDBFirstDemo;Integrated Security=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Entities
it will create a Entities folder with all models from database inside it.
Enable cors
-
Install
Microsoft.AspNetCore.Cors
package -
Add the CORS services
public void ConfigureServices(IServiceCollection services) { ... services.AddCors(); }
-
Enable cors with middleware. Note that the CORS middleware must precede any defined endpoints in your app that you want to support cross-origin requests (ex. before any call to UseMvc).
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } // Shows UseCors with CorsPolicyBuilder. app.UseCors(builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()); ... }
Model validation
Attribute validation
-
modify properties of model
-
We can define our own validation attribute
public class TorontoPhoneAttribute : System.ComponentModel.DataAnnotations.ValidationAttribute { protected override ValidationResult IsValid(object value, ValidationContext validationContext) { if(!value.ToString().StartsWith("647")) { return new ValidationResult("this is not 647-xxx-xxxx"); } return null; } }
-
In controller, verify
ModelStatus.IsValid
and return badrequest accordingly[HttpPost("")] public IActionResult AddCompany([FromBody] TblCompany company) { if (ModelState.IsValid) { this.employeeManagementV2Context.TblCompany.Add(company); this.employeeManagementV2Context.SaveChanges(); return Ok(); } return BadRequest(ModelState); }
-
POST a request, we will get errors as below
Fluent validation
- Install 3rd package
- asp.net core
FluentValidation.AspNetCore
- asp.net mvc
FluentValidation.Mvc5
- asp.net webapi v2
FluentValidation.WebApi
- asp.net core
References
https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api
https://blogs.msdn.microsoft.com/webdev/2017/04/06/jwt-validation-and-authorization-in-asp-net-core/
https://docs.microsoft.com/en-us/aspnet/core/security/cors
https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.1
https://www.c-sharpcorner.com/article/learn-about-web-api-validation/
https://www.jerriepelser.com/blog/validation-response-aspnet-core-webapi/