ASP.NET Web APIでAPIのバージョニングを設定する

この記事は、ASP.NET Web APIを使用してAPIを作成する時に、バージョニングを設定する方法について記載したものです。


一般的にAPIでバージョニングを行う方法は以下のように複数ありますが、今回はURLにバージョンを指定する方法について紹介します。

  • URLに指定する

https://api.sample.com/v1/users

  • クエリパラメータに指定する

https://api.sample.com/users?version=1

  • メディアタイプに指定する

Accept: application/json;v=1

  • 独自のHTTPヘッダに指定する

X-API-Version: 1

設定の流れ

設定の流れとしては以下のような感じです。


1. NuGetでMicrosoftが公開しているAPIバージョニングのためのライブラリを自身のプロジェクトに追加する
2. WebApiConfig.csにAPIバージョニングの設定を追加する
3. 各コントローラークラスにApiVersionアノテーションを付ける


以下、設定の流れを詳細に見ていきます。

1. NuGetでMicrosoftが公開しているAPIバージョニングのためのライブラリを自身のプロジェクトに追加する


以下のURLに公開されている Microsoft.AspNet.WebApi.VersioningAPIバージョニングを設定したいプロジェクトに追加してください。


NuGet Gallery | Microsoft.AspNet.WebApi.Versioning 3.0.1


Visual Studioのソリューションエクスプローラーで対象のプロジェクトを右クリックし、NuGetパッケージの管理をクリックして検索ボックスに Microsoft.AspNet.WebApi.Versioning と入力し対象のライブラリが表示されたインストールしてください。
正常に追加されたらプロジェクトの参照に Microsoft.AspNet.WebApi.Versioning が表示されているはずです。

2. WebApiConfig.csにAPIバージョニングの設定を追加する


ASP.NET Web APIの設定を記載するWebApiConfig.csに以下のコードを追加してください。

// バージョニングの設定
var constraintResolver = new DefaultInlineConstraintResolver()
{
    ConstraintMap =
    {
        ["apiVersion"] = typeof( ApiVersionRouteConstraint )
    }
};
config.MapHttpAttributeRoutes(constraintResolver);
config.AddApiVersioning();
3. 各コントローラークラスにApiVersionアノテーションを付ける


最後に各コントローラークラスにApiVersionアノテーションを付ければ完了です。

SampleController.cs

namespace SampleApi.Controllers
{
    [ApiVersion("1")]
    [RoutePrefix("api/v{version:apiVersion}/users")]
    public class SampleController
    {
        [HttpGet]
        [Route("")]
        public async Task<IHttpActionResult> GetUsers()
        {
            .....
        }
    }
}


上記の場合以下のようなエンドポイントでリクエスト可能となります。

https://sample.com/api/v1/users

最後に

ASP.NET Web APIにおけるAPIバージョニングの設定方法は、ここで紹介した以外にもいくつか方法があります。その他の方法については以下のページを参照ください。

https://github.com/microsoft/aspnet-api-versioning
https://github.com/microsoft/aspnet-api-versioning/wiki/New-Services-Quick-Start#aspnet-web-api
https://github.com/microsoft/aspnet-api-versioning/tree/master/samples/webapi
https://github.com/microsoft/aspnet-api-versioning/wiki/Configuring-Your-Application

情報処理安全確保支援士に一発合格した勉強法

平成30年度秋期試験で、情報処理安全確保支援士に合格しました。

f:id:takumetal:20190110210332p:plain
試験結果

この記事では、情報処理安全確保支援士に合格するために私がやった勉強内容をご紹介します。
ですがご覧の通り、午後はギリギリです。あんまり偉そうなことは言えません。

勉強期間

4か月
午前I、午前IIの勉強は、応用情報技術者試験ドットコムと情報処理安全確保支援士ドットコムをそれぞれ使ったのですが、その履歴を確認すると6月後半から開始していたので、期間としては4か月くらいみたいです。

