1.21 jigowatts

Great Scott!

ASP.NET MVCはじめました~MongoDBより値を取得し一覧表示する

概要

久しぶりにタイトルを戻してみました。というわけで今回はASP.NET MVC5(C#)からMongoDBにつなげてみます。まずはデータを取って一覧表示しようと思います。

Modelは簡単なユーザ情報を。こんな感じになります(デフォルト)。
f:id:sh_yoshida:20160912090429p:plain

環境

ドライバのインストール

パッケージマネージャーコンソールよりMongoDBのC#ドライバをインストールしましょう。

PM> Install-Package MongoDB.Driver

以下の3つがインストールされます。最新はいずれもv2.2.4です。

  • MongoDB.Bson
  • MongoDB.Driver
  • MongoDB.Driver.Core

MongoDBへ接続する

接続文字列とデータベース名を渡してあげるだけ。Rubyのドライバと似てますね。ローカルインストールされたMongoDBのsampleデータベースへ接続してみます。

■MongoDB.cs

var connectionString = ConfigurationManager.AppSettings["MongoDBConnection"];
var database = ConfigurationManager.AppSettings["Database"];
_client = new MongoClient(connectionString);
_database = _client.GetDatabase(database);

■Web.config

<appSettings>
    <add key="MongoDBConnection" value="mongodb://localhost"/>
    <add key="Database" value="sample"/>
</appSettings>

データの取得

条件なしで全件取得です。データベース、コレクション、メソッドという流れはシェルのAPIと一緒なのでわかりやすいと思います。

■UserRepository.cs

private static readonly string Collection = "users";

public async Task<IEnumerable<User>> GetAllAsync()
{
    var collection = GetCollection<User>(Collection);
    var filter = new BsonDocument();
    var result = await collection.Find(filter).ToListAsync();

    return result;
}

ラムダ式も用意されてます。こっちのほうが直感的かもしれない?

return await collection.Find(_ => true).ToListAsync();

MVC

あとはいつも通りですね。コードを一式載せておきます。

Model

■User.cs

using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using System.ComponentModel.DataAnnotations;

namespace aspnet_mvc5_mongodb.Models
{
    public class User
    {
        [BsonId]
        [BsonRepresentation(BsonType.ObjectId)]
        public string Id { get; set; }

        [BsonElement("name")]
        [Required]
        public string Name { get; set; }

        [BsonElement("age")]
        public int Age { get; set; }

        [BsonElement("email")]
        public string Email { get; set; }

        [BsonElement("address")]
        public string Address { get; set; }

    }
}

View

■Index.cshtml

@model IEnumerable<aspnet_mvc5_mongodb.Models.User>

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Name)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Age)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Email)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Address)
        </th>
        <th></th>
    </tr>

    @if (Model != null)
    {
        foreach (var item in Model)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.Name)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Age)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Email)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Address)
                </td>
                <td>
                    @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
                    @Html.ActionLink("Delete", "Delete", new { id = item.Id })
                </td>
            </tr>
        }
    }
</table>

Controller

■UsersController.cs

using aspnet_mvc5_mongodb.Models;
using aspnet_mvc5_mongodb.Repositories;
using aspnet_mvc5_mongodb.Repositories.Abstractions;
using System;
using System.Net;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace aspnet_mvc5_mongodb.Controllers
{
    public class UsersController : Controller
    {
        private readonly IUserRepository _repository;
        public UsersController()
            : this(new UserRepository())
        {

        }
        public UsersController(IUserRepository repository)
        {
            this._repository = repository;
        }

        public async Task<ActionResult> Index()
        {
            var model = await _repository.GetAllAsync();
            return View(model);
        }

        ...
    }
}

リポジトリ

■MongoDB.cs

using MongoDB.Driver;
using System.Configuration;

namespace aspnet_mvc5_mongodb.Repositories
{
    public class MongoDB
    {
        protected static IMongoClient _client;
        protected static IMongoDatabase _database;

        public MongoDB()
        {
            var connectionString = ConfigurationManager.AppSettings["MongoDBConnection"];
            var database = ConfigurationManager.AppSettings["Database"];
            _client = new MongoClient(connectionString);
            _database = _client.GetDatabase(database);
        }

        public static IMongoCollection<T> GetCollection<T>(string collection)
        {
            return _database.GetCollection<T>(collection);
        }

    }
}

■IUserRepository.cs

using aspnet_mvc5_mongodb.Models;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace aspnet_mvc5_mongodb.Repositories.Abstractions
{
    public interface IUserRepository
    {
        Task<IEnumerable<User>> GetAllAsync();
        ...
    }
}

■UserRepository.cs

using aspnet_mvc5_mongodb.Models;
using aspnet_mvc5_mongodb.Repositories.Abstractions;
using MongoDB.Driver;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace aspnet_mvc5_mongodb.Repositories
{
    public class UserRepository : MongoDB, IUserRepository
    {
        private static readonly string Collection = "users";


        public async Task<IEnumerable<User>> GetAllAsync()
        {
            var collection = GetCollection<User>(Collection);
            return await collection.Find(_ => true).ToListAsync();
        }

        ...
    }
}

実行

シェルから適当にデータを登録します。

