目次
サーバサイドをasp.net C#を使ってJavaScriptによる非同期通信の実装方法について説明します。
概要
サンプルコードの前にまずは非同期通信についての技術的な説明から
非同期通信はJavaScriptのFetch Apiを使う
まずは同期通信と非同期通信の違いを簡潔に説明すると
同期通信でサーバにアクセスすると必ずWebページ再表示が発生して見栄えが悪くなります。
非同期通信でサーバにアクセスすると部分的にWebページを更新でき見栄えを改善できます。
非同期通信はJavaScriptのFetch Apiで実装できます。また、歴史的にXMLHttpRequest → Ajax → fetch Api と移り変わっているので、特に理由がなければ古い方法は採用しないようにしましょう。
非同期通信のアクセス先はUrlかアクションコントローラー
通信先の指定は2通りの方法があり、
ルーティングによって生成されたUrlを記入するか、クラス名(ファイル名)とメソッド名を指定するアクションコントローラーの記入があります。
アクションコントローラーの記入はサーバサイドの言語やフレームワークによって記述が異なるようで、asp.netではMVCとRazor Pageで記述が異なります。
そのため、JavaScriptの再利用性を考慮すればWebApiのUrlを指定する方法が推奨方法で、一応コントローラーアクションで通信できる環境は用意しておくのが無難だと思います。
非同期通信はセキュリティ対策で拒否される
非同期通信はサーバ側でデフォルトで搭載されているセキュリティ対策で拒否されます。
2つのセキュリティ対策が必要で、
接続先がUrlで且つフロントとバックエンドのドメインが違う場合はクロスオリジン対策
接続先がアクションコントローラーで且つGet以外の通信ではXSRF対策
がそれぞれ必要です。
サンプルコード
ルーティングのUrlを指定する方法とRazor Pageによるコントローラーアクションを指定する方法のサンプルコードを記載します。
ルーティングのUrlを指定する方法
WebApiのUrlを指定する非同期通信のサンプルコード
C#
Controllersフォルダにあるクラスに[Route]属性を付与しメソッドに[HttpGet]属性を付与します。これでhttp://(ドメイン)/task/{id}というUrlにアクセスすればsampleというレスポンスを受け取れるGetメソッドの準備ができました。
[Route("task")]
public class TaskController : Controller
{
[HttpGet("{id}")]
public string GetById(int id)
{
return "sample";
}
}
javascript
こちらはそのGetメソッドからデータを受け取るスクリプトです。
fetch('/task/1', {
method: 'GET',
})
.then(data => {
console.debug(data);
});
クロスオリジン対策のサンプル
サーバとフロントを別のプロジェクトで開発しているとドメインが違うためクロスオリジン要求 (CORS) を有効にする必要があります。
サーバーサイドのStartupクラスを下記のように修正するとすべてのクロスオリジン要求を受け入れる設定になり、エラーは解消されますが、すべての通信が許容されてしまうのは問題なので、公式サイトの説明を参考に各自でしっかり許容範囲を調整してください。
public class Startup
{
private readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public void ConfigureServices(IServiceCollection services)
{
:
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins();
builder.AllowAnyMethod();
builder.AllowAnyHeader();
});
});
:
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
:
app.UseCors(MyAllowSpecificOrigins);
:
}
}
アクションコントローラーを指定する方法
asp.net Razor Pagesによる非同期通信のサンプルコードです。
C#
下記はリクエストパラメータでデータを送信して受信するするサンプルコードです。
public async Task<IActionResult> OnGetMethod(int id)
{
var output = async _customerSession.GetById(id)
return JsonReult(output);
}
JavaScript
fetch('?handler=Method&id=1', {
method: 'GET',
})
.then(data => {
console.debug(data.id);
});
ちなみにhandler自体がリクエストパラメータの1つなのでURLは
「?handler=Method?id=1」ではなく「?handler=Method&id=1」という記述になります。
クロスサイトリクエストフォージェリの防止
GET以外はクロスサイト リクエスト フォージェリ (XSRF/CSRF) 攻撃を防止するRequestVerficationTokenをヘッダーに記述しないと400エラーが返ってきます。
下記はJsonBodyでデータを送信でXSRF対策をしたPOSTのサンプルコードです。
Html
.cshtmlに<form method=”post”>と記述していると出力時にこのヘッダーが追加されます。
<form method="post">
:
</form>
下記は出力時に生成されるヘッダー
<input name="__RequestVerificationToken" type="hidden" value="ABCDEFG...(乱数)" />
C#
引数に[FromBody]属性を付与するのを忘れずに
public async Task<IActionResult> OnPostMethod([FromBody] Item item)
{
var output = async _customerSession.Post(item)
return new OkReuslt();
}
public class Item
{
public int input {get; set;}
}
JavaScript
JSONであることを示す’Content-Type’:’application/json’をヘッダーに追加します。
var item = {
"input":1
}
fetch('?handler=Method', {
method: 'POST',
headers: {
'Content-Type':'application/json',
'RequestVerificationToken' : $('input:hidden[name="__RequestVerificationToken"').val(),
},
body: JSON.stringify(item)
})
.then(data => {
});
補足
上記はRazorPagesでの実装方法でasp.net MVCではアクションコントローラーの記述が異なり、調べてる感じでは下記の2通りの記述方法があります。
- @Url.Action(“ActionName”, “ControllerName “, new { id = Id })
- /ActionName/ActionName?id=Id
アクションコントローラーの記述は言語やフレームワークによって異なりphpだとsample.php、rubyだと:sampleのような指定になります。依存性を考えれば非同期通信のアクセス先はOpenApiでルーティングしたUrlを指定しましょう。