1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

コンソールアプリケーションからWebサービスを叩いて取得したZIPファイルをローカルファイルとして保存してみた

Last updated at Posted at 2019-04-26

はじめに

良いタイトルが思いつかなかった。。。
PDFファイルとかを一纏めにしたZIPファイルのバイナリデータをWebサーバから取得して
クライアント端末に保存したい。
ということで、C#(.Net FW 4.5.2)で作成してみます。

システム構成図

ざっくりとこういうイメージで作ります。
image.png

  1. ConsoleAppからWeb I/Fを叩く
  2. Web I/FがAPIをコールしてZIPのバイナリデータを作成する
  3. Web I/FがAPIで作成したバイナリデータをConsoleAppに返却する
  4. ConsoleAppがバイナリデータをクライアント端末に保存する

という処理の流れになります。

コンソールアプリケーション

まずはクライアント端末に配置するコンソールアプリケーションから。

DownloadApp.cs
using System;
using System.Xml;
using System.Web;
using System.Net.Http;
using System.IO;
using System.Configuration;
using System.Text;
using System.Threading.Tasks;

namespace DownloadApp
{
    class DownloadApp
    {
        /// <summary>
        /// メイン処理
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            try
            {
                DownloadZipAsync().Wait();
            }
            catch (Exception ex)
            {
                // エラー処理
            }
        }

        static async Task DownloadZipAsync()
        {
            using (var client = new HttpClient())
            {
                // 1. GETでデータ取得
                string uri = "http://localhost:50984/WebService/WebService.asmx/GetBinaryOfZip?userId=1";
                HttpResponseMessage res = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead);

                // 2. 保存するzipファイルのストリームをオープン
                string outputFilePath = "C:\temp\test.zip"
                using (var fs = new FileStream(@outputFilePath, FileMode.Create, FileAccess.Write))
                {
                    // 3. 受信データの中身を読み込む
                    var resXml = await res.Content.ReadAsStringAsync();

                    var xmlDoc = new XmlDocument();
                    xmlDoc.LoadXml(resXml);

                    if (xmlDoc.GetElementsByTagName("base64Binary").Count == 0)
                    {
                        throw new ApplicationException("base64Binaryタグが存在しません。");
                    }

                    // 4. Webサービスから取得したBase64文字列をバイト型配列に変換
                    byte[] zipBinary =
                        System.Convert.FromBase64String(xmlDoc.GetElementsByTagName("base64Binary")[0].InnerText);

                    // 5. ファイルに書き込む
                    await fs.WriteAsync(zipBinary, 0, zipBinary.Length);
                }
            }
        }
    }
}

やっていることはシンプルです。
コード上の番号付きコメントを見れば大方わかると思います。
GETのURLの中身はテキトーです。環境に合わせて変更が必要です。

いくつかポイントを解説します。

・DownloadZipAsync().Wait()について

なぜWaitしているのか?
と思われた方がいらっしゃると思いますが、
コンソールアプリケーションで非同期メソッドを使用する場合、
Waitで処理の終了を待ってあげないと一瞬でMainの処理が終了してしまい、期待通りの動作になりません。
※今回はGETでWeb I/Fを呼び出す方法として「HttpClient」を使用しているため、DownloadZipAsyncメソッドは非同期メソッドとなっています。

・System.Convert.FromBase64Stringについて

今回のサンプルで呼び出すWeb I/Fは「asmx.cs」に定義されているメソッドになります。
ここからバイナリデータを返却するとbase64でエンコードされるので、
クライアントで受け取った際にbase64でデコードしてやる必要があります。
※特に意識せずとも自動的にbase64でエンコードされて返却されるようなのですが、こういう仕様なのでしょうか?わかる方いらっしゃいましたらご教授いただけると幸いです。

Web I/F

次にコンソールアプリケーションからコールされるWeb I/F。

WebService.asmx.cs
[WebMethod]
public byte[] GetBinaryOfZip(string userId)
{
    return GetBinary(userId);    
}

private byte[] GetBinary(string userId)
{
    using (var ms = new System.IO.MemoryStream())
    {
        // メモリストリーム上にZipArchiveを作成する
        using (var zipArchive = new System.IO.Compression.ZipArchive(ms, ZipArchiveMode.Create, true))
        {
			string entryName = userId + "_test.jpg";
			byte[] buffer = [jpgのバイナリデータ];
            // ファイル名を指定してエントリを作成
            System.IO.Compression.ZipArchiveEntry entry = zipArchive.CreateEntry(entryName);
            using (Stream es = entry.Open())
            {
                // エントリにバイナリを書き込む
                es.Write(buffer, 0, buffer.Length);
            }
        }
        return ms.ToArray();
    }
}

すみません、説明簡略化のためにAPIの処理もここに含めてしまっています。
本来privateのGetBinaryメソッドはここにいるべきではありません!
ビジネスロジックをWebの顔に書くのはやめましょう。

では、こちらもポイントを解説します。

・ZipArchiveについて

これ非常に便利です。
ZipArchiveとZipArchiveEntryを絵で説明するとこんな感じです。
image.png
ZipArchiveという箱(要するにzipファイル)の中に
ZipArchiveEntryという物(要するに画像やPDFのファイル)を
入れ込んでいるといったイメージです。

このコード例ではエントリを1つしか書き込んでいませんが、
複数書き込むことで複数のファイルをzipファイルの中に入れることができます。

おわりに

備忘録代わりにと思ってだいぶ駆け足で書いてしまいました。
それでも誰かの参考になれば幸いです。

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?