> db.users.insertMany(
    [
        {name: "Alice", age:19, email: "Alice@simple.com", address: "New York"},
        {name: "Steve", age:28, email: "Steve@simple.com", address: "San Francisco"},
        {name: "Emily", age:31, email: "Emily@simple.com", address: "Chicago"}
    ]
)

こんな感じでデータが登録されてればOK。

f:id:sh_yoshida:20160912093442p:plain

/Users/Indexにアクセス。

f:id:sh_yoshida:20160912090429p:plain

次回は画面からデータ登録できるようにしてみます☆彡

Visual Studio Code Yeomanのgenerator-aspnetをアップデート

概要

先日ASP.NET Core 1.0 RTMがリリースされ、generator-aspnetもv0.2.0にアップデートされたようなのでnpmから更新します。
.NET Core SDKのインストールはこちらから

環境

OS X EI Capitan バージョン 10.11.5
Visual Studio Code バージョン 1.2.1

最新ではないパッケージを確認

$ npm outdated -g
Package           Current  Wanted  Latest  Location
generator-aspnet    0.1.0   0.2.0   0.2.0
yo                  1.7.0   1.8.4   1.8.4

yoも最新ではなかったのでついでにアップデートしちゃいます。

パッケージを更新

$ npm update -g yo
$ npm update -g generator-aspnet

generatorはyoからアップデートすることもできるので、こっちからやってもOKですね。

f:id:sh_yoshida:20160629061407p:plain

Webアプリケーションの作成

ターミナルから`yo`のコマンドを入力して対話形式でプロジェクトを作成していきます。

f:id:sh_yoshida:20160629070412p:plain
なんやかんやありまして
f:id:sh_yoshida:20160629070440p:plain

VS Codeで開いて実行してみました。
ターミナルが使えるようになって便利になりましたね。
f:id:sh_yoshida:20160629070703p:plain

ちゃんと動きました!
f:id:sh_yoshida:20160629070523p:plain

Visual Studio Application Insights と ライブストリームを試してみた

概要

こちらのde:codeセッションを見ていたところ、Application Insightsという機能が紹介されていました。
channel9.msdn.com

Visual Studio Application Insights は、実行中のアプリケーションを監視し、パフォーマンスの問題や例外の検出と診断、アプリの使用方法の把握に役立ちます。

https://azure.microsoft.com/ja-jp/documentation/articles/app-insights-asp-net/

まだプレビューなのですが、面白そうだったのでアプリケーションに組み込んでAzureのポータルでのライブストリームでの監視をするところまで試してみます!

環境

Visual Studio Community 2015 Update 2
ASP.NET MVC 5
Azure 開発者プログラム特典サブスクリプション

実装

新規プロジェクト作成時にも追加することができますが、今回は既存のプロジェクトに追加します。
Visual Studioでプロジェクトを右クリックし、コンテキストメニューから[Application Insights テレメトリの追加]を選択します。

f:id:sh_yoshida:20160615115638p:plain

アカウント情報とテレメトリの送信先を選択します。
新規でも作成できますが、既存のリソースに追加してみました。大きなアプリケーションの場合は他のコンポーネントと同じリソースグループに配置することがお勧めらしいです。

f:id:sh_yoshida:20160615115645p:plain

この状態でデバッグしても動くのですが、Application Insights Web SDKを最新の安定版に更新するようお勧めされるのでNuGetパッケージマネージャで[Microsoft.ApplicationInsights.Web]を最新プレビューに更新しました。

f:id:sh_yoshida:20160615115653p:plain

ローカル環境でデバッグ実行するとVisual Studioの診断ツールや、Application Insightsの検索ウィンドウでアプリケーションの状態を観測できます。先日作ったWeb APIの動作の詳細も確認できました!

f:id:sh_yoshida:20160615115726p:plain

また、プロジェクトを右クリックし、コンテキストメニューから[Application Insights]-[Open Application Insights Portal]を選択することでAzureのポータルが開きます。

f:id:sh_yoshida:20160615124752p:plain

ここでもアプリケーションの状態を監視することができ、さらにライブストリームではほぼリアルタイムで状態を観測できるようです。

f:id:sh_yoshida:20160615125037p:plain

試しに一人でリクエスト投げたり、エラー発生させてみたりしてみましたが、ほぼリアルタイムでした。

f:id:sh_yoshida:20160615120830g:plain

このライブストリーム機能はMicrosoft.ApplicationInsights.Webの2.1.0-beta2以降が必要です。上記の通り、デフォルトのバージョンが1.2.3だったため更新するまで使えませんでした。
あとこのWeb SDKは現段階では.NET Framework 4/4.5に依存するため、ASP.NET Coreプロジェクトではダメでした。

ふわーっと触って満足してGitHubにコミットしようと思ったのですが、.csprojファイルにサブスクリプションIDが記述されてますね。
f:id:sh_yoshida:20160615130836p:plain

サブスクリプション ID とは

Windows Azure をご利用頂く際に、お客様と日本マイクロソフト株式会社は、無償または有償のサブスクリプション契約 (無料評価版、従量課金プラン等) を結びます。お客様が締結したこのサブスクリプション契約を一意のものとして識別するために、マイクロソフトでは 32 桁の GUID を付与しています。この GUID がサブスクリプション ID です。

https://blogs.msdn.microsoft.com/dsazurejp/2013/12/06/id-id/

うーん、これは公開しないほうがいいかも?