勉強内容

午前試験と午後試験に分けて書いていきます。

はじめに


情報処理の高度試験は、午前試験は足切りのようなもので、本番は午後試験です。 勉強時間の配分も午前は最低限に済ませて、午後の勉強に時間を割いた方が良いかと思います。 試験勉強を始める前に、色々な人の合格体験記を読んだのですが、午後Iが1番の難関と言っている方が多かったです。確かに午後Iも難しかったのですが、私は得点にも表れているように午後IIが1番難しかったです。 何より試験問題が長いので。。。

午前試験


午前I

応用情報技術者試験ドットコムの過去問道場で、繰り返し過去問を解きました。主に電車に乗っている時に解いていました。 過去問と全く同じ問題も出るので、午前Iはこれだけやっていれば充分かと思います。 60%取れればいいので、ここは最低限に済ませます。 短い空き時間を使って少しずつ解いていけば良いと思います。

午前II

こちらも午前Iと同じ方法です。 情報処理安全確保支援士ドットコムの過去問道場で、繰り返し過去問を解きました。 午前IIはセキュリティ関係の問いが多く、午後試験を解くために必要な用語や知識も身に付きます。 午前Iの過去問は応用情報のものなので、1回の試験分でも80問あり、結構量が多いのですが、こちらは25問しかないのでペースが速くなると思います。

午後試験


まず、過去問を1回分解いて、どれぐらいできるか確かめました。 結果、合格点には遠く及ばなかったので、以下の書籍を読みつつ、過去問を新しいものから順にひたすら解いていきました。

情報処理教科書 情報処理安全確保支援士 2019年版

情報処理教科書 情報処理安全確保支援士 2019年版

過去問は、IPAのサイトにあるものを印刷して使用していました。 最初はPC上で見たのですが、問題文と設問を行き来するのにとても不便だったので、ちょっと量は多かったですがすべて印刷しました。

たくさん過去問を解くことで、ある程度の文量の文章を読むことに慣れ、問題構成や設問のパターンを把握します。 分からない用語があれば、ネットで調べて概要を把握してください。 私は、共通鍵暗号公開鍵暗号、デジタル署名、証明書など、暗号関連の知識をつけるために以下の書籍を読みました。

暗号技術入門 第3版

暗号技術入門 第3版

過去問を解く際は、必ず時間を測ってください。自分がどれぐらいの時間で問題を解けるのか把握するためです。 午後試験は時間が足りない可能性もあるので、時間配分も意識しながら解くようにすると本番でも慌てずに済むと思います。

試験を受けての感想

私は免除がなく、午前Iから受けたので、丸一日とても長かったです。 本番の午後試験で重要だと思ったことは、自分が解答する問題をいかに早く選ぶことができるかです。 この選択に迷うとその分時間を消費してしまいますし、後から解答する問題を変えると、とても慌ててしまいます。 得点配分の大きい長文の記入形式問題に解答できそうな問題を選べば良いのではないでしょうか。

最後に、私が使用した教材です

応用情報技術者試験ドットコム
情報処理安全確保支援士ドットコム

情報処理教科書 情報処理安全確保支援士 2019年版

情報処理教科書 情報処理安全確保支援士 2019年版

上記のような勉強をすることで、私は1度目の挑戦で合格することができました。これから受験される方達の参考になれば幸いです。

LPIC 300 合格 LPIC Level 3 取得

LPIC 300に合格し、LPIC Level 3を取得しました。


取得点
570点


内訳

OpenLDAPの設定 75%
OpenLDAPの認証バックエンドとしての利用 100%
Sambaの基礎 63%
Sambaの共有の設定 88%
Sambaのユーザとグループの管理 66%
Sambaのドメイン統合 77%
Sambaのネームサービス 80%
LinuxおよびWindowsクライアントの操作 40%


受験回数・勉強期間
1回目。18日間です。


