アーカイブ

Archive for the ‘ASP.NET’ Category

Antaris/RazorEngine は Windows 環境以外サポートしていない?

LinuxのDockerコンテナで動かしたら、こんな例外が発生しました。

RazorEngine.Templating.TemplateCompilationException : Errors while compiling a Template.
Please try the following to solve the situation:
* If the problem is about missing/invalid references or multiple defines either try to load
the missing references manually (in the compiling appdomain!) or
Specify your references manually by providing your own IReferenceResolver implementation.
See https://antaris.github.io/RazorEngine/ReferenceResolver.html for details.
Currently all references have to be available as files!
* If you get ‘class’ does not contain a definition for ‘member’:
try another modelType (for example ‘null’ to make the model dynamic).
NOTE: You CANNOT use typeof(dynamic) to make the model dynamic!
Or try to use static instead of anonymous/dynamic types.
More details about the error:
– warning: (6, 4) Unnecessary using directive.
– warning: (5, 4) Unnecessary using directive.
– warning: (9, 4) Unnecessary using directive.
– warning: (7, 4) Unnecessary using directive.
– warning: (8, 4) Unnecessary using directive.
– error: (0, 0) Unexpected error writing debug information — ‘COM Interop is not supported on this platform.’
Temporary files of the compilation can be found in (please delete the folder): /tmp/RazorEngine_xbytpgsp.sjz
The template we tried to compile is:

ん?

Unexpected error writing debug information — ‘COM Interop is not supported on this platform.’

RazorEngine の issue を見ると出てますね。
https://github.com/Antaris/RazorEngine/issues/539

とりあえず他のテキストテンプレートエンジンを探します。
しかし、どこにCOMの相互運用なんて使うんだろう。

広告
カテゴリー:ASP.NET, Docker

NSwagを使って、OpenIdConnectのリクエストを投げる

Docs の内容のそのまま実装すると、バージョンが微妙に古いらしく警告が出るのと、認証が必要なAPIの定義方法が書いていなかったのでメモです。

はじめに

ASP.NET WebApi のコントローラー定義をもとに OpenAPI 形式のドキュメントを出力してくれる拡張としては、Swashbuckle が有名ですが、NSwag という拡張もあります。

Microsoft Docs NSwag と ASP.NET Core の概要
https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/getting-started-with-nswag?view=aspnetcore-2.2

<

h3>認証の概要

<

h3>
WebAPI を呼び出すSPAがこんな感じで OpenId Connect のサーバーにトークンを要求しているとして、

http://localhost:5000/auth/connect/authorize?client_id=test.app&redirect_uri=http%3A%2F%2Flocalhost%3A5012%2Fcallback.html&response_type=id_token%20token&scope=openid%20profile%test.api&state=4d76e302ed5742afaff207b1aee6710e&nonce=ead99dbe46d442d18c72f3691f2766ca

ここでは http://localhost:5000 が認証サーバーで、http://localhost:5012 が認証を受けるリソースサーバー(本来はSPAがこれに当たるけれど、今回はSwaggerがSPAの代わりに認証を受けるのでWebApi サーバーとイコール)になります。

SPA を想定しているので、レスポンスタイプは implicit(id_token token) を指定しています。
また、WebAPI は test.api というリソースとして定義しているので、scope に test.api を含めています。

SPA は認証サーバーから返ってきた IDトークン を HTTPヘッダー に乗せるいつものやつですね。

<

h3>パッケージの参照

<

h3>
WebAPI側は次の2つのパッケージを参照します。

dotnet add package IdentityServer4.AccessTokenValidation --version 2.7.0
dotnet add package NSwag.AspNetCore --version 12.0.14

<

h3>JWTの検証設定

<

h3>
JWT の検証は Startup.cs の ConfigureServices メソッドで下記のように定義されているとします。

services.AddAuthentication("Bearer")
    .AddIdentityServerAuthentication(options =>
    {
        options.Authority = "http://localhost:5000";
        options.RequireHttpsMetadata = false;
        options.ApiName = "test.api";
        options.ApiSecret = "test.api.secret";
    });

