Nancy(ASP.NET)でファイルアップロードサーバの作り方。

C#のアプリケーションからファイルアップロードの実験をするのにウェブ上のAzureとかAWSのサーバに対してアップロードすんのはアレなんで簡易的なサーバをローカルに立てたいなと。

半年前までの自分なら間違いなくnode.js + expressでやったはずなので、ちょうど1年ぐらい前に書いた

express3 でファイルアップロード処理。
http://d.hatena.ne.jp/fkmt5/20130414/1365958239

でやったはず。
だけど、今ならピュアマイクロソフトC#オンリーでやりたくなったのでNancyを使ってやってみることにした。
Nancyの説明は省くけど、IISサーバから独立したセルフホスティング型のHTTPサーバで簡単に実現するフレームワーク(ライブラリ?)。

まずは、Nancyの準備から。
※Visual Studio2013が必要かも


ほんで

こんななって

こんな感じ

これでNancyの準備はオッケー

次にNancyのプロジェクトの作成

で、スケルトンっつーかテンプレートっつーか、Hello Worldみたいなのが出来上がる。
ともかくどんな感じか見てみようってことでF5キーを叩いて実行する。

ドーン!エラー!!!!スケルトンがエラーって!初心者に優しくない!

拡大すると

すげー難しそうなエラーが出てる!初心者に優しくなーい!
だけど、これってマイクロソフト系の技術でセルフホスティングする時のあるあるなのな。

How to fix a AutomaticUrlReservationCreationFailureException when using Nancy FX Self Host
http://stackoverflow.com/questions/18368821/how-to-fix-a-automaticurlreservationcreationfailureexception-when-using-nancy-fx


管理者権限でコマンドプロンプトを開いて、↓このコマンドをたたく。

netsh http add urlacl url=http://+:3579/ user=ユーザー名(ローカルアカウントorマイクロソフトアカウント)

3579っつーのはNancyプロジェクトテンプレートが生成するポート番号なんで、それぞれのコードに合わせる。(もしくは自分が使いたい空きポートに合わせる)

Program.cs

namespace FirstNancy
{
    using System;
    using Nancy.Hosting.Self;

    class Program
    {
        static void Main(string[] args)
        {
            var uri =
                new Uri("http://localhost:3579");

            using (var host = new NancyHost(uri))
            {
                host.Start();

                Console.WriteLine("Your application is running on " + uri);
                Console.WriteLine("Press any [Enter] to close the host.");
                Console.ReadLine();
            }
        }
    }
}

ほんで再実行したら。

となって、ブラウザで http://localhost:3579 にアクセスすると

ですよと。
ここまでがNancyをセルフホスティング(簡単に言えばサーバーマシンを用意せずに、開発マシンのローカルに簡易HTTPサーバを立てること)で動かすHello Worldの完成。

で、アップロードを受け付けるためにやらなアカンのは

  1. アップロード用のフォームの作成(HTMLのFORMでやんのが楽やから)
  2. サーバ側でmultipart/form-dataの待ち受け

アップロード用のフォームは↓こんな感じのHTMLになります。

    <form enctype="multipart/form-data" action="/upload" method="post">
        File Upload: <input name="userfile1" type="file"><br/>
        <input type="submit" value="Send File">
    </form>

それをプロジェクト内のViews/index.sshtmlに埋め込みます。

Nancyのロゴの下の方で良いでしょう。
index.sshtml

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>FirstNancy</title>

    <style type="text/css">

        body {
            text-align: center;
        }

    </style>

</head>
<body>
    <img src="@Path['~/Content/nancy-logo.png']" alt="Nancy logo" /><br />
    This view was rendered using the SuperSimpleViewEngine

    <br/>
    <br/>
    <form enctype="multipart/form-data" action="/upload" method="post">
        File Upload: <input name="userfile1" type="file"><br/>
        <input type="submit" value="Send File">
    </form>

</body>
</html>

これでアップロードフォームは完了。次にサーバ側の待ち受けの口を作ります。
IndexModule.csに/upload と言うURIにPOSTでリクエストが来た場合の処理を追記します。

            Post["/upload"] = parameters =>
            {
                var file = this.Request.Files.FirstOrDefault();
                var uploadFile = Path.Combine(@"C:\Upload", file.Name);
                using (var fileStream = new FileStream(uploadFile, FileMode.Create))
                {
                    file.Value.CopyTo(fileStream);
                }
                return View["index"];
            };

C#とウェブサーバ系のプログラミング経験がある人には何やってるのかすぐわかる感じなのですが。
http://localhost:3579/upload にPOSTでファイルアップロードされたら C:\Upload フォルダにアップロードされたファイルを上書き保存してく。こんな感じ。

IndexModule.cs

namespace FirstNancy
{
    using Nancy;
    using System.IO;
    using System.Linq;

    public class IndexModule : NancyModule
    {
        public IndexModule()
        {
            Get["/"] = parameters =>
            {
                return View["index"];
            };

            Post["/upload"] = parameters =>
            {
                var file = this.Request.Files.FirstOrDefault();
                var uploadFile = Path.Combine(@"C:\Upload", file.Name);
                using (var fileStream = new FileStream(uploadFile, FileMode.Create))
                {
                    file.Value.CopyTo(fileStream);
                }
                return View["index"];
            };
        }
    }
}

こんだけです。

マイクロソフト系の技術者の方でデスクトップアプリはバリバリでもウェブはちょっと・・・って人が多いのはやはり昔のASP.NETがヘビーでリッチでWindowsサーバが必要とハードルが高いのがあったと思います。
かといって、javaRubyJavaScriptまで手は広げたくないし。

Visual Studio上で、C#を使って開発するのが1番生産性が高いというようなプログラマの人がウェブもちょっとやってみっかな?と思うのであればセルフホスティングで動かすNancyは良い選択枝になると思います。
※node.js + socket.io なのがお望みならば、OWIN+SingnalRをセルフホスティングでどうぞ)

今日はここまで