ASP.NET Core 6 MVCでCSV出力をしよう!【Visual Studio 2022】

プログラミング

本記事は以下の続き、応用編です。

本記事の内容はチュートリアルで作成した映画の情報をCSV出力する実装です。

CSV出力は何かと業務で利用頻度が高いと思い、議事録として。

CSV出力する方法

それではやっていきましょう。

今回はチュートリアルで作成した、データベースから値を取得するのでDB接続などの手順は割愛します。冒頭で紹介した記事の続きです。まだの方はそちらを先に読んでください。

モデルを作成

Modelsフォルダを右クリックしCsvOut.cs を作成します。

CsvOut.cs のコードは以下のように修正します。

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

namespace MvcMovie.Models
{
    public class CsvOut
    {
        // ヘッダー
        private static string[] headerArray = { "Id", "Title", "ReleaseDate", "Genre", "Price" };

        // ヘッダーとCSVデータ作成
        public static string CreateCsv(List<Movie> 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(Movie m)
        {
            var sb = new StringBuilder();

            sb.Append(string.Format($@"""{m.Id}"","));
            sb.Append(string.Format($@"""{m.Title}"","));
            sb.Append(string.Format($@"""{m.ReleaseDate}"","));
            sb.Append(string.Format($@"""{m.Genre}"","));
            sb.Append(string.Format($@"""{m.Price}"","));

            return sb.ToString();
        }
    }
}

コントローラーを作成

続いて、コントローラーの処理を修正していきます。

チュートリアルで作成した、MoviesController.cs を以下のように修正します。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using MvcMovie.Data;
using MvcMovie.Models;
using System.Text;

namespace MvcMovie.Controllers
{
    public class MoviesController : Controller
    {
        private readonly MvcMovieContext _context;

        public MoviesController(MvcMovieContext context)
        {
            _context = context;
        }

        // GET: Movies
        public async Task<IActionResult> Index(string movieGenre, string searchString)
        {
            // Use LINQ to get list of genres.
            IQueryable<string> genreQuery = from m in _context.Movie
                                            orderby m.Genre
                                            select m.Genre;
            var movies = from m in _context.Movie
                         select m;

            if (!string.IsNullOrEmpty(searchString))
            {
                movies = movies.Where(s => s.Title!.Contains(searchString));
            }

            if (!string.IsNullOrEmpty(movieGenre))
            {
                movies = movies.Where(x => x.Genre == movieGenre);
            }

            var movieGenreVM = new MovieGenreViewModel
            {
                Genres = new SelectList(await genreQuery.Distinct().ToListAsync()),
                Movies = await movies.ToListAsync()
            };

            return View(movieGenreVM);
        }

        // GET: Movies/Details/5
        public async Task<IActionResult> Details(int? id)
        {
            if (id == null || _context.Movie == null)
            {
                return NotFound();
            }

            var movie = await _context.Movie
                .FirstOrDefaultAsync(m => m.Id == id);
            if (movie == null)
            {
                return NotFound();
            }

            return View(movie);
        }

        // GET: Movies/Create
        public IActionResult Create()
        {
            return View();
        }

        // POST: Movies/Create
        // To protect from overposting attacks, enable the specific properties you want to bind to.
        // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
        {
            if (ModelState.IsValid)
            {
                _context.Add(movie);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            return View(movie);
        }

        // GET: Movies/Edit/5
        public async Task<IActionResult> Edit(int? id)
        {
            if (id == null || _context.Movie == null)
            {
                return NotFound();
            }

            var movie = await _context.Movie.FindAsync(id);
            if (movie == null)
            {
                return NotFound();
            }
            return View(movie);
        }

        // POST: Movies/Edit/5
        // To protect from overposting attacks, enable the specific properties you want to bind to.
        // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
        {
            if (id != movie.Id)
            {
                return NotFound();
            }

            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(movie);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!MovieExists(movie.Id))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }
                return RedirectToAction(nameof(Index));
            }
            return View(movie);
        }

        // GET: Movies/Delete/5
        public async Task<IActionResult> Delete(int? id)
        {
            if (id == null || _context.Movie == null)
            {
                return NotFound();
            }

            var movie = await _context.Movie
                .FirstOrDefaultAsync(m => m.Id == id);
            if (movie == null)
            {
                return NotFound();
            }

            return View(movie);
        }

        // POST: Movies/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> DeleteConfirmed(int id)
        {
            if (_context.Movie == null)
            {
                return Problem("Entity set 'MvcMovieContext.Movie'  is null.");
            }
            var movie = await _context.Movie.FindAsync(id);
            if (movie != null)
            {
                _context.Movie.Remove(movie);
            }
            
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }

        private bool MovieExists(int id)
        {
          return (_context.Movie?.Any(e => e.Id == id)).GetValueOrDefault();
        }

        //CSV処理 start
        public async Task<IActionResult> csvDown(string download)
        {
            if (download == "download")
            {

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

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

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

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

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

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

            return View();
        }
        //CSV処理 end

    }
}

ビューにダウンロードボタンを追加

Movies/Index.cshtml に以下の処理を追記

@using (Html.BeginForm("csvDown", "Movies", FormMethod.Get))
{
    <button class="btn btn-secondary" value="download" name="download" type="submit">CSV出力(DB)</button>
}

アプリをテストする

テストをする前に、デバックした際に最初の画面の設定を変えておきます。

Program.csの内容を少し修正します。

【修正前】

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

【修正後】

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Movies}/{action=Index}/{id?}");

Controllerの値を変更しています。

それではデバックしてCSVがダウンロードされることを確認してください。

学習方法

ネットで学習を進めるのもいいですが、正しい情報を探すのが大変なので下記書籍をおすすめします。

最後に

書籍を購入して勉強するのもいいですが専門書は高いし、質問もできません。私はいつも世界最大級のオンライン学習サイトUdemyで学習を行っています。Udemyでは具体的な方法を教えてくれるし質問も可能なのでとても学習しやすいと感じています。セールも定期的に実施されています。私は90%オフもの講義もたくさんあるので私はセールを狙って購入しています。
「Udemy」公式サイト:https://www.udemy.com/
IT業界での転職を考えている人はIT求人ナビをご利用ください。
より良い環境への転職を考えている人はA8.netへの転職を考えてみては。給料よさそう。
更に上のエンジニアを目指すならテックアカデミーがおすすめ。

コメント

タイトルとURLをコピーしました