2011年3月23日水曜日

ASP.NET MVCでCaptcha(キャプチャ)を使う

My Clipでもキャプチャを実装していたのだが、今回チヌかかり釣りMEGAでも同様のことをやりたかったので、昔のソースコードを引っ張り出してきて再確認したので、それをまとめておく。

使用しているのは下記ブログポストで紹介されているライブラリ。
ASP.NET MVC CAPTCHA

※最新のソースコードは下記ブログポストらしいのだが、ダウンロードしたバイナリをMVC 3の環境に組み込んでも参照しているアセンブリバージョンの兼ね合いでコンパイルができないので、今回はMy Clip実装時の上記ブログポストのソースコードで実装方法を紹介する。
MVC CAPTCHA for Preview Release 3

  1. 上記のリンクからソースコードをダウンロードし、ManagedFusion.Web のプロジェクトをコンパイルする
  2. コンパイルしてできた ManagedFusion.dll と ManagedFusion.Web.dll を ASP.NET MVC 3 のプロジェクトで参照する

3, 下記を web.config に追加する
<httpHandlers>
 <add verb="GET" path="captcha.ashx" validate="false" type="ManagedFusion.Web.Mvc.Handlers.CaptchaImageHandler, ManagedFusion.Web"/>
</httpHandlers>

4, 下記を Global.asax に追加する
public static void RegisterRoutes(RouteCollection routes)
{
 routes.IgnoreRoute("{handler}.ashx");
}

5, cshtml に下記を追加する
<div>
    @Html.Raw(Html.CaptchaImage(50, 180))
</div>
<div>
    @Html.Raw(Html.CaptchaTextBox("captcha"))
</div>
Html.Raw で囲んでいるのは CaptchaImage, CaptchaTextBox ともに文字列を返却するようになっているため。ソースコードを書き換えて各関数ともに文字列ではなく MvcHtmlString を返却するようにすれば Raw で囲む必要はなくなる。

6, コントローラーアクションに下記属性を追加する
 [CaptchaValidation("captcha")]
 [HttpPost]
 public ActionResult Register(RegisterModel model, bool captchaValid)
 {
   // Do something
 }
captchaValid にキャプチャでの検証結果が代入されている。

以上で5でコードを追加した cshtml を表示するばキャプチャが表示されているはずだ。

2011年3月8日火曜日

HttpWebRequestで画像をASP.NET MVCに送ってみる

当ブログ100回目のポストはHttpWebRequestを使って画像をASP.NET MVCで稼動しているサイトへアップロードする方法を解説する(元ネタはStackOverflow)。

クライアント - アップロード
static void UploadFile(string url, string file, string paramName, string contentType)
{
    var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
    var boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

    var wr = (HttpWebRequest)WebRequest.Create(url);
    wr.ContentType = "multipart/form-data; boundary=" + boundary;
    wr.Method = "POST";
    wr.KeepAlive = true;
    wr.Credentials = System.Net.CredentialCache.DefaultCredentials;

    var rs = wr.GetRequestStream();
    var headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
    var header = string.Format(headerTemplate, paramName, file, contentType);
    var headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
    rs.Write(headerbytes, 0, headerbytes.Length);

    var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
    var buffer = new byte[4096];
    var bytesRead = 0;
    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
    {
        rs.Write(buffer, 0, bytesRead);
    }
    fileStream.Close();

    var trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
    rs.Write(trailer, 0, trailer.Length);
    rs.Close();

    WebResponse wresp = null;
    try
    {
        wresp = wr.GetResponse();
        var stream2 = wresp.GetResponseStream();
        var reader2 = new StreamReader(stream2);
        var result = reader2.ReadToEnd();
        Console.WriteLine(string.Format("File uploaded. Server response is: {0}", result));
    }
    catch (Exception ex)
    {
        if (wresp != null)
        {
            wresp.Close();
            wresp = null;
        }
        Console.WriteLine("Exception occurred!! " + ex.ToString());
    }
    finally
    {
        wr = null;
    }
}
データをポストするときのフォーマットを正確に作ってやって、そこに送りたいデータをはめ込むだけ。

クライアント - 使い方
UploadFile("http://localhost:55778/Image/PostImage",
          @"C:\test.JPG",
          "file", "image/jpeg");

ASP.NET MVC側 - ImageController
[HttpPost]
public int PostImage()
{
    var request = base.HttpContext.Request;
    if (request.Files.Count == 0)
        return 0;

    var httpPostedFile = request.Files[0] as HttpPostedFileBase;
    httpPostedFile.SaveAs("tekitouna_path.jpg");
    return 1;
}

上記のコードをASP.NET MVCサイトを動作させた状態でクライアントを実行すればサーバ側でファイルを受け取り保存することが可能なはずだ。