勉強に使ったもの
Ping-t
ping-t.com


勉強法
Ping-tの各問題をすべて金になるまで解きます。
次に模擬試験をひたすら行い、
模擬試験でコンスタントに90%以上取れるようになったら受験しました。


本番試験の感想
入力問題は12問でました。思っていたより多かったです。
だいたい30分くらいですべて解き終えて、
10分くらい見直しした後に終了。
Ping-tで見たような問題もありましたが、見たことのないような
問題の方が多かった印象です。

Ping-tだけでも合格できると思いますが、100%合格できるかは微妙ですね。
万全の状態で臨みたい方は、Ping-tと併せて他の対策もした方が良いかもしれません。

ImageToolsを使用してSilverlightアプリケーション上でGIFを再生する

ImageToolsというライブラリを使用して、Silverlightアプリケーション上でGIFを再生する方法を書きます。

ImageTools 公式サイト
imagetools.codeplex.com

使い方

  1. ImageToolsライブラリをダウンロードする。

上記公式サイトから、ライブラリをダウンロードしてください。


2.Silverlight アプリケーションのプロジェクトにImageToolsのDLLを参照設定する。
 GIFを再生するために必要なDLLはおおよそ以下の4つ。
 ImageTools.dll
 ImageTools.Controls.dll
 ImageTools.Utils.dll
 ImageTools.IO.Gif.dll

3.参照設定後、xamlファイルに以下のように記述する。
 namespaceにImageToolsを追加し、GIFを表示するためのImageToolsのAnimatedImageタグを定義する。

<UserControl x:Class="ImageToolsSampleApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:imagetools="clr-namespace:ImageTools.Controls;assembly=ImageTools.Controls"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <imagetools:AnimatedImage x:Name="image" Height="100" Width="100" Stretch="Fill" MouseLeftButtonUp="image_MouseLeftButtonUp"></imagetools:AnimatedImage>
    </Grid>
</UserControl>


4.上記xamlファイルのコードビハインドで以下のように記述する。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using ImageTools;
using ImageTools.IO;
using ImageTools.IO.Gif;

namespace ImageToolsSampleApp
{
    public partial class MainPage : UserControl
    {
        // GIFアニメーションの動いてるか止まっているかを持つフラグ
        private bool isAnimate = false;

        public MainPage()
        {
            InitializeComponent();
            Decoders.AddDecoder<GifDecoder>();

            ExtendedImage extendedImage = new ExtendedImage();

            // GIF読み込み完了時の処理
            extendedImage.LoadingCompleted += (sender, args) =>
            {
                Dispatcher.BeginInvoke(() =>
                {
                    image.Source = extendedImage;
                    isAnimate = true;
                    
                    // GIFの再生秒数を抽出
                    double totalDelayTime = 0F;
                    for (int i = 0; i < extendedImage.Frames.Count; i++)
                    {
                        totalDelayTime += (extendedImage.Frames[i].DelayTime / 100.0) * 1000.0;
                    }
                    totalDelayTime += (extendedImage.DelayTime / 100.0) * 1000.0;
                });
            };

            // GIF読み込み
            extendedImage.UriSource = new Uri("Image/sample.gif", UriKind.Relative);
        }

        // GIFクリック時の処理
        private void image_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            // GIFの状態をみて、再生するか止めるか行う
            if (isAnimate == false)
            {
                image.Start();
                isAnimate = true;
            } else 
            {
                image.Stop();
                isAnimate = false;
            }
        }
    }
}


以上

LPIC 202 合格 LPIC Level2 取得

先日、LPIC 202を受験し、合格。LPIC Level2を取得したので、受験記録を書きます。

取得点

640点

内訳
  • ドメインネームサーバ      75%
  • Webサービス          81%
  • ファイル共有          87%
  • ネットワーククライアントの管理 90%
  • 電子メールサービス       87%
  • システムのセキュリティ     78%
