アーカイブ

Archive for the ‘プログラミング’ 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

ソリューションファイルとプロジェクトファイルが同じディレクトリにある状態で、Dockerサポート(Dockerfile)を作成すると、docker build時にビルドが失敗する。

Visual StudioのソリューションエクスプローラーからDockerサポートの追加をして、docker build をしたところ、こんなエラーが出ました。
ログの全体はこんな感じ。

> docker build . -t sample
Sending build context to Docker daemon  339.5MB
Step 1/16 : FROM microsoft/dotnet:2.2-aspnetcore-runtime AS base
 ---> df0d46ff6229
Step 2/16 : WORKDIR /app
 ---> Using cache
 ---> e6407778a2d1
Step 3/16 : EXPOSE 80
 ---> Using cache
 ---> a17ec6fc7197
Step 4/16 : FROM microsoft/dotnet:2.2-sdk AS build
 ---> 343e2dc38168
Step 5/16 : WORKDIR /src
 ---> Using cache
 ---> 064e8cb7ff8d
Step 6/16 : COPY signalsample.csproj ./
 ---> 3361ca72b93c
Step 7/16 : RUN dotnet restore /signalsample.csproj
 ---> Running in d5b618d70751
MSBUILD : error MSB1001: Unknown switch.
Switch: /signalsample.csproj

For switch syntax, type "MSBuild /help"
The command '/bin/sh -c dotnet restore /signalsample.csproj' returned a non-zero code: 1

msbuild 時によくわからないスイッチがあると言われる。

For switch syntax, type “MSBuild /help”
The command ‘/bin/sh -c dotnet restore /signalsample.csproj’ returned a non-zero code: 1

dockerfileを見ると、

FROM microsoft/dotnet:2.2-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80

FROM microsoft/dotnet:2.2-sdk AS build
WORKDIR /src
COPY signalsample.csproj ./
RUN dotnet restore /signalsample.csproj
COPY . .
WORKDIR /src/
RUN dotnet build signalsample.csproj -c Release -o /app

FROM build AS publish
RUN dotnet publish signalsample.csproj -c Release -o /app

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "signalsample.dll"]

8行目の restore でプロジェクトファイルの指定/から始まっていてこいつがスイッチとして認識されているっぽい。

RUN dotnet restore /signalsample.csproj

たぶん、dotnet コマンドからプロジェクトを作ったあとに、同じフォルダーにソリューションフォルダーを作った事が原因だと思われる。(dotnet build や dotnet publish はソリューションフォルダーが無いことを考慮しているのに、dotnet restore は考慮されていのか…)
とりあえず、/を取るか、./とするとdocker buildもdocker-compose buildもうまく通った。

RUN dotnet restore signalsample.csproj
カテゴリー:Visual Studio タグ: