ASP.NET WebAPI を使用したZIPファイルのアップロードから展開したそれぞれのファイルを仮保存とかなしでやるサンプル


仕事で複数のCSVをZIPしてアップロードする必要があったのでやってみました。

HTTPの圧縮方法でオーソドックなのは、JSONをGZIPしてあげれば良いのでしょう。
WEBアプリで完結できる場合はそちらの方がいいと思います。

しかし事務系の仕事などではCSVは現役バリバリのフォーマットだったりしますし、歴史あるシステムでもよく使われています。
今回はそんなCSVをZIPにするお話です。

html (cshtml)

bootstrapを使用しています。
デフォルトのファイル選択ボックスがダサいので小細工がしてあります。

<form class="form-inline" id="myform">
    <div class="form-group">
        <div class="hidden">
            <input id="file-input" type="file">
        </div>
        <input type="text" id="file-name" class="form-control" placeholder="select file..." readonly>
    </div>
    <div class="form-group">
        <div class="btn-group">
            <button type="button" id="browse" class="btn btn-info">Browse</button>
            <button type="button" id="upload" class="btn btn-info">upload</button>
        </div>
    </div>
</form>

javascript

こちらもhtmlに合わせた小細工がしてあります。
大切なのは$.ajaxあたりです(まあふぅんて感じか)。

$(function () {

    $('#browse').on('click', function () {
        $('#file-input').trigger('click');
    });

    $('#file-input').on('change', function () {
        $('#file-name').val($(this).val());
    });

    $('#upload').on('click', function () {
        upload();
    });

});

var upload = function () {

    var formData = new FormData();
    $file = $('#file-input');
    formData.append('file', $file[0].files[0]);// マルチでも送信できるがとりあえず1つ
    $.ajax({
        url: "http://localhost:54302/api/mytestapi",// この辺は環境に合わせて
        type: "POST",
        data: formData,
        cache: false,
        contentType: false,
        processData: false,
    })
    .done(function (data, textStatus, jqXHR) {
        alert(data);
    })
    .fail(function (jqXHR, textStatus, errorThrown) {
        alert("fail");
    });
};

C# (WebAPI Controller)

コントローラーに書くべきかはさておき。
今回はサンプルなのでコントローラーのみ。
(でもファイルフォーマットの処理をモデルにもってくのは違う気がするぞ。)
今回は自分が複数のCSVファイルをZIPしてアップロードするためCsvHelperを使用しています。

using CsvHelper;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Http;

namespace WebApplication1.Controllers
{
    public class MyTestApiController : ApiController
    {
        // POST api/<controller>
        public string Post(HttpRequestMessage request)
        {
            if (!request.Content.IsMimeMultipartContent())
                return string.Empty;

            var sb = new StringBuilder();

            MultipartMemoryStreamProvider provider = request.Content.ReadAsMultipartAsync().Result;
            foreach (var content in provider.Contents)
            {
                // 各Contentを処理
                using (var ms = new MemoryStream(content.ReadAsByteArrayAsync().Result))
                using (var za = new ZipArchive(ms))
                {
                    foreach (var entry in za.Entries)
                    {
                        sb.AppendLine($"===== {entry.FullName} =====");

                        using (var sr = new StreamReader(entry.Open()))
                        using (var csvr = new CsvReader(sr))
                        {
                            csvr.Configuration.HasHeaderRecord = true;
                            if (csvr.ReadHeader())
                            {
                                sb.AppendLine("----- Header -----");
                                sb.AppendLine(csvr.FieldHeaders.Aggregate((aggregated, item) => $"{aggregated},{item}"));
                            }

                            sb.AppendLine("----- Records -----");
                            while (csvr.Read())
                            {
                                sb.AppendLine(csvr.CurrentRecord.Aggregate((aggregated, item) => $"{aggregated},{item}"));
                            }
                        }

                        sb.AppendLine();
                    }
                }
            }

            return sb.ToString();
        }
    }
}

結果

アラートであれですけど。