はじめに
2016年に.NET Coreが誕生し、Windowsのプラットフォーム依存がなくなりました。以前書いた記事に対するコメントで「C#?Visual Studio要るんでしょ?」、「開発を支えるツールがあるの?」など、C#がWindows以外で動くことは知っているけど、実用に耐えるのか?を疑問に思っている人が多いと感じました。私が個人サービスを開発して得た経験や知見を通じてVisualStudioがなくても充分に開発出来るということを知ってもらえたら嬉しいです。ハンズオン形式でご紹介しますので、よろしければ作成したリポジトリをご覧ください。
本記事は.NET5を対象としています。ご了承下さい。
事前準備
.NET Coreを利用するためには.NET SDKと呼ばれる.NETアプリケーションに必要な一連のライブラリとツールが必要です。以下のURLからダウンロードしてください。
環境変数の設定
エラーの原因を探るためにstackoverflow、github issueなど英語の記事を探すことがあります。sdkをインストールするとデフォルトのlocaleが設定され、エラーが日本語で表示されます。日本語では記事が見つかりにくく、トラブルシュートに時間がかかってしまうのでデフォルトのlocaleはen-us
に設定することをオススメします。DOTNET_CLI_UI_LANGUAGE
環境変数にen-us
を設定すれば英語でエラーが表示されるようになります。
VSCodeの拡張
VSCodeの拡張が充実しているので入れた方が開発体験が上がると思います。最低限必要な拡張機能をインストールすることをオススメします。
C#のVSCode拡張です。デバッグなどC#にまつわる機能をサポートしています。
///
と入力するとSummaryのテンプレートを自動生成してくれます。
プロジェクト作成
dotnet new
コマンドを用いることで用意されたテンプレートに基づいてプロジェクトを作成することが出来ます。dotnet new
と叩くと、以下のようにconsoleアプリからWEB API、SPAと一通りのアプリケーションテンプレートが利用出来ることがわかります。
$ dotnet new
Template Name Short Name Language Tags
------------------------------------------- ------------------- ---------- ----------------------
Console Application console [C#],F#,VB Common/Console
Class library classlib [C#],F#,VB Common/Library
WPF Application wpf [C#] Common/WPF
WPF Class library wpflib [C#] Common/WPF
WPF Custom Control Library wpfcustomcontrollib [C#] Common/WPF
WPF User Control Library wpfusercontrollib [C#] Common/WPF
Windows Forms (WinForms) Application winforms [C#] Common/WinForms
Windows Forms (WinForms) Class library winformslib [C#] Common/WinForms
Worker Service worker [C#],F# Common/Worker/Web
MSTest Test Project mstest [C#],F#,VB Test/MSTest
NUnit 3 Test Project nunit [C#],F#,VB Test/NUnit
NUnit 3 Test Item nunit-test [C#],F#,VB Test/NUnit
xUnit Test Project xunit [C#],F#,VB Test/xUnit
MVC ViewImports viewimports [C#] Web/ASP.NET
Razor Component razorcomponent [C#] Web/ASP.NET
MVC ViewStart viewstart [C#] Web/ASP.NET
Razor Page page [C#] Web/ASP.NET
Blazor Server App blazorserver [C#] Web/Blazor
Blazor WebAssembly App blazorwasm [C#] Web/Blazor/WebAssembly
ASP.NET Core Empty web [C#],F# Web/Empty
ASP.NET Core Web App (Model-View-Control... mvc [C#],F# Web/MVC
ASP.NET Core Web App webapp [C#] Web/MVC/Razor Pages
ASP.NET Core with React.js and Redux reactredux [C#] Web/MVC/SPA
ASP.NET Core with Angular angular [C#] Web/MVC/SPA
ASP.NET Core with React.js react [C#] Web/MVC/SPA
Razor Class Library razorclasslib [C#] Web/Razor/Library
ASP.NET Core Web API webapi [C#],F# Web/WebAPI
ASP.NET Core gRPC Service grpc [C#] Web/gRPC
今回はASP.NET Core Web APIを作成します。作成するには以下のコマンドを入力します。
$ dotnet new webapi
カレントディレクトリを見るとASP.NET Core Web APIのテンプレートが作成されています。
$ ls
Controllers Startup.cs dotnetcore_sample.csproj
Program.cs WeatherForecast.cs obj
Properties appsettings.Development.json
README.md appsettings.json
.NET SDK のバージョンを管理する
.NET CLIコマンドを実行するときに使う .NET SDK のバージョンを定義します。異なるバージョンのプロジェクトを開発する際などに便利な機能です。バージョンを管理するファイルはglobal.json
というファイルで以下のコマンドを入力すると作成できます。
$ dotnet new globaljson
するとglobal.json
という名前で以下のようなファイルが作成されます。ここで使用するsdkのバージョンを固定することができます。
{
"sdk": {
"version": "5.0.403"
}
}
ソリューションファイルの作成
複数のプロジェクトファイルを整理するためにソリューションファイル(以下、sln)というものがあります。slnは必要なときにコマンドで生成するようになっています。プロジェクト作成で使用したnew
コマンドを利用してslnを作成します。
$ dotnet new sln
これでslnファイルのテンプレートが作成されました。プロジェクトに紐付ける場合はaddコマンドを入力します。以下は先ほど作成したプロジェクトファイルをslnファイルに追加しています。
$ dotnet sln add dotnetcore_sample.csproj
これで先ほど作成したプロジェクトに紐づきました。
実行
パッケージを取得します。
$ dotnet restore
プロジェクトを実行します。
$ dotnet run
実行するとhttps://localhost:5001で立ち上がるのでcurl
コマンドを叩いて結果を確認してみます。
$ curl -s -X GET https://localhost:5001/WeatherForecast | python -mjson.tool
[
{
"date": "2021-12-02T23:16:50.986985+09:00",
"summary": "Warm",
"temperatureC": -6,
"temperatureF": 22
},![スクリーンショット 2021-12-01 午後11.40.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496802/7c1eacb6-274a-4395-1130-d09fea08bb69.png)
...
]
ちゃんとWEB APIが動くことを確認できました。
ちなみにWEB APIテンプレートはSwaggerも導入されていますので、https://localhost:5001/swagger/index.htmlにアクセスするとswaggerの画面が表示されます。
監視する
dotnet watch
コマンドを用いてファイルを監視することで、ファイルが変更されたらビルドをしてくれます。毎回ビルドし直さなくても良くなるので開発効率が上がります。
$ dotnet watch run
watch : Started
Building...
ファイルを変更すると再度ビルドが始まり、変更内容をビルドしてくれます。
watch : Exited
watch : File changed: dotnetcore_sample/Program.cs
watch : Started
Building...
ステップ実行
プロジェクトファイルが存在するディレクトリでVSCodeを開くと以下のダイアログが表示されます。
Yesを入力すると.vscodeディレクトリが作成されアタッチするためのファイルが作成されます。F5を押下すると実行され、ブレークポイントを貼ってステップ実行が可能となります。
これで一通りの開発が出来るようになりました。
#Docker
.NET CoreではDockerが利用出来るようになりました。Dockerを用いることで環境依存を無くなり、AWS、GCP、Azureなどホスティングを選定する選択肢が広がります。AWS FargateやGCP Cloud Runなどサーバーレスを用いることで従来のホスティングより費用を抑えることが出来るのも魅力です。個人的には、これが一番強力だと感じています。
ビルド
先ほど作ったWEB APIをビルドします。まずはDockerfileを用意します。DockerfileはMSから公式のサンプルが出ていますので参考にすると良いかもしれません。
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /app
COPY *.sln .
COPY *.csproj .
RUN dotnet restore
RUN dotnet publish -c release -o /out
FROM mcr.microsoft.com/dotnet/aspnet:5.0
WORKDIR /app
COPY --from=build /app/out ./
ENTRYPOINT ["dotnet", "dotnetcore_sample.dll"]
ビルドします。パッケージがキャッシュされるため--no-cache
をつけています。
$ docker build --no-cache -t dotnetcore_sample .
実行します。
$ docker run --rm -p 5000:80 dotnetcore_sample
これでlocalhost:5000に先ほど作成したWEB APIが立ち上がりました。
開発体験(DX)が向上するためのツール
Visual Studioがなくても開発出来ることを説明しましたが、ここからは快適に開発するためのツールを紹介します。
##.NETツール
.NETツールとは、NuGetにアップロードされたコンソールアプリケーションをCLI上で実行出来る仕組みです。nodeでいうnpmをイメージしてもらえるとわかりやすいかもしれません。.NETツールのおかげで、今まで煩雑だった.NET系のCLI処理が簡単にかけるようになりました。.NETツールには、どこでもコマンドが叩けるグローバルツール、既定のディレクトリのみ利用できるローカルツールの2種類があります。ここでは、C#で代表的なコードフォーマッタであるdotnet-format
を例にあげて紹介します。個人的にはDockerの次に魅力を感じています
.NETツールは以下のリンクから探すことが可能です。
グローバルツール
グローバルインストールするには-g
オプションを付けます。-g
オプションを付けると、どのディレクトリからもコマンドを入力することが可能です。
- インストール
$ dotnet tool install -g dotnet-format
- アンインストール
$ dotnet tool uninstall -g dotnet-format
- アップデート
$ dotnet tool update -g dotnet-format
- 実行
$ dotnet format
ローカルツール
特定のディレクトリのみ実行する場合は、ローカルツールを使用します。インストールしたツールを管理するマニフェストファイル1が必要です。GitHub ActionsなどのCIで実行する場合は、ローカルツールを利用します。
- マニフェストファイルを作成する
$ dotnet new tool-manifest
コマンドを実行すると.config/dotnet-tools.json
が追加され、以下のような内容になっているかと思います。
{
"version": 1,
"isRoot": true,
"tools": {}
}
これでマニフェストファイルの雛形が完成しました。次はマニフェストファイルにツールをインストールします。
- インストール
$ dotnet tool install dotnet-format
これでローカルにインストールされ、先ほど作成した.config/dotnet-tools.json
にdotnet-format
が追加されています。
{
"version": 1,
"isRoot": true,
+ "tools": {
+ "dotnet-format": {
+ "version": "5.1.250801",
+ "commands": [
+ "dotnet-format"
+ ]
+ }
+ }
}
これでローカルツールを利用する準備が整いました。あとはパッケージを取得し、実行するだけです。
- パッケージを取得する
$ dotnet tool restore
- フォーマットする
$ dotnet format
特定のディレクトリのプロジェクトに対してdotnet format
が適応されました。
コードフォーマッター
開発体験を向上するにはコードフォーマッタがあると便利です。.NETツールで紹介したdotnet-format
を用いて、VSCodeの連携を含めてご紹介します。dotnet-format
の使い方は.NETツールの章で説明させて頂きましたので、ここでは説明を省きます。
.NET6 SDKからdotnet formatが標準で組込みされるようになりました。.NET6を利用する方は.NETツールでのインストールは不要です
.editorconfigを作成する
.editorconfigがなくともフォーマットされますが、細かい設定が可能となるので作っておいた方が良いと思います。roslyn2の.editorconfigが公開されているので、この設定を持ってくるのが楽ですし、天下のroslynなので間違いはないかと思います。
VSCodeの保存と同時にフォーマットする
Ctrl + Sなどの保存と同時にフォーマットすると非常に開発が楽になります。
- 左下の歯車のアイコン→設定をクリックします
- フォームに「format」と入力します
- Format On Saveにチェックします
- フォームに「csharp」と入力します
"[csharp]": {
+ "editor.defaultFormatter": "ms-dotnettools.csharp",
},
これで、保存時にC#のソースコードがフォーマットされるようになりました。
静的コード解析
品質の高いコードを書くために、静的解析は必須です。C#にはさまざまな静的コード解析がありますが、ここでは私のオススメするRoslynator
を紹介します。なぜRoslynatorがオススメかというと、モダンな解析、CLIが充実しており、後述するCIに組み込むことが可能となります。
以前は、解析失敗してもexitコードが0で終わるというバグがあったため、CIに組み込む場合は自作のシェルスクリプトなど書く必要がありましたが、「dotnet format --check
と同じにして〜〜」とわがままを言ったところ、改善していただけました感謝
CLIでの.NET6はまだサポートされていません。issueに上がっており、対応前提で動いてくれてますので気長に待ちましょう(貢献するのもよいかも!)
インストール
.NETツールをインストールします。
$ dotnet tool install roslynator.dotnet.cli
パッケージ追加
解析対象のプロジェクトにパッケージを追加します。
$ dotnet add package Roslynator.Analyzers
解析
以下のコマンドで解析、修正が出来ます。解析はレベルがあり--severity-level
を使うと厳密に解析するか指定出来ます。
# 診断
$ dotnet roslynator analyze dotnetcore_sample.sln
# より厳密な解析
$ dotnet roslynator analyze dotnetcore_sample.sln --severity-level=hidden
# 修正
$ dotnet roslynator fix dotnetcore_sample.sln
先ほど作成したプロジェクトを実行すると以下のように解析結果が表示されます。
$ dotnet roslynator analyze dotnetcore_sample.sln
Load solution 'dotnetcore_sample/dotnetcore_sample.sln'
Done loading solution 'dotnetcore_sample/dotnetcore_sample.sln'
Analyze solution 'dotnetcore_sample/dotnetcore_sample.sln'
Analyze 'dotnetcore_sample' 1/1
Program.cs(22,17): info RCS1021: Use expression-bodied lambda.
Startup.cs(32,13): info RCS1021: Use expression-bodied lambda.
Startup.cs(54,13): info RCS1021: Use expression-bodied lambda.
Startup.cs(29,1): info RCS1036: Remove redundant empty line.
Program.cs(12,18): warning RCS1102: Make class static.
Done analyzing solution 'dotnetcore_sample/dotnetcore_sample.sln' in 00:02.30
3 RCS1021 Convert lambda expression body to expression-body.
1 RCS1036 Remove redundant empty line.
1 RCS1102 Make class static.
5 diagnostics found
VSCode拡張
VSCode拡張を入れると、開発中も解析してくれます。便利ですね〜〜
CIを導入する
コードの品質やデプロイを自動化するにはCIの導入が必要です。ここまでご紹介したツールを組み合わせてGithub Actionsを動かすサンプルをご紹介します。Github ActionsでなくともCodeBuildなどどのCIでも同じように動かすことが可能です。
ワークフローを追加する
mainブランチへのプルリクエストがトリガーとなるワークフローを追加します。github Actionsはlinuxが一番コスパが良いのでubuntuで実行しています。以下の例は、単純にビルド、フォーマット、解析のコマンドを羅列しているだけなので、ここまで記事を見ていただけたらわかると思います
name: .NET Core
on:
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: setup checkout
uses: actions/checkout@v2
with:
submodules: true
- name: setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.403
- name: restore project
run: dotnet restore
- name: build project
run: dotnet build --no-incremental
- name: restore .NET Tool
run: dotnet tool restore
- name: restore .NET Tool
run: dotnet tool restore
- name: analyze code
run: dotnet roslynator analyze --severity-level=hidden
- name: format code
run: dotnet format --check
プルリクエストを出す
プルリクエストを出すと、CIが動きチェックします。下記の例はチェックに失敗しています。
「Details」をクリックし、詳細を確認します。
静的コード解析が失敗したことにより、CIが落ちたことがわかります。
このようにCIが失敗したらマージさせないなどコードの品質向上するための仕組みを構築することが出来ました。
まとめ
以前書いた記事ではVisualStudioを使わないとどれだけ不便なのか、それとも問題ないのかをお伝え出来なかったので、一通り開発で必要なものを選別して書かさせていただきました。Windowsに依存するものでなければある程度、同じように開発出来ることがわかっていただけたかと思います。私個人としては、C#がマルチプラットフォームで開発出来ることを夢見てたので、とても感慨深いものがありますし、おそらく同じような方は多いのではないかと思います。とにかく.NET系は破壊的変更が少なく、継続して開発しやすい素晴らしいフレームワークだと思いますのでC#perも他の言語を触れていた人も含め、本記事で興味を持っていただければ幸いです