ASP.NET Core + angular2でやってみよう（その2） EF Coreの設定とか

ASP.NET core + angular2アプリケーションを作成する（その2）

その1は[こちら](http://qiita.com/shwld/items/3ed53f3e5d38625d3237)

[作業リポジトリはこちら](https://github.com/shwld/dotnetcore_angular2)

## EntityFramework Core を設定する
MySQLとかも使ってみたいが、今回はSQLServerを使う。

### パッケージのインストール

パッケージマネージャコンソールから

```
Install-Package Microsoft.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.SqlServer
```

project.jsonに以下を追加で記述してツールをインストールする（コンソールから入れる方法どうやるんだろう）

``` project.json
"dependencies": {
  "Microsoft.EntityFrameworkCore.Tools": {
    "version": "1.0.0-preview2-final",
    "type": "build"
  }
}

"tools": {
  "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
}
```

### 適当なモデルを作る

``` Models/Note.cs
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace core_angular2.Models
{
    [Table("Notes")]
    public class Note
    {
        [Required, Key]
        public float Id { get; set; }

        [Display(Name = "ノート名"), MaxLength(50)]
        public string Name { get; set; }
    }
}
```

コンテキストを作る

``` Models/DefaultContext.cs
using Microsoft.EntityFrameworkCore;

namespace core_angular2.Models
{
    public class DefaultContext : DbContext
    {
        public DefaultContext(DbContextOptions<DefaultContext> options)
            : base(options)
        { }

        public DbSet<Note> Notes { get; set; }
    }
}
```

### 接続に使うクラスを作る

``` Providers/EntityFrameworkConfigurationProvider.cs
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using core_angular2.Models;

namespace core_angular2.Providers
{
    public class EntityFrameworkConfigurationProvider : ConfigurationProvider
    {
        public EntityFrameworkConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction)
        {
            OptionsAction = optionsAction;
        }

        Action<DbContextOptionsBuilder> OptionsAction { get; }

        public override void Load()
        {
            var builder = new DbContextOptionsBuilder<DefaultContext>();
            OptionsAction(builder);

            using (var dbContext = new DefaultContext(builder.Options))
            {
                // dbContext.Database.EnsureCreated();
            }
        }
    }
}
```

``` EntityFrameworkConfigurationSource.cs
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace core_angular2.Providers
{
    public class EntityFrameworkConfigurationSource : IConfigurationSource
    {
        private readonly Action<DbContextOptionsBuilder> _optionsAction;

        public EntityFrameworkConfigurationSource(Action<DbContextOptionsBuilder> optionsAction)
        {
            _optionsAction = optionsAction;
        }

        public IConfigurationProvider Build(IConfigurationBuilder builder)
        {
            return new EntityFrameworkConfigurationProvider(_optionsAction);
        }
    }
}
```

``` EntityFrameworkExtensions.cs
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace core_angular2.Providers
{
    public static class EntityFrameworkExtensions
    {
        public static IConfigurationBuilder AddEntityFrameworkConfig(
            this IConfigurationBuilder builder, Action<DbContextOptionsBuilder> setup)
        {
            return builder.Add(new EntityFrameworkConfigurationSource(setup));
        }
    }
}
```

### 接続設定する

設定ファイルのひな型を作る

``` ConnectionStringsSettings.json
{
  "ConnectionStrings": {
    "DefaultContext": ""
  }
}
```

開発環境用の接続設定ファイルを作る

``` ConnectionStringsSettings.json
{
  "ConnectionStrings": {
    "DefaultContext": "Data Source=(LocalDb)\MSSQLLocalDB"
  }
}
```

Startup.csの最初でconnectionStringsを取得し、Configrationに設定する

（env.EnvironmentNameを使うことで環境ごとの接続文字列の定義を分けることができる）

``` Startup.cs
public Startup(IHostingEnvironment env)
{
    var connectionStringsConfig = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("connectionStringsSettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"connectionStringsSettings.{env.EnvironmentName}.json", optional: true)
        .Build();
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
        .AddJsonFile("connectionStringsSettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"connectionStringsSettings.{env.EnvironmentName}.json", optional: true)
        .AddEntityFrameworkConfig(options =>
            options.UseSqlServer(connectionStringsConfig.GetConnectionString("DefaultContext")));
    Configuration = builder.Build();
}
```

Startup.csのConfigurationServiceに追加する

```
public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddEntityFrameworkSqlServer();
    services.AddDbContext<DefaultContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultContext")));
}
```

### マイグレーションしてデータベースを作る

パッケージマネージャコンソールから

```
Add-Migration AddNoteTable
Update-Database
```

SQLServerオブジェクトエクスプローラーでデータベースができていることが確認できるはず

### Collationも設定しておく

```
Add-Migration SetDefaultCollation
```

``` 
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;

namespace core_angular2.Migrations
{
    public partial class SetDefaultCollation : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.Sql("ALTER DATABASE dotnetcore_angular2 SET SINGLE_USER WITH ROLLBACK IMMEDIATE;", suppressTransaction: true);
            migrationBuilder.Sql("ALTER DATABASE dotnetcore_angular2 COLLATE Japanese_BIN2;", suppressTransaction: true);
            migrationBuilder.Sql("ALTER DATABASE dotnetcore_angular2 SET MULTI_USER;", suppressTransaction: true);
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {

        }
    }
}

```

## ControllerからDbへ接続してみる

DbContextにコネクションストリング経由で取得するstaticメソッドを追加

``` 
public static DefaultContext GetBy(string connectionString)
{
    var optionsBuilder = new DbContextOptionsBuilder<DefaultContext>();
    optionsBuilder.UseSqlServer(connectionString);

    return new DefaultContext(optionsBuilder.Options);
}
```

Controllerにコネクションストリングを渡すために設定モデルを追加

``` Models/ConfigData.cs
namespace core_angular2.Models
{
    public class ConfigData
    {
        public string DefaultConnectionString { get; set; }
    }
}
```

Startup.csのConfigureServicesに設定を追加する

``` Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    ...

    services.Configure<ConfigData>(options =>
    {
        options.DefaultConnectionString = Configuration.GetConnectionString("DefaultContext");
    });
}
```

### ValuesControllerを修正してapi/values/1でDbの中身を取得してみる

``` Controllers/ValuesController.cs
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using core_angular2.Models;

namespace core_angular2.Controllers
{
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        private DefaultContext _Db { get; set; }
        public ValuesController(IOptions<ConfigData> optionsAccessor)
        {
            this._Db = DefaultContext.GetBy(optionsAccessor.Value.DefaultConnectionString);
        }

        // GET api/values
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        [HttpGet("{id}")]
        public string Get(int id)
        {
            var note = this._Db.Notes.First();
            return $"note: id={note.Id}, name={note.Name}";
        }

        // POST api/values
        [HttpPost]
        public void Post([FromBody]string value)
        {
        }

        // PUT api/values/5
        [HttpPut("{id}")]
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
        }
    }
}
```

### よし、とれた
> note: id=1, name=テストノート

※ データベースには適当に値を登録しておきました



次は認証周りとかやりたい

公式ドキュメントにはお世話になっています。

https://docs.asp.net/en/latest/

https://angular.io/docs/ts/latest/quickstart.html