このクイックスタートでは、Microsoft.Data.SqlClient 7.1.1 を使用して ASP.NET Core のミニマル API を構築します。
まずは空のフォルダ、.NET SDK、そしてパソコンからアクセス可能なSQL ServerやAzure SQLデータベースから始めます。 最後に、メッセージをテーブルに追加し、IDで読み返すウェブAPIで締めくくります。
その過程で、アプリは次のことを行います:
- ASP.NET Core構成から接続文字列を読み込みます。 ローカル開発の場合、値はユーザーシークレットから得られるため、プロジェクトフォルダには含まれません。
- 依存性注入でデータ クラスを登録します。
- 各リクエストごとに接続を開いて破棄し、デフォルトの接続プールが物理接続を再利用できるようにします。
- リクエストの
CancellationTokenをすべてのデータベースコールに渡します。
このアプリは、Quickstart: Connect and query with Microsoft.Data.SqlClient と同じ dbo.SqlClientQuickstart テーブルを使用しています。 2つのクイックスタートのどちらを先にやってもいいですよ。
Prerequisites
- .NET 10 SDKまたはそれ以降のサポートされている .NET SDKです。 SDKはWindows、Linux、macOSで動作します。
- 接続できるデータベースです。 作成するには、コンソール クイックスタートの前提条件を確認してください。
-
curlまたは PowerShell を使用して API にリクエストを送信
現在のASP.NET Coreは、.NET Framework上ではなく、.NET上で動作しています。 .NETフレームワークのドライバーを使用するには、.NETフレームワークプロジェクトを参照してください。
データベースのアイデンティティは接続やテーブルの作成、挿入、選択の許可が必要です。
プロジェクトを作成する
空のフォルダー内で、以下のコマンドを実行してください:
dotnet new web --framework net10.0 --name SqlClientWebQuickstart
cd SqlClientWebQuickstart
dotnet add package Microsoft.Data.SqlClient --version 7.1.1
dotnet add package Microsoft.Data.SqlClient.Extensions.Azure --version 7.1.1
dotnet user-secrets init
dotnet user-secrets init プロジェクトファイルに UserSecretsId を追加します。 ASP.NET Coreは、アプリがDevelopment環境で実行されている場合にのみユーザー シークレットを読み込みます。これはdotnet runの既定です。
拡張パッケージはドライバーのMicrosoft Entra認証モードを提供します。 もしアプリがSQL認証のみを使用している場合は、 Microsoft.Data.SqlClient.Extensions.Azureを省略しても構いません。 両方のパッケージを使う場合は、それぞれのバージョンを同じにしてください。
接続の設定
接続文字列をユーザーシークレットにConnectionStrings:Quickstartとして保存してください。 ユーザーシークレットはプロジェクトフォルダではなくユーザープロファイルに保存されているため、ソース管理にはコミットされません。 パスワードや本番環境の接続文字列をappsettings.jsonに入れないでください。
これらの開始点から1つを選び、プレースホルダーを置き換えてください。
dotnet user-secrets setコマンドはPowerShellとBashでシングルクォートを使っています。 コマンドプロンプトでは、キーと値の一部としてシングルクォートを保存するため、代わりに二重引用符を使ったほうがいいです。
Azure SQL with Microsoft Entra ID
データベースにアクセスできるMicrosoft EntraのIDでサインインしてください。 ローカル開発の場合は、Azure CLIのような開発者ツールをご利用ください。
az login
その後、接続文字列を保存します。 Azure SQLデータベースから正確なサーバー名とデータベース名をコピーしてください。 同じ接続文字列は、コンソールのクイックスタートで説明されているSQLデータベースアイテムのサーバー名とデータベース名を使うと、Microsoft FabricのSQLデータベースでも動作します。
dotnet user-secrets set 'ConnectionStrings:Quickstart' 'Server=tcp:<server>,1433;Database=<database>;Authentication=Active Directory Default;Encrypt=Strict;Connect Timeout=30'
この接続文字列にはシークレットは含まれていません。
Active Directory Default はローカルで開発者のサインインを使用します。 Azure App ServiceやAzure Container Appsに展開する際、アプリのマネージド ID にデータベースへのアクセスを許可し、値をAuthentication=Active Directory Managed Identityに変更し、ホストの設定でConnectionStrings__Quickstartに設定します。 その他のオプションについては、Microsoft.Data.SqlClient での Microsoft Entra 認証を参照してください。
SQL認証を備えたローカルSQL Server
信頼された証明書がないローカル開発インスタンスの接続文字列を保存します。 PowerShellやBashがパスワード内の $ 文字を展開しないように、シングルクォートを使ってください。
dotnet user-secrets set 'ConnectionStrings:Quickstart' 'Server=tcp:<server>,1433;Database=<database>;User ID=<user-id>;Password=<password>;Encrypt=true;TrustServerCertificate=true;Connect Timeout=30'
Caution
TrustServerCertificate=true サーバー証明書の検証を省略します。 ローカル開発インスタンスでのみ使用してください。 共有または本番SQL Serverインスタンスの場合は、クライアントが信頼する証明書をインストールし、TrustServerCertificate=trueを削除してください。 詳細については、「 Microsoft.Data.SqlClient での暗号化と証明書の検証」を参照してください。
コードを追加する
Program.csの内容を次のコードに置き換えます。
using System.Data;
using Microsoft.Data.SqlClient;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<MessageStore>();
var app = builder.Build();
await app.Services.GetRequiredService<MessageStore>()
.EnsureTableAsync(app.Lifetime.ApplicationStopping);
app.MapPost("/messages", async (
NewMessage input, MessageStore store, CancellationToken cancellationToken) =>
{
if (string.IsNullOrWhiteSpace(input.Text) || input.Text.Length > 200)
{
return Results.BadRequest("Text must be 1 to 200 characters.");
}
Message message = await store.AddAsync(input.Text, cancellationToken);
return Results.Created($"/messages/{message.Id}", message);
});
app.MapGet("/messages/{id:int}", async (
int id, MessageStore store, CancellationToken cancellationToken) =>
await store.GetAsync(id, cancellationToken) is Message message
? Results.Ok(message)
: Results.NotFound());
app.Run();
record NewMessage(string Text);
record Message(int Id, string Text, DateTimeOffset CreatedAt);
sealed class MessageStore(IConfiguration configuration)
{
private readonly string _connectionString =
configuration.GetConnectionString("Quickstart")
?? throw new InvalidOperationException(
"Set the ConnectionStrings:Quickstart configuration value.");
public async Task EnsureTableAsync(CancellationToken cancellationToken)
{
const string sql = """
IF OBJECT_ID(N'dbo.SqlClientQuickstart', N'U') IS NULL
BEGIN
CREATE TABLE dbo.SqlClientQuickstart
(
Id int IDENTITY(1, 1) PRIMARY KEY,
Message nvarchar(200) NOT NULL,
CreatedAt datetimeoffset NOT NULL
CONSTRAINT DF_SqlClientQuickstart_CreatedAt
DEFAULT sysdatetimeoffset()
);
END;
""";
await using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync(cancellationToken);
await using var command =
new SqlCommand(sql, connection) { CommandTimeout = 30 };
await command.ExecuteNonQueryAsync(cancellationToken);
}
public async Task<Message> AddAsync(
string text, CancellationToken cancellationToken)
{
const string sql = """
INSERT INTO dbo.SqlClientQuickstart (Message)
OUTPUT INSERTED.Id, INSERTED.Message, INSERTED.CreatedAt
VALUES (@message);
""";
await using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync(cancellationToken);
await using var command =
new SqlCommand(sql, connection) { CommandTimeout = 30 };
command.Parameters.Add("@message", SqlDbType.NVarChar, 200).Value = text;
await using SqlDataReader reader =
await command.ExecuteReaderAsync(cancellationToken);
await reader.ReadAsync(cancellationToken);
return new Message(
reader.GetInt32(0), reader.GetString(1), reader.GetDateTimeOffset(2));
}
public async Task<Message?> GetAsync(
int id, CancellationToken cancellationToken)
{
const string sql = """
SELECT Id, Message, CreatedAt
FROM dbo.SqlClientQuickstart
WHERE Id = @id;
""";
await using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync(cancellationToken);
await using var command =
new SqlCommand(sql, connection) { CommandTimeout = 30 };
command.Parameters.Add("@id", SqlDbType.Int).Value = id;
await using SqlDataReader reader =
await command.ExecuteReaderAsync(cancellationToken);
return await reader.ReadAsync(cancellationToken)
? new Message(
reader.GetInt32(0), reader.GetString(1), reader.GetDateTimeOffset(2))
: null;
}
}
アプリを実行する
固定のポートでアプリを起動:
dotnet run --urls http://localhost:5000
起動時に、存在しなければアプリがテーブルを作成します。 アプリが準備完了すると、出力には以下の行が含まれます:
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
アプリがデータベースにアクセスできなければ、起動時に SqlExceptionを表示して停止します。 一般的な原因については「トラブルシューティング」を参照してください。
API を呼び出す
アプリはそのまま実行したままにして、2つ目のターミナルを開いてください。 POSTリクエスト付きのメッセージを追加し、それをGETリクエストでIDで読み返します。 テーブルにすでに行がある場合、例えばコンソールのクイックスタートから行がある場合は、GETリクエストの 1 を、POSTリクエストが返す id に置き換えてください。
PowerShell の場合:
Invoke-RestMethod -Method Post -Uri http://localhost:5000/messages -ContentType application/json -Body (@{ text = 'Hello from ASP.NET Core' } | ConvertTo-Json)
Invoke-RestMethod http://localhost:5000/messages/1
PowerShellは各JSON応答をテーブルとしてフォーマットします。 最初の行はPOSTリクエストへの 201 Created 応答で、2行目はGET応答です:
id text createdAt
-- ---- ---------
1 Hello from ASP.NET Core 2026-10-21T00:04:43.3588978+00:00
1 Hello from ASP.NET Core 2026-10-21T00:04:43.3588978+00:00
PowerShell 5.1 Windows、APIが返す文字列としてcreatedAtを表示します。 PowerShell 7はそれを 10/20/2026 7:04:43 PMなどのローカル時刻の日付に変換します。
Windows PowerShellでは、curl は Invoke-WebRequest の別名であり、Invoke-WebRequest は curl オプションを受け入れません。 PowerShellコマンドを使うか、コマンドプロンプトから curl.exe 実行してください。
コマンド プロンプトの場合:
curl -X POST http://localhost:5000/messages -H "Content-Type: application/json" -d "{\"text\":\"Hello from ASP.NET Core\"}"
curl http://localhost:5000/messages/1
コマンドプロンプトはシングルクォートを引用文字として扱わないため、JSONの本文はバックスラッシュでエスケープされたダブルクォートを使用します。 各コマンドはJSON応答を出力します:
{"id":1,"text":"Hello from ASP.NET Core","createdAt":"2026-10-21T00:05:15.4936763+00:00"}
{"id":1,"text":"Hello from ASP.NET Core","createdAt":"2026-10-21T00:05:15.4936763+00:00"}
Bash の場合:
curl -X POST http://localhost:5000/messages -H "Content-Type: application/json" -d '{"text":"Hello from ASP.NET Core"}'
curl http://localhost:5000/messages/1
{"id":1,"text":"Hello from ASP.NET Core","createdAt":"2026-10-20T20:44:17.8634925+00:00"}
{"id":1,"text":"Hello from ASP.NET Core","createdAt":"2026-10-20T20:44:17.8634925+00:00"}
IDやタイムスタンプは異なります。 もしコンソールのクイックスタートを先に実行すると、IDはそのクイックスタートの行から続きます。 存在しない ID を要求すると 404 Not Found が返されます。 空のメッセージの場合、400 Bad Request が返されます。
最初の端末でCtrl+Cを押してアプリを停止します。
コードのしくみ
- アプリは
MessageStoreをシングルトンとして登録します。 接続文字列だけを保持し、IConfigurationから一度読み取ります。 接続を維持できません。 - 各メソッドは
SqlConnectionを作成し、開いて1つのコマンドを実行し、await usingで破棄します。 Disposingは物理接続を接続プールに戻し、次のリクエストでその接続が再利用されます。 接続プーリングはデフォルトでオンになっているので、設定する必要はありません。 チューニング オプションについては、Microsoft.Data.SqlClient を使用した SQL Server 接続プーリングを参照してください。 - ASP.NET Core は
CancellationTokenパラメーターをリクエストにバインドします。 クライアントが切断されると、トークンによってオープン操作、コマンド、読み取りがキャンセルされます。 -
@messageと@idパラメータはカラム型とサイズに一致します。 APIは値をデータベースに送信する前に、メッセージの長さを検証します。 -
OUTPUT INSERTED.Id, INSERTED.Message, INSERTED.CreatedAt挿入された行(サーバー生成のIDとタイムスタンプを含む)を、2つ目のクエリなしで返します。 - 他の環境では、ASP.NET Core は、
ConnectionStrings:Quickstartなどの環境変数や、Azure Key Vault のような別の構成プロバイダーから同じConnectionStrings__Quickstartキーを読み取ります。
Troubleshoot
| エラーまたは症状 | 確認すべきこと | 詳細情報 |
|---|---|---|
Set the ConnectionStrings:Quickstart configuration value. |
アプリは接続文字列を見つけられませんでした。 プロジェクトフォルダで dotnet user-secrets list を実行し、アプリが Development 環境で動作しているか確認してください。 |
ASP.NET Core でのアプリシークレットの安全な開発用ストレージ |
System.ArgumentException: Cannot find an authentication provider for 'ActiveDirectoryDefault' スタートアップ時 |
接続文字列はActive Directory認証モードを使用していますが、プロジェクトではMicrosoft.Data.SqlClient.Extensions.Azureを参照していません。
Microsoft.Data.SqlClientと同じバージョンのパッケージを追加してください。 |
Microsoft Entra認証は7.0で拡張パッケージに移行 |
SqlException スタートアップ時 |
アプリは接続できなかったか、テーブルを作成できませんでした。 エラー番号は原因を示し、例えばログイン失敗の場合は18456です。 | コンソールクイックスタートでのトラブルシューティング |
415 Unsupported Media Type |
そのリクエストでは Content-Type: application/json が設定されていません。 |
最小限の API クイック リファレンス |
Cannot bind parameter 'Headers' |
Windows PowerShell で curl コマンドを実行しており、そこで curl が Invoke-WebRequest を実行します。
APIを呼び出すPowerShellコマンドを使ってください。 |
Invoke-RestMethod |
''' is an invalid start of a value |
コマンドプロンプトでBash curlコマンドを実行したため、単一引用符が本文の一部として送信されました。 API を呼び出すの「コマンド プロンプト」コマンドを使ってください。 | APIを呼び出す |
リソースをクリーンアップする
任意のクエリツールでテーブルを落とす:
DROP TABLE IF EXISTS dbo.SqlClientQuickstart;
保存されている接続文字列を削除してください。 プロジェクトフォルダから実行してください:
dotnet user-secrets clear
その後、プロジェクトフォルダを削除してください。 親フォルダーで、PowerShell から以下のコマンドを実行してください:
Remove-Item -Recurse -Force SqlClientWebQuickstart
Bash の場合:
rm -rf SqlClientWebQuickstart