<

h3>NSwagの設定

<

h3>
NSwag も JWT の検証と同じように Startup.cs の ConfigureServices メソッドで下記のように設定します。
注意点としては、Scope に WebApi のリソース名を入れてあげるのと、クライアントで指定したレスポンスタイプに応じた Flow を設定することですかね。

services.AddOpenApiDocument(config =>
{
    config.OperationProcessors.Add(new OperationSecurityScopeProcessor("oauth2"));
    config.DocumentProcessors.Add(new SecurityDefinitionAppender("oauth2",
        new SwaggerSecurityScheme
        {
            Type = SwaggerSecuritySchemeType.OAuth2,
            Flow = SwaggerOAuth2Flow.Implicit,
            AuthorizationUrl = $"http://localhost:5000/connect/authorize",
            Scopes = new Dictionary
            {
                { "test.api", "test.api" },
                { "openid", "openid"},
                { "profile", "profile"},
            }
        }));
});

ConfigureServices で設定が終わっているので、Configure メソッドで追加の定義をします。
クライアントで要求したClientIdと同じものをセットするようにします。
微妙に非推奨なI/Fが多くて困りました。

app.UseSwagger(); 
app.UseSwaggerUi3(settings =>
{
    settings.OAuth2Client = new OAuth2ClientSettings
    {
        AppName = "DemoApi",
        ClientId = "test.spa"
    };
});
カテゴリー:ASP.NET

Visual Studioでdockerコンテナのデバック中にError: 。というエラーでデバックが開始できない。

もう少し情報を出してほしいですよね。。。

0>C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Sdks\Microsoft.Docker.Sdk\build\Microsoft.VisualStudio.Docker.Compose.targets(310,5): Error: 。
トラブルシューティング情報の詳細については、http://aka.ms/DockerToolsTroubleshooting をご覧ください

一応このトラブルシュートに飛ばされます。
ここで挙げられているUserProfile以下のファイルをリネームなどを行ったけれど解決せず。
https://docs.microsoft.com/ja-jp/visualstudio/containers/vs-azure-tools-docker-troubleshooting-docker-errors?view=vs-2017

単品で docker-compose build をすると、正常に終わり、up も問題なくできて動く。
Visual Studioからデバックした時だけの問題っぽい。
今回の docker-compose にはソリューション内で作ったASP.NET Coreのコンテンが5つと、MySQL, Redis用のコンテナの7つからできているんだけれど、どこのコンテナが悪いかわからないので、とりあえずすべてコメントした上で、一つづつコメントを解除していく。

結局、前回話題にした alpineコンテナ をベースにしているDockerファイルが残っていたのが原因でした。

カテゴリー:ASP.NET, Docker

microsoft/dotnet:2.1-aspnetcore-runtime-alpine を基にしたコンテナを、Visual Studio でデバックしようとすると、/bin/bash が無いといわれデバックできない。

そのままですが、Visual Studioではdocker-composeプロジェクトのデバック開始時に、下記のようなコマンドを実行して、そのVisual Studioのセッションですでに起動しているコンテナ内のdotnetプロセスをすべて殺しに行きます。

docker exec -i b13437825d3e /bin/bash -c "if PID=$(pidof -x dotnet); then kill $PID; fi"

で、そのときに/bin/bash を使っているので、コンテナサイズの削減を目的にalpineとかにしていると、/bin/bashが無いよとか言われてデバックの開始に失敗します。

alpine に対する対応は始まっているらしく、Visual Studio 2019では対応が行われるようですが、2017を使っている間は、alpineベースのイメージを作る場合はDockerのビルドステージを分けるとかで対応する必要がありそうです。
https://developercommunity.visualstudio.com/content/problem/256756/new-container-tools-in-158-cant-debug-alpine-docke.html

どうしても alpine を使いたい人は、コンテナ起動時に apt add すれば良いので Dockerfile をこうすれば行ける。。。嫌だけれど

FROM base AS final
WORKDIR /app
RUN apt update && apt add bash
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "xxxxxxxx.dll"]

