質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.50%

  • IIS 7

    54questions

    IIS(インターネットインフォメーションサービス) 7は、 Microsoftによって開発された、Windowsの標準ウェブサーバーです。Window Server 2008 と Windows Vista向けにリリースされました。

  • ASP.NET Web API

    12questions

    ASP.NET Web APIはブラウザやモバイル機器のようなクライアント向けのHTTPサービスを構築するフレームワークです。Microsoft .NET Frameworkがベースになっており、RESTfulサービスを構築するには理想的です。

.Net Web API シングルトンについて

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 368

皆様に質問なのですが、IISを用いた.Net Web APIにてシングルトン等使われていますか?

当方始めてAPIを作っておりますが、シングルトンにSortedListで変数を持っています。まれに同時アクセスする際、ContainsKeyがfalseだったのに同じキーのエントリが存在するとの例外が発生します。

マルチテナントアプリのため、呼び出し元クライアントからのリクエストヘッダー内の施設情報を元に、設定を取得する必要があります。その際、毎回リードから入るのはもったいないためシングルトンに確保して居ます。
IISのワーカー再起動にて再度取得できるよう、ContainsKeyがfalseなら読み込んだ情報をシングルトンのプロパティのSortedListにAddする単純な作りです。

// シングルトン中のプロパティ例
public SortedList HogeList<string, Hoge> { get; set;}

// Add部分メソッド例
public Hoge GetHoge(string keyStr)
{
    Hoge result = null;
    if (AppSingleton.Instance.HogeList.ContainsKey(keyStr))
    {
        result = AppSingleton.Instance.HogeList[keyStr];
    }
    else
    {
        // オプジェクト作るメソッド呼ぶ
        result = CreateHoge(keyStr);
        AppSingleton.Instance.HogeList.Add(keyStr, result);
        // ↑ここで同じキーのエントリ...例外出る
    }
    return result;
}

この場合、CreateHoge後にもう一回Containsかけるくらいしか思いつかないのですが、根本解決とは思えません。
そもそもWeb APIでこのようなシングルトンで持つのは適していないのか?
みなさんはどうやってるのか知りたいですー!
ちなみに、プロパティの型はDictionaryでも良かったなーソートの必要性無いし...

2018/04/27 10:11追記
私の開発環境は以下です。
.Net 4(Coreでない)
IIS8.5
ですが、ある意味技法的な質問でもあるのでいろいろな回答をお待ちしております!

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • SurferOnWww

    2018/04/27 09:35

    開発環境を書いてください。特に Core か否か。

    キャンセル

  • ashinaga_onisan

    2018/04/27 10:13 編集

    すみません。追記いたしました。 また、Coreだとこういう技術がある、等でも構いませんので、ご意見お願いします!

    キャンセル

回答 2

checkベストアンサー

+2

.Net 4(Coreでない)

Core でなければ、旧来の Web Forms や MVC と同様に、Web API も ASP.NET ランタイム上で動くので、「アプリケーション状態」が使えます。

AllKeys、Count プロパティ、Add、Clear、Get、GetKey、Remove、RemoveAt、Set メソッドを使用する際、ロックおよびロック解除を自動で行う点に注目です。

詳しくは以下の記事の「アプリケーション状態」のセクションおよびそこから張られたリンク先の記事を見てください。

ASP.NET の状態管理の概要
https://msdn.microsoft.com/ja-jp/library/75x4ha6s.aspx

具体的には、例えば Global.asax の Application_Start で以下のように key / value を追加すると、

namespace WebAPI
{
    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            // 上はテンプレートで自動生成された既存のコード

            // Key / Value を「アプリケーション状態」に追加
            Application["test"] = "this is a HttpApplicationState test.";
        }
    }
}


コントローラーでは以下のようにして取得できます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using WebAPI.Models;
using System.Web.Http.ModelBinding;

namespace WebAPI.Controllers.BizB
{
    public class ListAuthorsWebApiController : ApiController
    {
        [HttpGet]
        [Route("BizB/ListAuthors/GetAllAuthors")]
        public List<AuthorDTO> GetAllAuthors()
        {
            System.Web.HttpContext context = System.Web.HttpContext.Current;
            System.Web.HttpApplicationState applicationState = context.Application;
            string testValue = (string)applicationState["test"];

            //・・・中略・・・
        }
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/27 16:54 編集

