Web API の JSON 形式に関しては、
Building Your First Web API with ASP.NET Core MVC and Visual Studio ? ASP.NET documentation
https://docs.asp.net/en/latest/tutorials/first-web-api.html
に詳しい解説があります。
が、クライアント側が書いていないので、先の XML 形式と同じように WFP アプリでクライアントを書いていきます。
送受信の形式
- WPF アプリで JSON 形式で送信
- ASP.NET Core Web API で JSON 形式で返信
することを考える。データはいちいち JSON 形式に直すのは面倒なので、C# のクラスから Newtonsoft.Json.JsonSerializer を使ってシリアライズ/デシリアライズをする。
Web API 側の設定
XML 形式の場合は Formatters を追加したが、JSON の場合はもともとロードされているので不要。
JsonOutputFormatter と JsonInputFormatter が初期値で使われている。
Web API の PeopleController クラスを作る
Modelクラスである Person クラスを作っておく。
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
JsonSerializer は、IEnumerable<Person> もでシリアライズしてくれるので、XML 形式のような People クラスは不要で、そのまま使える。
コントローラーを作るときに「Entitiy Frameworkを使用したアクションがあるAPIコントローラー」を選べば、CURD機能のAPIが、ずらっと出力される。
このまま動くので改変しなくてよい。
[Produces("application/json")]
[Route("api/People")]
public class PeopleController : Controller
{
private readonly ApplicationDbContext _context;
public PeopleController(ApplicationDbContext context)
{
_context = context;
}
// GET: api/People
[HttpGet]
public IEnumerable<Person> GetPerson()
{
return _context.Person;
}
// GET: api/People/5
[HttpGet("{id}")]
public async Task<IActionResult> GetPerson([FromRoute] int id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Person person = await _context.Person.SingleOrDefaultAsync(m => m.Id == id);
if (person == null)
{
return NotFound();
}
return Ok(person);
}
// PUT: api/People/5
[HttpPut("{id}")]
public async Task<IActionResult> PutPerson([FromRoute] int id, [FromBody] Person person)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != person.Id)
{
return BadRequest();
}
_context.Entry(person).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!PersonExists(id))
{
return NotFound();
}
else
{
throw;
}
}
// return NoContent();
return await GetPerson(person.Id);
}
// POST: api/People
[HttpPost]
public async Task<IActionResult> PostPerson([FromBody] Person person)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_context.Person.Add(person);
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException)
{
if (PersonExists(person.Id))
{
return new StatusCodeResult(StatusCodes.Status409Conflict);
}
else
{
throw;
}
}
return CreatedAtAction("GetPerson", new { id = person.Id }, person);
}
// DELETE: api/People/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeletePerson([FromRoute] int id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Person person = await _context.Person.SingleOrDefaultAsync(m => m.Id == id);
if (person == null)
{
return NotFound();
}
_context.Person.Remove(person);
await _context.SaveChangesAsync();
return Ok(person);
}
private bool PersonExists(int id)
{
return _context.Person.Any(e => e.Id == id);
}
/// <summary>
/// 受け口を POST に変換する
/// </summary>
[HttpPost("{id}")]
[Route("Edit/{id}")]
public async Task<IActionResult> Edit([FromRoute] int id, [FromBody] Person person)
{
return await PutPerson(id, person);
}
[HttpPost]
[Route("Create")]
public async Task<IActionResult> Create([FromBody] Person person)
{
return await PostPerson(person);
}
}
クライアントからの表示の都合上 PutPerson の戻り値を変えている。
あと、POST 形式だけで通るように、Edit と Create を追加している。
WPF クライアントを作る
XML 形式のときと同じように、Person クラスだけを作る。
JsonSerializer が使えるように、Newtonsoft.Json を NuGet で参照設定させておく。
namespace ClientJson
{
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private async void clickGet(object sender, RoutedEventArgs e)
{
var hc = new HttpClient();
// hc.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var res = await hc.GetAsync("http://localhost:5000/api/people");
var str = await res.Content.ReadAsStringAsync();
textXml.Text = str;
var js = new Newtonsoft.Json.JsonSerializer();
var jr = new Newtonsoft.Json.JsonTextReader( new System.IO.StringReader(str));
var items = js.Deserialize<IEnumerable<Person>>(jr);
textPerson.Text = "";
foreach (var item in items)
{
textPerson.Text += $"{item.Id} {item.Name} {item.Age} n";
}
}
private async void clickGetById(object sender, RoutedEventArgs e)
{
int id = 2;
var hc = new HttpClient();
// hc.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var res = await hc.GetAsync($"http://localhost:5000/api/people/{id}");
var str = await res.Content.ReadAsStringAsync();
textXml.Text = str;
var js = new Newtonsoft.Json.JsonSerializer();
var jr = new Newtonsoft.Json.JsonTextReader(new System.IO.StringReader(str));
var item = js.Deserialize<Person>(jr);
textPerson.Text = $"{item.Id} {item.Name} {item.Age}";
}
private async void clickPutById(object sender, RoutedEventArgs e)
{
var person = new Person() { Id = 2, Name = "update person", Age = 99 };
var js = new Newtonsoft.Json.JsonSerializer();
var sw = new System.IO.StringWriter();
js.Serialize(sw, person);
var hc = new HttpClient();
// hc.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var json = sw.ToString();
var cont = new StringContent(json, Encoding.UTF8, "application/json");
var res = await hc.PutAsync($"http://localhost:5000/api/people/{person.Id}", cont);
var str = await res.Content.ReadAsStringAsync();
textXml.Text = str;
var jr = new Newtonsoft.Json.JsonTextReader(new System.IO.StringReader(str));
var item = js.Deserialize<Person>(jr);
textPerson.Text = $"{item.Id} {item.Name} {item.Age}";
}
private async void clickPost(object sender, RoutedEventArgs e)
{
var person = new Person() { Id = 0, Name = "new person", Age = 88 };
var js = new Newtonsoft.Json.JsonSerializer();
var sw = new System.IO.StringWriter();
js.Serialize(sw, person);
var hc = new HttpClient();
// hc.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var json = sw.ToString();
var cont = new StringContent(json, Encoding.UTF8, "application/json");
var res = await hc.PostAsync($"http://localhost:5000/api/people", cont);
var str = await res.Content.ReadAsStringAsync();
textXml.Text = str;
var jr = new Newtonsoft.Json.JsonTextReader(new System.IO.StringReader(str));
var item = js.Deserialize<Person>(jr);
textPerson.Text = $"{item.Id} {item.Name} {item.Age}";
}
private void clickDeleteById(object sender, RoutedEventArgs e)
{
}
private async void clickCreate(object sender, RoutedEventArgs e)
{
var person = new Person() { Id = 0, Name = "new person", Age = 88 };
var js = new Newtonsoft.Json.JsonSerializer();
var sw = new System.IO.StringWriter();
js.Serialize(sw, person);
var hc = new HttpClient();
// hc.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var json = sw.ToString();
var cont = new StringContent(json, Encoding.UTF8, "application/json");
var res = await hc.PostAsync($"http://localhost:5000/api/people/Create", cont);
var str = await res.Content.ReadAsStringAsync();
textXml.Text = str;
var jr = new Newtonsoft.Json.JsonTextReader(new System.IO.StringReader(str));
var item = js.Deserialize<Person>(jr);
textPerson.Text = $"{item.Id} {item.Name} {item.Age}";
}
private async void clickEdit(object sender, RoutedEventArgs e)
{
var person = new Person() { Id = 2, Name = "edit person", Age = 99 };
var js = new Newtonsoft.Json.JsonSerializer();
var sw = new System.IO.StringWriter();
js.Serialize(sw, person);
var hc = new HttpClient();
// hc.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var json = sw.ToString();
var cont = new StringContent(json, Encoding.UTF8, "application/json");
var res = await hc.PostAsync($"http://localhost:5000/api/people/Edit/{person.Id}", cont);
var str = await res.Content.ReadAsStringAsync();
textXml.Text = str;
var jr = new Newtonsoft.Json.JsonTextReader(new System.IO.StringReader(str));
var item = js.Deserialize<Person>(jr);
textPerson.Text = $"{item.Id} {item.Name} {item.Age}";
}
}
}
namespace SampleWebApiXml.Models
{
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
}
- Web APIの戻り値形式が、デフォルトでJSONなので、 hc.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(“application/json”)); は、設定しなくてもよい。
- Person クラスと JSON 形式は、JsonSerializer.Serialize と Deserializeを使えばよい。
- これも、日本語を通すためにはきちんと UTF8 エンコードが必要かも。
でもって、うまく動くと dotnet run でサーバーを起動、WPF クライアントから JSON 形式で送受信ができるようになる。ここまで、できるようになれば、クライアントを Javascript や Ruby に切り替えたり、サーバー側を CakePHP で切り替えて相互に動かせるようになる。
サンプルコード
動作できるサンプルコードはこちら
https://1drv.ms/u/s!AmXmBbuizQkXgfsRYiYpmZzonGIBZw