受験回数・勉強期間

1回目の受験。勉強期間は11日間。20〜30時間程度かなぁ。

勉強に使ったもの

ping-t
ping-t.com

Linux教科書 LPICレベル2 スピードマスター問題集 Version4.0対応
www.shoeisha.co.jp

勉強法

まず、3日間で、ping-tの問題を1周。次に2日間でping-tの問題を1周。
その後、スピードマスターの問題を解く。ping-tの模擬試験をやる。
最後に、スピードマスターの模擬試験をやる。みたいな感じです。

本番試験の感想

60問解くのに22分程度かかり、入力問題は10問出ました。
スピードマスターやping-tで見たような問題も結構出ました。

以下の条件を満たした状態で受験すれば、ほぼ受かるかと思います。

ping-tの模擬試験で常に90%以上取れる。
スピードマスターの問題を全てやって、模擬試験で7割程度取れる。

Rails チュートリアルでrails testした時に、「ActiveRecord::PendingMigrationError」が発生した時の対処

Railsチュートリアルをやっていてちょっとはまったところがあったので、同じことで困っている人のためにメモ。

【発生箇所】
Rails チュートリアルの第6章 6.3.1 ハッシュ化されたパスワード付近。

【現象】
6.3.1 ハッシュ化されたパスワードで、最初にusersテーブルにpassword_digestカラムを
追加するために、マイグレーションした後で、rails testコマンドを実行すると、以下のエラーが出る。