    なるほど!Win Formsの業務ばかりだったので初めて知りました。Application スコープに置いておけばシングルトンなんか要らないですね。頂いたサンプルやネット上の文献は全てstring型を値としていましたが、上述のSortedListそのまま突っ込むことも可能でした(^^)ただし、あまり大きなデータ入れるなとは書いてあるものの、明示的な線引きが無く扱いが難しそうです...せめて物理メモリの○%みたいな閾値があれば(´・ω・`)

    ところで、ロックが自動で行われる件についてまだ文献が見つけられていません。逆に動的にコールすると言った情報や、読んでる間はアプリケーション全体が止まるなどと言う本当かわからない情報もありました。この辺りは実際の動作確認もしてみますが、なにか詳しいサイト等ご存知ありませんでしょうか。

    キャンセル

  • 2018/04/27 19:07 編集

    > せめて物理メモリの○%みたいな閾値があれば

    メモリを圧迫するのは質問者さんの案シングルトンでも同じこと思うのですが・・・

    何にせよ、そういう指標はないと思います。少なくとも自分は聞いたことがないです。(そもそも質問者さんの運用環境で Web アプリにどのぐらいのメモリが割り当てられて・・・というのは質問者さんにしか分かりません)

    > ロックが自動で行われる件についてまだ文献が見つけられていません。

    自分の持っている本「プログラミング Microsoft ASP.NET 4」に書いてあったことですが「アクセスをシリアル(直列)化するために必要なロックメカニズム」は間違いなく実装されているようです。

    ただ、Item プロパティの get アクセサは Lock メソッドと組み合わせて使用しなければクロススレッドの読み取り書き込みを阻止しないという記述もありました。検証したわけではないので保証の限りではないですが。質問者さんの方で検証してみてください。

    なお、Application オブジェクトへの書き込みは推奨されなくなってるそうです。Cache を使えということのようです。

    なので、私が上のレスで書いたような使い方に限った方がよさそうです。

    キャンセル

  • 2018/04/27 22:45

    >シングルトンでも同じ
    シングルトンはあくまでワーカープロセスのリサイクル時に破棄されますが、Applicationスコープはアプリが動き続ける限り保持して、自アプリだけでなく他のIIS上のアプリにもパフォーマンスの影響を与えるようでした。

    調べた限りではCacheの方が適当のようですね!Applicationのロックのテストは、どうも自分だけがいじれるようにするため、スタンドアロンでのデバッグは失敗に終わりました...ログ吐くかなんかしてIIS Expressじゃないリアルなサーバーに配置してテストするほかなさそうです。
    この’自分しか’の捉え方もセッションでは無い何かで制御されているのか、フロントからの正規アクセスでロックして、その後テストクライアントから別セッションで問い合わせても特に怒られず...
    フロントの要求はレスポンス返すまで終わってるのですが、この時自動的にアンロックされているのでしょうかね?Application.IsLocked等ロック中か調べるすべがなくて(´・ω・`)

    なんにせよもう少し調べて見ます!ASP初心者に色々ありがとうございました!

    キャンセル

  • 2018/04/28 00:32

    一つだけ・・・

    > Applicationスコープはアプリが動き続ける限り保持して、

    ワーカープロセスのリサイクルで消えるのは同じです。それを考えて先の私のレスで Global.asax の Application_Start で設定するサンプルを書いてます。

    キャンセル

  • 2018/04/28 00:47

    ぁ、そうなのですね。すみません。何か変なページ読んだかもしれません(ノД`)
    ともするとシングルトンだろうが、Application だろうが、Global.aspxのパブリック変数だろうがメモリの食い方は一緒ですね。唯一Cacheだけが有効期限とともに解放されると。
    ご指摘ありがとうございました!

    キャンセル

+1

おそらく、その不具合というのは同時アクセスした時に双方のアクセスがかぶってしまうために、読み出してる最中に書き込みが起こって変なデータが読み出されてしまったり、複数の書き込みがかぶって、変なデータが書き込まれたりするんじゃないでしょうか。
そうならないように、いわゆる排他制御というのを行わなければなりません

シングルトンというのはインスタンスが一つ、というのを保証するもので、同時アクセスする時に排他制御してくれるってものではないですねー

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/27 16:57

    ご意見ありがとうございます。今回はシングルトンに置いたプロパティの更新に対する競合対策(排他制御)の仕方そのものの質問でした。タイトルが悪くて申し訳ありません。

    キャンセル

  • 2018/04/27 18:26

    そういうことなら、「ASP.NET 排他制御」でぐぐるとかすればいろいろでてきますねー

    キャンセル

  • 2018/04/27 22:48

    ありがとうございました!
    調べ方を聞いたわけではなかったのでSurferOnWwwさんをベストアンサーとさせていただきます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • IIS 7

    54questions

    IIS(インターネットインフォメーションサービス) 7は、 Microsoftによって開発された、Windowsの標準ウェブサーバーです。Window Server 2008 と Windows Vista向けにリリースされました。

  • ASP.NET Web API

    12questions

    ASP.NET Web APIはブラウザやモバイル機器のようなクライアント向けのHTTPサービスを構築するフレームワークです。Microsoft .NET Frameworkがベースになっており、RESTfulサービスを構築するには理想的です。