— 追記
TimeZone設定とかも欲しいし、baseで設定したほうが良い気がしてきた。

FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
ENV TZ=Asia/Tokyo
RUN apt update && apt add bash
WORKDIR /app
EXPOSE 80
カテゴリー:ASP.NET, Docker

asp.net core で src フォルダー直下をソリューションディレクトリにしてはいけない

src配下にソリューションディレクトリがあると深くなりすぎるので、こんな感じのリポジトリの構成にしたところ

+-- リポジトリーのルート
  +-- README.md
  +-- src
    +-- xxxx.sln
    +-- docker-compose.yml
    +-- Project1
    +-- Project2

docker-compose up したときに作られる network や volume が src-xxxx となってしまって、他のプロジェクトとコンフリクトした、、、
docker-compose up するときにプロジェクト名を設定してから上げれば良いんだけれど毎回だと辛い、ちょっと深くなるけれどソリューションフォルダーは作ったほうが良さそう

カテゴリー:ASP.NET, Docker

asp.net core 2.1 プロジェクトで docker build すると、CS2017が発生してビルドが失敗する

こんなエラーが出ました。

CSC : error CS2017: Cannot specify /main if building a module or library

検索したらこんなのが
ASP.NET Core 2.1 gives error CS2017: Cannot specify /main if building a module or library
https://github.com/aspnet/websdk/issues/350

指示通り、RazorCompileToolsetを追加したらビルドが通った。

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <StartupObject>MockMvc.Program</StartupObject>
    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
    <RazorCompileToolset>PrecompilationTool</RazorCompileToolset>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.1.2" PrivateAssets="All" />
    <PackageReference Include="Microsoft.Extensions.Http.Polly" Version="2.1.1" />
    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.0.2105168" />
    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.7" />
    <PackageReference Include="Refit" Version="4.6.58" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\AuthServer.IdentityServer\AuthServer.IdentityServer.csproj" />
  </ItemGroup>

</Project>

 

カテゴリー:ASP.NET, Docker

asp.net core の Secret Manager

前回 .net coreにおける設定値の解決 で説明したとおり、asp.net coreの設定情報はWebHostBuilderで定義した順序でJSONファイルやら環境変数やらを合成していく方法が取られているわけなんだけれど、asp.net coreには開発環境の機密情報を管理する仕組みとしてSecret Managerがあります。
https://docs.microsoft.com/ja-jp/aspnet/core/security/app-secrets?view=aspnetcore-2.1&tabs=windows

これまでもgit-hubなどの公開リポジトリーにソースコードを公開する場合は、開発環境とは言えデータベースの接続文字列が入るのは気持ち悪いので、機密情報は通常の設定ファイルとは別にして.gitignoreで除外設定したりしていました(接続文字列が入ってたりすると、git-hubから警告メールも来るし)。

Secret Managerがこれまでと違うのは、これまでプロジェクトにJOINした人がREADME.mdなどに記載された情報を元に設定ファイルを作ったり、必要に応じて人にもらって設定ファイルをセットアップしていたのが、Secret Managerに値を設定する場合はREADME.mdなどにコマンドを書いておけば簡単に環境のセットアップができるようになったことです。

まぁ、企業のプライベートリポジトリーでソースコードを管理していて、かつ開発環境に対する設定なら、環境設定もめんどくさいので、xxx.{env}.json(connectionString.Development.jsonとか)なファイルに接続情報を書いて、リポジトリーに入れちゃってもいいかなぁと思わなくもないけれど。

今の所、保存する設定情報の種類で下記のように保存先を変更しています。

開発環境 検証環境、本番環境
環境によらないアプリケーション共通の設定 xxxxx.json xxxxx.json
環境ごとの設定 xxxxx.{env}.json xxxxx.{env}.json
データベースの接続情報などの機密情報 connectionStrings.{env}.configなど or Secret Manager コンテナの環境変数,Azure KeyValut, AWS Secrets Managerなど
カテゴリー:ASP.NET, 未分類