nabehiro ブログ

開発・プログラミングに関して適当に書くブログ

CSV と Excel の読み書き用の C# のライブラリ TableIO を作りました

今更?感がありますが、年末年始で CSVExcel のようなテーブル形式のデータを
同じような方法で読み書きできるライブラリを作成しました。

github.com

仕事の都合で CSVExcel を同じようなインターフェースで扱いたい!と思っていて
最初は CsvHelper をゴニョゴニョしてやろうと思ったんですが( CsvHelper.Excel 使ったり)
やっぱり CSV 専用のライブラリなのでちょい厳しいと感じて、自作することにしました。

joshclose.github.io

使い方

1.nuget で、TableIO を取得。CSV だけじゃなく、Excel(xlsx) を扱いたいときは TableIO.ClosedXml を。

2.コードを書く。

using TableIO;

class Model
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Remarks { get; set; }
}

public void Main()
{
    IList<Model> models = null;

    // read file to models.
    using (var stmReader = new StreamReader("readfile.csv"))
    {
        // parameters is (textReader, hasHeader)
        var tableReader = new TableFactory().CreateCsvReader<Model>(stmReader, true);
        var models = tableReader.Read();

        Assert.AreEqual(5, models.Count);
        Assert.AreEqual(1, model[0].Id);
    }

    // write models to file.
    using (var stmWriter = new StreamWriter("writefile.csv"))
    {
        var tableWriter = new TableFactory().CreateCsvWriter<ValidCsvModel>(stmWriter);
        // parameter is (models, header)
        tableWriter.Write(models, new[] { "ID", "NAME", "PRICE", "REMARKS" });
    }
}

3.使い方の詳細は以下をご参照ください。
GitHub - nabehiro/TableIO: TableIO provides common interaface for reading and writing CSV, Excel and other table format content.

LINE Pay を、C# で試してみた

昨日 LINE Pay を導入したいんだけどみたいな話をクライアントに言われたので調べてみた。

LINE Pay は Sandbox 環境が直ぐに利用できるのですんなり試すことができました。
LINE Pay Developers : Sandbox creation

LINE Pay API を叩くまでの手続きは以下のリンクの通り。
LINE Pay のテストフロー

API 仕様は以下。。
技術サポート : LINE Pay Merchant

感想はわかりやすいつくりで簡単に導入できそうなイメージを持ちました。
一点混乱したのが、契約したサンドボックス環境の中にサンドボックスモードというのがあり、
最初よくわからなかったが、サンドボックスモードはPCのブラウザのみで、
LINE App(スマフォ)との連携をシミュレートしたモードということでした。。

以下は通常モードで、LINE App(スマフォ) からアクセスしたときの感じです。

自分のアカウントでは、LINE Pay をまったく使っていないせいかクレカ決済のみ
しか選択肢はでてこなかったですが、LINE Pay カードに事前にチャージしておけばそちらからも
支払うことができます。

一通り試した動作サンプルは Github に上げました。
GitHub - nabehiro/LinePaySample: LINE Pay sample C#

HomeController.cs がほぼ全て。

EntityFrameworkで登録日、更新日を自動設定する

Ruby on Rails みたいに、EntiryFramework・CodeFirst で CreatedAt, UpdatedAt を自動設定する方法がないか探してみた。

Adding CreatedDate to an entity using Entity Framework 5 Code First - Stack Overflow

を参考に、DbContext#SaveChanges() 時、
登録レコードは CreatedAt, UpdatedAt に現在日を、更新レコードは UpdatedAt に現在日を指定してます。

public partial class MyDbContext : DbContext
{
    public override int SaveChanges()
    {
        var now = DateTime.Now;
        foreach(var entry in ChangeTracker.Entries().Where(e => e.State == EntityState.Added || e.State == EntityState.Modified))
        {
            var type = entry.Entity.GetType();
            if (entry.State == EntityState.Added && HasCreatedAt(type))
                entry.Property("CreatedAt").CurrentValue = now;
            if (HasUpdatedAt(type))
                entry.Property("UpdatedAt").CurrentValue = now;
        }
        return base.SaveChanges();
    }

    private static Dictionary<Type, bool> _entityHasCreatedAtDic = new Dictionary<Type, bool>();
    private static Dictionary<Type, bool> _entityHasUpdatedAtDic = new Dictionary<Type, bool>();
    private bool HasCreatedAt(Type type)
    {
        if (!_entityHasCreatedAtDic.ContainsKey(type))
            _entityHasCreatedAtDic[type] = type.GetProperties().Any(p =>
                p.Name == "CreatedAt" && p.CanWrite && p.PropertyType == typeof(DateTime));
        return _entityHasCreatedAtDic[type];
    }
    private bool HasUpdatedAt(Type type)
    {
        if (!_entityHasUpdatedAtDic.ContainsKey(type))
            _entityHasUpdatedAtDic[type] = type.GetProperties().Any(p =>
                p.Name == "UpdatedAt" && p.CanWrite && p.PropertyType == typeof(DateTime));
        return _entityHasUpdatedAtDic[type];
    }
}

NLog ログ出力とエラー通知(プッシュ通知)を行う

エラーが発生した場合、メールで通知をすることが多いかと思います。
ただ、メールを都度確認するのは面倒なので、iPhone のプッシュ通知で確認する方法を考えてみた。
みんな大好き Atlassian が提供している HipChat & HipChat API & HipChat iPhone app を利用して
NLog の機能拡張(Nuget)を作成して、通知できるようにしてみました。

https://github.com/nabehiro/NLog.Extensions

利用する手順は以下の通り

HipChat アカウントの作成

https://www.hipchat.com/

HipChat 上にエラーの通知先のチャット部屋を作成
HipChat API 用の Auth Token(API v1.0) を作成

