A skeleton webapi that loads data from a sqlite database.
Webapi setup
Create a new api project
cd ~/dev/DatingApp
dotnet new webapi -o DatingApp.API
cd DatingApp.API
Start the application
dotnet run
Check with the browser that the api is running at https://localhost:5001/api/values.
Add a .gitignore
file
*.swp
*.*~
project.lock.json
.DS_Store
*.pyc
# Visual Studio Code
.vscode
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
msbuild.log
msbuild.err
msbuild.wrn
# Visual Studio 2015
.vs/
Visual Studio Code and dotnet watch
The course suggest to add dotnet watch to the project dependencies. This step is not needed, with the new release of netcore it is always available.
Start Visual Studio Code
code .
From the terminal pane of vsc run dotnet watch and test a small change on the value controller to see that everything is working
dotnet watch run
Database configuration and initalization
Create a Models folder.
Right click on the folder select New C# class and name it Value.
namespace DatingApp.API.Models
{
public class Value
{
public int Id { get; set; }
public string Name { get; set; }
}
}
Create a Data folder.
Right click on the folder select New C# class and name it DatingContext.
using Microsoft.EntityFrameworkCore;
using DatingApp.API.Models;
namespace DatingApp.API.Data
{
public class DatingContext : DbContext
{
public DatingContext(DbContextOptions<DatingContext> options)
: base(options)
{ }
public DbSet<Value> Values { get; set; }
}
}
In the terminal stop dotnet watch (CTRL+c)
dotnet add package Microsoft.EntityFrameworkCore.Sqlite -v 2.1.0-rc1-final
Open appsettings.json and add a new section
"ConnectionStrings": {
"DatingDbConnection": "Data Source=DatingApp.db"
},
Register the dbcontext in Startup.cs ConfigureServices method.
...
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddDbContext<DatingContext>(options => options.UseSqlite(Configuration.GetConnectionString("DatingDbConnection")));
}
...
Create an initial migration with EF
dotnet ef migrations add InitialMigration
dotnet ef database update
The first command created a Migrations folder with 3 files. The update command applies the migration creating a new database.
Database usage
Add a context to a new constructor in ValuesController.cs
...
private readonly DatingContext _context;
public ValuesController(DatingContext context)
{
this._context = context;
}
...
Change the return type for the two get methods and add asynchronous data loading from the db.
[HttpGet]
public async Task<ActionResult<IEnumerable<Value>>> Get()
{
var values = await _context.Values.ToListAsync();
return Ok(values);
}
[HttpGet("{id}")]
public async Task<ActionResult<Value>> Get(int id)
{
var value = await _context.Values.FirstOrDefaultAsync(x => x.Id == id);
return Ok(value);
}
Some test data
Using Db Browser for Sqlite open the database DatingApp.db and add few rows to the Values table. Remember to Write Changes to the db.
Test the API with Postman
Start Postman, login, the. create a new collection named DatingApp.
Inside the DatingApp collection create a folder Skeleton.
Add a new GET request, name it GetValues and use the following url https://localhost:5001/api/values then click save.
Send the request and check that the body of the response contains the test records previously saved into the database.
[
{
"id": 1,
"name": "value db1"
},
{
"id": 2,
"name": "value db2"
},
{
"id": 3,
"name": "Value db3"
}
]
Add a new GET request, name it GetValue and use the following url https://localhost:5001/api/values/1 then click save.
Send the request and check that the body of the response contains the test records previously saved into the database.
{
"id": 1,
"name": "value db1"
}
Change the url to other ids to check that all the values are correctly loaded. Change the url to a not existing id and check that a 204 is returned.
CORS
Register the cors service in Startup.cs ConfigureServices method.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddDbContext<DatingContext>(options => options.UseSqlite(Configuration.GetConnectionString("DatingDbConnection")));
services.AddCors();
}
And configure CORS before MVC.
Note that this example configuration is very relaxed and unconstrained, not suitable for production.
...
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
// CORS must be configured before mvc
app.UseCors(policy => policy
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials());
app.UseMvc();
}