[vagrant@localhost sample_app]$ rails test
Running via Spring preloader in process 13972
/home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activerecord-5.0.1/lib/active_record/migration.rb:573:in `check_pending!': (ActiveRecord::PendingMigrationError)

Migrations are pending. To resolve this issue, run:

bin/rails db:migrate RAILS_ENV=test

from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activerecord-5.0.1/lib/active_record/migration.rb:586:in `load_schema_if_pending!'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activerecord-5.0.1/lib/active_record/migration.rb:592:in `block in maintain_test_schema!'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activerecord-5.0.1/lib/active_record/migration.rb:823:in `suppress_messages'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activerecord-5.0.1/lib/active_record/migration.rb:597:in `method_missing'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activerecord-5.0.1/lib/active_record/migration.rb:592:in `maintain_test_schema!'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/railties-5.0.1/lib/rails/test_help.rb:15:in `'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:293:in `require'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:293:in `block in require'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:259:in `load_dependency'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:293:in `require'
from /home/vagrant/rails_tutorial_since_20170315/sample_app/test/test_helper.rb:3:in `'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:293:in `require'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:293:in `block in require'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:259:in `load_dependency'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:293:in `require'
from /home/vagrant/rails_tutorial_since_20170315/sample_app/test/controllers/static_pages_controller_test.rb:1:in `'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:293:in `require'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:293:in `block in require'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:259:in `load_dependency'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:293:in `require'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/railties-5.0.1/lib/rails/test_unit/test_requirer.rb:11:in `block in require_files'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/railties-5.0.1/lib/rails/test_unit/test_requirer.rb:10:in `each'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/railties-5.0.1/lib/rails/test_unit/test_requirer.rb:10:in `require_files'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/railties-5.0.1/lib/rails/test_unit/minitest_plugin.rb:86:in `plugin_rails_init'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/minitest-5.10.1/lib/minitest.rb:80:in `block in init_plugins'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/minitest-5.10.1/lib/minitest.rb:78:in `each'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/minitest-5.10.1/lib/minitest.rb:78:in `init_plugins'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/minitest-5.10.1/lib/minitest.rb:129:in `run'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/railties-5.0.1/lib/rails/test_unit/minitest_plugin.rb:73:in `run'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/gems/2.3.0/gems/minitest-5.10.1/lib/minitest.rb:62:in `block in autorun'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/site_ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /home/vagrant/.rbenv/versions/2.3.2/lib/ruby/site_ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from -e:1:in `

'


【対処法】
まず、データベースをリセットするために以下のコマンドを実行。

[vagrant@localhost sample_app]$ rails db:migrate:reset
Dropped database 'db/development.sqlite3'
Dropped database 'db/test.sqlite3'
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite3'
== 20170403115448 CreateUsers: migrating ======================================

    • create_table(:users)

-> 0.0036s
== 20170403115448 CreateUsers: migrated (0.0037s) =============================

== 20170408025509 AddIndexToUsersEmail: migrating =============================

    • add_index(:users, :email, {:unique=>true})

-> 0.0039s
== 20170408025509 AddIndexToUsersEmail: migrated (0.0040s) ====================

== 20170408091417 AddPasswordDigestToUsers: migrating =========================

    • add_column(:users, :password_digest, :string)

-> 0.0023s
== 20170408091417 AddPasswordDigestToUsers: migrated (0.0023s) ================


次に、先ほどのエラーメッセージに表示されていた以下のコマンドを実行。

[vagrant@localhost sample_app]$ bin/rails db:migrate RAILS_ENV=test
== 20170403115448 CreateUsers: migrating ======================================

    • create_table(:users)

-> 0.0023s
== 20170403115448 CreateUsers: migrated (0.0024s) =============================

== 20170408025509 AddIndexToUsersEmail: migrating =============================

    • add_index(:users, :email, {:unique=>true})

-> 0.0021s
== 20170408025509 AddIndexToUsersEmail: migrated (0.0025s) ====================

== 20170408091417 AddPasswordDigestToUsers: migrating =========================

    • add_column(:users, :password_digest, :string)

-> 0.0018s
== 20170408091417 AddPasswordDigestToUsers: migrated (0.0019s) ================

こうすると、rails testが実行できるようになる。

以上

SQL Serverに大量のテストデータを登録するときのコツ

アプリケーションのテストで、データベース(SQL Server)に十数万件のテストデータを登録する必要がありました。
SQLファイルに自動でINSERT文を生成して、SQL Server Management Studioでそのクエリを実行すると、メモリ不足のエラーになり、データ登録ができずに困っていたのですが、INSERT文のあとに「GO」を付けるとうまくいきました。


以下のようにひたすら、INSERT文を書き続けると、メモリ不足でエラーになる。

INSERT INTO テーブル名 VALUES(1, "Japan", 0, "TEST");
INSERT INTO テーブル名 VALUES(2, "Japan", 0, "TEST");
INSERT INTO テーブル名 VALUES(3, "Japan", 0, "TEST");
INSERT INTO テーブル名 VALUES(4, "Japan", 0, "TEST");
INSERT INTO テーブル名 VALUES(5, "Japan", 0, "TEST");
INSERT INTO テーブル名 VALUES(6, "Japan", 0, "TEST");
・
・
・
・(何十万行のINSERT文)


そこで、以下のように「GO」を付けるとメモリ不足にならずクエリが成功する。

INSERT INTO テーブル名 VALUES(1, "Japan", 0, "TEST");
INSERT INTO テーブル名 VALUES(2, "Japan", 0, "TEST");
INSERT INTO テーブル名 VALUES(3, "Japan", 0, "TEST");
GO
INSERT INTO テーブル名 VALUES(4, "Japan", 0, "TEST");
INSERT INTO テーブル名 VALUES(5, "Japan", 0, "TEST");
INSERT INTO テーブル名 VALUES(6, "Japan", 0, "TEST");
GO
・
・
・
・(何十万行のINSERT文)


まぁ、「GO」を付けることで、1つのステートメントが終了しましたよ〜と通知するみたいですね。
「GO」を付けないとずっと1つのステートメントが続いてしまって、メモリが解放されずにどんどん圧迫してしまい、失敗していたみたいです。


知らないとちょっと困るので、メモ。