ASP.NET core DBのテーブルデータをCSVとしてダウンロードする

ASP.NET core DBのテーブルデータをCSVとしてダウンロードする

ASP.NET core MVCで、DBのテーブルデータをCSVとしてダウンロードする手順を記述してます。.NETのバージョンは6を使用してます。

環境

  • OS windows10 pro
  • IDE Visual Studio 2022
  • .NET 6

プロジェクト作成

「ASP.NET Core Web アプリ(Model-View-Controller)」を選択してプロジェクトを作成してます。
※ここでは「aspcoremvc」という名前でプロジェクトを作成してます。

SQLServer

「hoge」というDBにある「member」テーブルを使用します。

「member」テーブルに、以下のデータを作成してます。

EntityFrameworkCore追加

使用するパッケージを追加しておきます。

「ツール」 > 「NuGet パッケージ マネージャー」 > 「パッケージ マネージャー コンソール」を選択します。

以下の2つを作成したプロジェクトに追加しておきます。

PM> Install-Package -ProjectName プロジェクト名 -Id Microsoft.EntityFrameworkCore.SqlServer
PM> Install-Package -ProjectName プロジェクト名 -Id Microsoft.EntityFrameworkCore.Tools

Model作成

DBに接続して作成します。Scaffold-DbContextを使用して、以下のコマンドを実行してModelを作成します。

DB名 : hoge
ホスト : 192.168.xxx.xxx
ユーザー : sa
パスワード : password
modelを作成するフォルダ : Models
コンテキスト名 : MemberDbContext

PM> Scaffold-DbContext -Provider Microsoft.EntityFrameworkCore.SqlServer -Connection "Data Source=192.168.xxx.xxx;Database=hoge;user id=sa;password=password" -f -OutputDir "Models" -Context "MemberDbContext" -UseDatabaseNames -DataAnnotations

「Models」フォルダ配下に「Model」と「Context」が作成されていることが確認できます。

「MemberDbContext.cs」に記述されているDB接続情報は使用しないので、コメントアウトしておきます。

//        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
//        {
//            if (!optionsBuilder.IsConfigured)
//            {
//#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
//                optionsBuilder.UseSqlServer("Data Source=192.168.xxx.xxx;Database=hoge;user id=sa;password=password");
//            }
//        }

「member.cs」

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;

namespace aspcoremvc.Models
{
    [Table("member")]
    public partial class member
    {
        [Key]
        public int id { get; set; }
        public int department { get; set; }
        [StringLength(4)]
        [Unicode(false)]
        public string year { get; set; } = null!;
        [StringLength(2)]
        [Unicode(false)]
        public string month { get; set; } = null!;
        public int employee { get; set; }
        [Column(TypeName = "datetime")]
        public DateTime created_data { get; set; }
        [Column(TypeName = "datetime")]
        public DateTime updated_data { get; set; }
    }
}

「MemberDbContext.cs」

using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

namespace aspcoremvc.Models
{
    public partial class MemberDbContext : DbContext
    {
        public MemberDbContext()
        {
        }

        public MemberDbContext(DbContextOptions<MemberDbContext> options)
            : base(options)
        {
        }

        public virtual DbSet<member> members { get; set; } = null!;

//        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
//        {
//            if (!optionsBuilder.IsConfigured)
//            {
//#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
//                optionsBuilder.UseSqlServer("Data Source=192.168.101.187;Database=hoge;user id=sa;password=password");
//            }
//        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<member>(entity =>
            {
                entity.Property(e => e.created_data).HasDefaultValueSql("(getdate())");

                entity.Property(e => e.month).IsFixedLength();

                entity.Property(e => e.updated_data).HasDefaultValueSql("(getdate())");

                entity.Property(e => e.year).IsFixedLength();
            });

            OnModelCreatingPartial(modelBuilder);
        }

        partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
    }
}

DB接続情報

