読者です 読者をやめる 読者になる 読者になる

1.21 jigowatts

Great Scott!

ASP.NET MVCはじめました~データのキャッシュ

概要

データキャッシュの実装とテストについて調べてみました。

参考資料

ASP.NET MVCでのキャッシュについては、今のところ、キャッシュ機能をアプリケーションに注入する方法が推奨されています。

特定のキャッシュ機能の実装に依存しないようにキャッシュサービスを注入してあげれば良さそう。

環境

キャッシュサービスの実装

インターフェイスと実装。インターフェイスは必要に応じて機能を追加します。書籍のサンプルコードではSystem.Web.CachingのCacheオブジェクトを使用していましたが、System.Runtime.CachingのMemoryCacheオブジェクトに置き換えてみました。
/Framework/ICacheService.cs

public interface ICacheService
{
    Object Get(String key);
    void Set(String key, Object data);
    Object this[String key] { get; set; }
}

/Framework/AspNetCacheService.cs

public class AspNetCacheService : ICacheService
{
    private readonly MemoryCache _memoryCache;
    public AspNetCacheService()
    {
        _memoryCache = MemoryCache.Default;
    }

    public object Get(string key)
    {
        return _memoryCache[key];
    }

    public void Set(string key, object data)
    {
        _memoryCache[key] = data;
    }

    public object this[string key]
    {
        get { return _memoryCache[key]; }
        set { _memoryCache[key] = value; }
    }
}
キャッシュサービスの注入

アプリケーションの起動時にキャッシュサービスを注入するためのパブリックなRegisterCacheServiceメソッドを用意しておくと、コントローラごとにサービスを注入する必要はなく、テストもできるって訳ですね。
Global.asax.cs

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ...

        RegisterCacheService(new AspNetCacheService());
        CacheService["StartTime"] = DateTime.Now.ToString();
    }

    private static ICacheService _internalCacheObject;

    public static void RegisterCacheService(ICacheService cacheService)
    {
        _internalCacheObject = cacheService;
    }

    public static ICacheService CacheService
    {
        get { return _internalCacheObject; }
    }
}


HomeController.cs

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var data = MvcApplication.CacheService["StartTime"];
        if (data != null)
        {
            ViewBag.StartTime = (String)data;
        }

        return View();
    }
}

キャッシュサービスのテスト

テストの時はモックを用意してRegisterCacheServiceメソッドに渡してあげる感じ。
HomeControllerTests.cs

public class HomeControllerTests
{
    [TestMethod()]
    public void IndexTest_Cache()
    {
        var expected = "2017-04-15 12:00:00.000";
        var mockCacheService = new Mock<ICacheService>();
        mockCacheService.Setup(m => m["StartTime"]).Returns(expected);
        MvcApplication.RegisterCacheService(mockCacheService.Object);

        var controller = new HomeController();
        ViewResult result = controller.Index() as ViewResult;
        var actual = result.ViewBag.StartTime;

        Assert.AreEqual(expected, actual);
    }
}

実行結果

f:id:sh_yoshida:20170415173157p:plain

参考資料

Visual Studio Community 2017 をインストールする

概要

Visual Studio Community 2017 をインストールします!*1

ダウンロード

いろんなルートでダウンロードできますが以下でいいでしょう。

www.visualstudio.com
f:id:sh_yoshida:20170414015220p:plain

インストール

インストーラ起動![続行]を押す。

f:id:sh_yoshida:20170414015613p:plain

数分間お待ちください。

f:id:sh_yoshida:20170414015617p:plain

ワークロードを選択しないとインストールサイズは 606MB ですが...

f:id:sh_yoshida:20170414020420p:plain

[ASP.NETとWeb開発]を選択してみると、サイズは 4.88GB になりました!ひとまずこれで[インストール]を押す。

f:id:sh_yoshida:20170414020433p:plain

インストールには1時間程度かかりました。

f:id:sh_yoshida:20170414023622p:plain

起動してみましょう!

f:id:sh_yoshida:20170414030740p:plain

起動

サインインしてみます。

f:id:sh_yoshida:20170414032923p:plain

別窓が上がり、二段階認証もクリア!RC版ではダメでしたけど解消されてますね。

f:id:sh_yoshida:20170414033002p:plain

VS Community 2017 が起動しました☆

f:id:sh_yoshida:20170414033049p:plain

RC版ではワークロードの選択で[Web開発]を選んだだけでは.NET Coreが入らなかったけど、[ASP.NETとWeb開発]に変更されてて、こっちでは.NET Coreがインストールされていました。

f:id:sh_yoshida:20170414033200p:plain

軽快なモジュール式インストール

https://www.visualstudio.com/ja/vs/community/

インストーラの[変更]からワークロードを追加してみます。

f:id:sh_yoshida:20170414033335p:plain

