こちらのイベントに参加させて頂きました。
fukuten.connpass.com
Visual Studio をはじめとした Microsoft の最新情報を届けてくれると同時に、ハンズオンまであるという濃いイベント。
ハンズオンにて紹介している資料では、Azure Cloud Shell を使用していますが、せっかくなので、Visual Studio 2019 でやってみました。
なお、ハンズオン資料は以下です。
Visual Studio 2019 Launch Event in Fukuoka
ASP.NET Core を使用して Web API を作成する - Learn | Microsoft Docs
1.新しいプロジェクトの作成
2.ASP.NET Core Webアプリケーション
3.プロジェクト名を入力
プロジェクト名は、チュートリアル同様「RetailApi」としました。
4.「API」を選択
5.実行
▶ボタンを押すと、Webサーバが起動します。
6.フォルダを追加
一旦、Webサーバを停止させます。
フォルダを追加します。RetailApiの階層にて右クリックし、フォルダを追加。
7.
以下の3つのフォルダを作成します。
8.ファイルを追加
ファイルを追加します。
追加する階層にて右クリックし、「新しい項目」を選択。
9.
コードファイルを選択し、作成。
10.
最終的にこんな感じになります。
追加・編集するコードは以下のようになります。
Controllers/ProductsController.cs
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RetailApi.Data;
using RetailApi.Models;
namespace RetailApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
private readonly ProductsContext _context;
public ProductsController(ProductsContext context)
{
_context = context;
}
[HttpGet]
public ActionResult<List<Product>> GetAll() =>
_context.Products.ToList();
[HttpGet("{id}")]
public async Task<ActionResult<Product>> GetById(long id)
{
var product = await _context.Products.FindAsync(id);
if (product == null)
{
return NotFound();
}
return product;
}
[HttpPost]
public async Task<ActionResult<Product>> Create(Product product)
{
_context.Products.Add(product);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
[HttpPut("{id}")]
public async Task<IActionResult> Update(long id, Product product)
{
if (id != product.Id)
{
return BadRequest();
}
_context.Entry(product).State = EntityState.Modified;
await _context.SaveChangesAsync();
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(long id)
{
var product = await _context.Products.FindAsync(id);
if (product == null)
{
return NotFound();
}
_context.Products.Remove(product);
await _context.SaveChangesAsync();
return NoContent();
}
}
}
Controllers/ValuesController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace RetailApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return "value";
}
[HttpPost]
public void Post([FromBody] string value)
{
}
[HttpPut("{id}")]
public void Put(int id, [FromBody] string value)
{
}
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
}
Data/ProductsContext.cs
using Microsoft.EntityFrameworkCore;
using RetailApi.Models;
namespace RetailApi.Data
{
public class ProductsContext : DbContext
{
public ProductsContext(DbContextOptions<ProductsContext> options)
: base(options)
{
}
public DbSet<Product> Products { get; set; }
}
}
Data/SeedData.cs
using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using RetailApi.Models;
namespace RetailApi.Data
{
public static class SeedData
{
public static void Initialize(IServiceProvider serviceProvider)
{
using (var context = new ProductsContext(serviceProvider
.GetRequiredService<DbContextOptions<ProductsContext>>()))
{
if (!context.Products.Any())
{
context.Products.AddRange(
new Product { Name = "Squeaky Bone", Price = 20.99m },
new Product { Name = "Knotted Rope", Price = 12.99m }
);
context.SaveChanges();
}
}
}
}
}
Models/Product.cs
using System.ComponentModel.DataAnnotations;
namespace RetailApi.Models
{
public class Product
{
public long Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
[Range(minimum: 0.01, maximum: (double)decimal.MaxValue)]
public decimal Price { get; set; }
}
}
Program.cs
using System;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using RetailApi.Data;
namespace RetailApi
{
public class Program
{
public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args).Build();
SeedDatabase(host);
host.Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
private static void SeedDatabase(IWebHost host)
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<ProductsContext>();
context.Database.EnsureCreated();
SeedData.Initialize(services);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "A database seeding error occurred.");
}
}
}
}
}
Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.EntityFrameworkCore;
using RetailApi.Data;
namespace RetailApi
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ProductsContext>(options =>
options.UseInMemoryDatabase("Products"));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
}
}
}
ソースの詳細については、公式サイトをご参照ください。
docs.microsoft.com