sqlserverと接続できるように接続情報を追加します。

「appsettings.json」に、以下のコードを追加します。

「ConnectionStrings」を追加します。

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "DefaultConnection": "Server=192.168.xxx.xxx;Database=hoge;User ID=sa;Password=password;"
  }
}

サービス登録

サービスに、コンテキストを登録します。「Program.cs」を編集します。

さきほど「appsettings.json」に作成した接続情報「DefaultConnection」を使用して「MemberDbContext」を登録します。

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();

// 追加
builder.Services.AddDbContext<MemberDbContext>(
    options => options.UseSqlServer(
        builder.Configuration.GetConnectionString("DefaultConnection")
        )
    );

Model作成

CSVデータを作成するためのModelを作成します。
ここでは「CsvOut.cs」という名前で作成してます。

「CsvOut.cs」

using System.Collections.Generic;
using System.Text;

namespace aspcoremvc.Models
{
    public class CsvOut
    {
        // ヘッダー
        private static string[] headerArray = { "id", "department", "year", "month", "employee", "created_data", "updated_data" };

        // ヘッダーとCSVデータ作成
        public static string CreateCsv(List<member> memberList)
        {
            var sb = new StringBuilder();

            // ヘッダーの作成
            sb.AppendLine(CreateCsvHeader(headerArray));

            // CSVデータの作成
            memberList.ForEach(x => sb.AppendLine(CreateCsvData(x)));

            return sb.ToString();
        }


        // ヘッダー作成
        private static string CreateCsvHeader(string[] headerArray)
        {
            var sb = new StringBuilder();
            foreach (var header in headerArray)
            {
                sb.Append($@"""{header}"",");
            }
            // 最後のカンマのみ削除
            return sb.Remove(sb.Length - 1, 1).ToString();
        }

        // CSVデータ作成
        private static string CreateCsvData(member m)
        {
            var sb = new StringBuilder();

            sb.Append(string.Format($@"""{m.id}"","));
            sb.Append(string.Format($@"""{m.department}"","));
            sb.Append(string.Format($@"""{m.year}"","));
            sb.Append(string.Format($@"""{m.month}"","));
            sb.Append(string.Format($@"""{m.employee}"","));
            sb.Append(string.Format($@"""{m.created_data}"","));
            sb.Append(string.Format($@"""{m.updated_data}"","));

            return sb.ToString();
        }
    }
}

Controller作成

「Controllers」フォルダ配下に「CsvController.cs」を編集します。

csvDownメソッド作成します。

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using aspcoremvc.Models;
using Microsoft.EntityFrameworkCore;

namespace aspcoremvc.Controllers
{
    public class CsvController : Controller
    {
        private readonly MemberDbContext _context;

        public CsvController(MemberDbContext context)
        {
            _context = context;
        }
        public async Task<IActionResult> csvDown(string download)
        {
            if (download == "download")
            {

                var members = from m in _context.members
                              select m;

                // リストを作成
                var memberList = await members.ToListAsync();

                // CSV生成
                var csvString = CsvOut.CreateCsv(memberList);

                var fileName = DateTime.Now.ToString("yyyyMMddHHmmss") + "_member.csv";

                // ダウンロードする文字列をbyteデータにする
                var csvData = Encoding.UTF8.GetBytes(csvString);

                // CSVファイルダウンロード
                return File(csvData, "text/csv", fileName);
            }

            return View();
        }

    }
}

View作成

次に「Views」配下に「csv」フォルダを作成して配下に「csvDown.cshtml」を追加しておきます。

formを追加します。

<form asp-controller="Csv" asp-action="csvDown" method="get">
    <button class="btn btn-secondary" value="download" name="download" type="submit">CSV出力</button>
</form>

「F5」キーでデバックを実行して、起動して「http://localhost:ポート番号/csv/csvDown」にアクセスします。

ボタンをクリックするとCSVファイルが出力されることが確認できます。