[.NETデスクトップ開発]、[Azureの開発]、[データの保存と処理]を追加で選択し、[変更]。

f:id:sh_yoshida:20170414033422p:plain

テンプレートが増えました。

f:id:sh_yoshida:20170414080942p:plain

不要になったらワークロードのチェックを外して[変更]することで必要なものだけが入った構成になります。

sh-yoshida.hatenablog.com

*1:RC版が出た時にお試しでインストールしたエントリーのアクセスが少し伸びてたので、RC版の内容でいいのかと思っていたところ、我が家のWindows機がリカバリ→再インストールとなったためVS Community 2017をインストールします!の略

ASP.NET MVCはじめました~PDFを出力する

概要

TuesPechkinというライブラリを使ってPDFを出力するやり方について調べてみました。

GitHub - tuespetre/TuesPechkin: A .NET wrapper for the wkhtmltopdf library with an object-oriented API.

f:id:sh_yoshida:20170330165500p:plain

環境

TuesPechkin?

Google翻訳してみたら「火器屋」って…物騒ですねぇ。以下、README.mdから。

TuesPechkin is a .NET Wrapper for the wkhtmltopdf library.

https://github.com/tuespetre/TuesPechkin

HTMLをPDFに変換してくれるwkhtmltopdfライブラリの.NETラッパーとあります。wkhtmltopdfというのが本体なんですね。

wkhtmltopdf

Azure Websites does not currently support the use of wkhtmltopdf.

https://github.com/tuespetre/TuesPechkin

試しにAzure App Serviceにデプロイしてみたけど現段階で動きませんでした。

You must have Visual C++ 2013 runtime installed to use these packages.

https://github.com/tuespetre/TuesPechkin

wkhtmltopdfがC++で書かれているからランタイムもないとダメなんすかね。

とりあえず、動かしてみましょう!

インストール

ライブラリのインストールはパッケージマネージャーコンソールより以下を実行。TuesPechkinライブラリも一緒にインストールされます。他にもTuesPechkin.Wkhtmltox.Win32とTuesPechkin.Wkhtmltox.Win64がそれぞれ用意されているので環境に合わせてって感じでしょうか。

PM> Install-Package TuesPechkin.Wkhtmltox.AnyCPU

実装

HTMLをPDFに変換してくれるってことは、出力したいイメージのViewを作成してあげればOKと理解したので、以前作ったToDoリストをPDF化してみます。ちょっと面倒なのはレイアウトページを使っているとヘッダーやフッターまで一緒に出力されてしまうので、Indexページをそのまま出力するんじゃなく、PDF出力用のIndexViewを用意しなきゃいけないとこですかね。

/Controllers/ReportController.cs

public class ReportController : Controller
{
    ...
    public ActionResult TodoReport()
    {
        var pdfData = CreatePDF("Todo", "Report", null);

        return File(pdfData, "application/pdf", "TodoReport.pdf");
    }

    private byte[] CreatePDF(string actionName, string controllerName, object routeValues = null)
    {
        var helper = new UrlHelper(ControllerContext.RequestContext);
        var indexUrl = helper.Action(actionName, controllerName, routeValues, Request.Url.Scheme);

        return _service.Create(indexUrl);
    }
}


/Services/Report/ReportService.cs

public class ReportService : IReportService
{
    ...
    public byte[] Create(string indexUrl)
    {
        var document = new HtmlToPdfDocument()
        {
            GlobalSettings =
            {
                ProduceOutline = true,
                DocumentTitle = "PDF Sample",
                PaperSize = PaperKind.A3,
                Margins =
                {
                    All = 1.375,
                    Unit = Unit.Centimeters
                }
            },
            Objects =
                {
                    new ObjectSettings()
                    {
                        PageUrl = indexUrl,
                    },
                }
        };

        var converter = new StandardConverter(
            new PdfToolset(
                new WinAnyCPUEmbeddedDeployment(
                    new TempFolderDeployment())));
        var pdfData = converter.Convert(document);

        return pdfData;
    }
}

実行結果

ToDoリストのIndexページの[Download PDF]リンクからPDFをダウンロードします。ただ、出力したいのはデータ部分のみ。ヘッダーもフッターも余計なリンクとかもいらないですね。

f:id:sh_yoshida:20170330165446p:plain

なので出力イメージのView(レイアウトページ使用なし)を用意しておきます。Viewなのでブラウザで見ることも可能。
※PDF出力の際に表示されるわけではありません。

f:id:sh_yoshida:20170330165506p:plain

ダウンロードリンクを押下すると、PDF出力処理が走って出力イメージのViewをPDFに変換してくれます。そして、Viewの通りに出力されました!BootStrapを使ってますが、問題なく理解してくれてますね!

f:id:sh_yoshida:20170330165500p:plain

ソース

github.com