https://sigmact.hipchat.com/admin/api
※NLog.Extensions は、v1.0 にしか対応していません。(v2.0もありますので注意)

Nuget のインストール

NLog.Extensions をインストール。
好みで、NLog.Config (NLog設定ファイルの設定が楽になるNuget) をインストール

NLog.config を設定

https://github.com/nabehiro/NLog.Extensions#hipchat-target

iPhone の HipChat app でメッセージのプッシュ通知で受けるには通知先の人を、メンション(@nabehiro とか)で指定する必要があるようです。

NLog.config のサンプル
https://github.com/nabehiro/NLog.Extensions/blob/master/WebSample/NLog.config

NLog でログを書き出すコード追加
public class HomeController : Controller
{
    private static Logger _logger = LogManager.GetCurrentClassLogger();
    public ActionResult Index()
    {
        _logger.Info("Hello, Nlog on Web");

        try
        {
            throw new Exception("Oh,My God!!");
        }
        catch (Exception ex)
        {
            _logger.Error("Exception occured", ex);
        }
        _logger.Error("Hello, Nlog on Web, Error Error");

        return View();
    }
}

軽量なアプリケーションなら、メール+HipChat のエラー通知でいいかなーと。
メールサーバが死んでるときもカバー出来ますし。

余談

プログラムを変えずに対応するには、Zapier で
「あるZapierのメアドにメール受信すると、HipChat の API を投げる」
といった Zap を作っても対応できます。
無料枠だと 現在月80回しか Zap が実行できないのがキツイッス・・
Twilio も電話 or SMS で通知できるけど、ちょっと一通当たりタカイッス・・

ファイルダウンロード完了後に画面遷移などをjavascriptで行う

レアケースですが、PDFファイルダウンロード後にページの画面遷移(再読込)を行いたいケースがありました。
javascript(setInterval) と Cookie を利用するとファイルダウンロード後に処理を行うことができます。

サンプル

form submit でファイルダウンロードし、ダウンロードが完了した後に alert を出します。(画面遷移したい場合は、location.hrefなどで)
サーバサイドのファイルダウンロード処理の中では cookie({ name:"downloaded", value:"yes", path:"/"}) を発行します。

jquery.js, jquery.cookie.js を使用している前提。

<html><body>

<form>
  <input type="submit" value="ダウンロード" />
</form>

<script>
  // aタグで行う場合は、clickイベントで同様のことを行う
  $("form").submit(function() {
    setInterval(function () {
      if ($.cookie("downloaded")) {
        $.removeCookie("downloaded", { path: "/" });
        alert("ダウンロード完了");
      }
    }, 1000);
  });
</script>

</body></html>

俺の iGoogle を作ってみた

これまでお昼には必ずチェックしていた iGoogle
11/1 にサービス停止したのでクローンサイトを作って見ました。

俺の iGoogle
※無料 heroku にホスティングしているので初回リクエストは遅いかも。

感想

rails を触るのは、1.9 以来でしたが、
アップグレード量が多く、驚きました。(enviroments系のオプションの増加、turbolinks、...)
CoffeeScript と Sass を初めて使いましたが、rails ではビルドプロセスを意識することがなくて有難かったです。
あと最近 javascript MV* が流行っているのでベーシックっぽい backbone.js を試してみました。


最初、CoffeeScript と backbone.js を利用せずピュアな javascript で書いていましたが
機能を追加(今回はタブでコンテンツを切り替え)仕様とした際、
私の javascript の作りが悪いせいか、辛い&途方に暮れる 感じでした。。


それで、CoffeeScript と backbone.js を利用しだしました。
まだまだ backbone.js のご作法通りとは程遠い感はありますが個人的にコードは改善されたと思います。

本当は

クリックイベント等発火
→モデル変更
→モデル変更イベント発火
→モデル変更イベントをオブザーバー(ビュークラス)でビュー更新

というやり方が backbone.js のご作法なんだろうなーと思いつつ、うまく実装出来なかった部分はかなりありました、、


CoffeeScript はクラスを作るのが楽なのが嬉しいですね。
backbone.js が、Model, Collection, View クラスを継承して作るのが基本なので相性はいいと思いました。
あと、イベントコールバック内などでの、this の解決が楽なのがかなり嬉しい!(JSだけだと煩わしいコードになりがちでしたので)


今後は、CoffeeScript、Sass は積極的に使っていこうと思います

Azure Virtual Machine をバックアップするPowerShellスクリプトを作ってみました

Azure Virtual Machine のディスクをバックアップする PowerShellスクリプトを作ってみました。

GitHub - nabehiro/AzureVMBackup: Azure Virtual Machine Backup Power Shell Script

バックアップ方法

  1. (起動していたら)Virtual Machine を停止
  2. Virtual Machine のディスクに関連付けられている OSディスク、データディスクをバックアップディレクトリにコピーする
  3. (停止したら)Virtual Machine を起動
  4. (設定でバックアップ保持数を指定していたら)古い順にバックアップを削除

使用方法

Using Blob Snapshots to Backup Azure Virtual Machines | greatrexpectations

# Configuration
# ================================================================
$subscriptionName = "<input here>"
$cloudServiceName = "<input here>"
$virtualMachineName = "<input here>"
$remainigBackupCount = 2
  • 実行(PowerShellの権限設定を要求されるかも)

実行を継続するかの確認がはいりますので、あやまって実行しちゃっても中断できます。

利用上の注意

結構テストをして正常に動作することを確認していますが、
プラットフォームだけに問題が発生しても責任は取れません。



Windows Azure Powershell のコマンドを、C# で普通に使えるようにしてほしいなぁ。
https://github.com/WindowsAzure/azure-sdk-tools