WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

ASP.NET Identity のユーザー管理 (MVC)

by WebSurfer 2017年10月29日 18:10

ASP.NET Identity ベースのフォーム認証を実装した ASP.NET MVC5 アプリケーションで、管理者がユーザー情報の追加、変更、削除を行う機能を実装する例を書きます。

ユーザー管理画面

CodeZine の記事「ASP.NET Identity でユーザーを管理する」に、ASP.NET Web Forms アプリ用のユーザー管理画面を作る手順が載っていますが、その MVC 版です。

ベースとなるのは、Visual Studio 2015 Community で MVC のテンプレートを利用し、認証に「個別のユーザーアカウント」を指定して自動生成させたプロジェクトです。設定は以下の画像を見てください。

MVC のテンプレート

上の設定で自動生成されたプロジェクトは ASP.NET Identity ベースのフォーム認証を使用する ASP.NET MVC5 アプリケーションの基本的機能を持ちます。

プロジェクトの作成後、Visual Studio で[デバッグの開始(S)]または[デバッグなしで開始(H)]で実行すると、Web サーバーとして IIS Express が立ち上がって web アプリが実行され、テンプレートに含まれている Home/Index がブラウザ(デフォルトで IE)に表示されます。

そこから[Register]をクリックしてユーザー登録を行うと、初回に EF Code First と LocalDB の機能を利用してユーザー情報のストア(.mdf ファイル)が App_Data フォルダに生成され、その後は登録した Email とパスワードでログイン可能になります。

その状態から、Web アプリケーションに管理者がユーザー情報の追加、変更、削除を行う機能を実装します。

ユーザー情報の追加、変更、削除を行うのに用いるクラスは以下の通りです。いずれもテンプレートから自動生成されたコードに完全な形で含まれているので、それらをそのまま利用します。

(1) Models/IdentityModels.cs

(2) App_Start/IdentityConfig.cs

また、App_Start/Startup.Auth.cs の Startup クラスで、ApplicationUserManager のインスタンスを OwinContext へ登録するコードも自動生成されます。

なので、Controller では HttpContext.GetOwinContext() で OwinContext を取得し、それから GetUserManager<ApplicationUserManager>() メソッドで ApplicationUserManager オブジェクトを取得できるようになっています。

それらを利用してユーザー情報の追加、変更、削除を行う Controller の実装例を以下に示します。説明はコード内のコメントに書きましたので、それを見てください。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

// 上は自動生成されたもの。それに以下の名前空間を追加
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Mcv5App2.Models;
using System.Threading.Tasks;
using System.Net;
using System.ComponentModel.DataAnnotations;

namespace Mcv5App2.Controllers
{
  // Edit 用に AccountViewModels.cs の既存の RegisterViewModel
  // を流用しようとしたが、パスワードを入力しない場合は検証に
  // 引っかかっるので、以下の EditViewModel を定義して利用。
  // (Controller 内に定義したのは単に分けるのが面倒だから)
  public class EditViewModel
  {
    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
    public string Email { get; set; }

    // PasswordValidator を使えばここでの検証は不要
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [System.ComponentModel.DataAnnotations.Compare(
     "Password", 
     ErrorMessage = 
     "Password と Confirm Password が一致しません")]
    public string ConfirmPassword { get; set; }
  }


  // ここから Controller のコード
  public class UsersController : Controller
  {
    private ApplicationUserManager _userManager;

    public ApplicationUserManager UserManager
    {
      get
      {
        return _userManager ?? 
            HttpContext.GetOwinContext().
            GetUserManager<ApplicationUserManager>();
      }
      private set
      {
        _userManager = value;
      }
    }

    // GET: Users(登録済みユーザーの一覧)
    // Model は ApplicationUser
    public ActionResult Index()
    {
      var users = UserManager.Users.
                OrderBy(user => user.UserName);
      return View(users);
    }

    // GET: Users/Details/Id(指定 Id のユーザー詳細)
    // Model は ApplicationUser
    public async Task<ActionResult> Details(string id)
    {
      if (id == null)
      {
        return new HttpStatusCodeResult(
                        HttpStatusCode.BadRequest);
      }

      var target = await UserManager.FindByIdAsync(id);

      if (target == null)
      {
        return HttpNotFound();
      }

      return View(target);
    }

    // GET: Users/Create(新規ユーザー作成・登録)
    // Model は AccountViewModels.cs の RegisterViewModel
    public ActionResult Create()
    {
      return View();
    }

    // POST: Users/Create(新規ユーザー作成・登録)
    // Model は AccountViewModels.cs の RegisterViewModel
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> 
                        Create(RegisterViewModel model)
    {
      // PasswordValidator による判定の結果は ModelState
      // には反映されないので注意(下記 result で判定)
      if (ModelState.IsValid)
      {
        // ユーザー入力のメールアドレスを UserName, Email
        // プロパティに設定して ApplicationUser を生成
        var user = new ApplicationUser {
                            UserName = model.Email,
                            Email = model.Email };

        // 上の ApplicationUser とユーザー入力のパスワ
        // ードで新規ユーザーを作成・登録
        var result = await UserManager.
                     CreateAsync(user, model.Password);

        // ユーザー作成・登録の成否を result.Succeeded で
        // 判定。PasswordValidator の判定結果も result に
        // 反映される
        if (result.Succeeded)
        {
          // 登録に成功したら Users/Index にリダイレクト
          return RedirectToAction("Index", "Users");
        }
        // result.Succeeded が false の場合 ModelSate にエ
        // ラー情報を追加しないとエラーメッセージが出ない。
        // AccountController と同様に AddErrors メソッドを
        // 定義して利用(一番下に定義あり)
        AddErrors(result);
      }

      // ユーザー登録に失敗した場合、登録画面を再描画
      return View(model);
    }

    // GET: Users/Edit/Id(指定 Id のユーザー情報の更新)
    // ここで更新できるのは UserName, Email, パスワード
    // のみ。
    // Model は上に定義した EditViewModel
    public async Task<ActionResult> Edit(string id)
    {
      if (id == null)
      {
        return new HttpStatusCodeResult(
                        HttpStatusCode.BadRequest);
      }

      var target = await UserManager.FindByIdAsync(id);

      if (target == null)
      {
        return HttpNotFound();
      }

      EditViewModel model = 
        new EditViewModel() { Email = target.Email };

      return View(model);
    }

    // POST: Users/Edit/Id(指定 Id のユーザー情報の更新)
    // ここで更新できるのは UserName, Email, パスワード
    // のみ。
    // UserName をソルトに使っていてパスワードだけもしくは
    // UserName だけを更新するのは NG かと思っていたが問題
    // なかった。(実際どのように対処しているかは不明)
    // Model は上に定義した EditViewModel
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> 
                  Edit(string id, EditViewModel model)
    {
      if (id == null)
      {
        return new HttpStatusCodeResult(
                        HttpStatusCode.BadRequest);
      }

      if (ModelState.IsValid)
      {
        var target = await UserManager.FindByIdAsync(id);
        target.Email = model.Email;
        target.UserName = model.Email;

        // ユーザーが新パスワードを入力した場合はパス
        // ワードも更新する
        if (!string.IsNullOrEmpty(model.Password))
        {
          // PasswordValidator による検証
          var resultPassword = 
              await UserManager.PasswordValidator.
                    ValidateAsync(model.Password);

          if (resultPassword.Succeeded)
          {
            // 検証 OK の場合、入力パスワードを hash
            var hashedPassword = 
                UserManager.PasswordHasher.
                HashPassword(model.Password);
            target.PasswordHash = hashedPassword;
          }
          else
          {
            // 検証 NG の場合 ModelSate にエラー情報を
            // 追加して編集画面を再描画
            AddErrors(resultPassword);
            return View(model);
          }
        }

        var resultUpdate = 
          await UserManager.UpdateAsync(target);

        if (resultUpdate.Succeeded)
        {
          // 更新に成功したら Users/Index にリダイレクト
          return RedirectToAction("Index", "Users");
        }
        AddErrors(resultUpdate);
      }

      // 更新に失敗した場合、編集画面を再描画
      return View(model);
    }

    // GET: Users/Delete/Id(指定 Id のユーザーを削除)
    // 階層更新が行われているようで、ロールがアサインされて
    // いるユーザーも削除可能。
    // Model は ApplicationUser
    public async Task<ActionResult> Delete(string id)
    {
      if (id == null)
      {
        return new HttpStatusCodeResult(
                        HttpStatusCode.BadRequest);
      }

      var target = await UserManager.FindByIdAsync(id);

      if (target == null)
      {
        return HttpNotFound();
      }

      return View(target);
    }

    // POST: Users/Delete/Id(指定 Id のユーザーを削除)
    // Model は ApplicationUser
    // 上の Delete(string id) と同シグネチャのメソッド
    // は定義できないので、メソッド名を変えて、下のよう
    // に ActionName("Delete") を設定する
    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> 
                        DeleteConfirmed(string id)
    {
      if (id == null)
      {
        return new HttpStatusCodeResult(
                        HttpStatusCode.BadRequest);
      }

      var target = await UserManager.FindByIdAsync(id);

      if (target == null)
      {
        return HttpNotFound();
      }

      // ロールがアサインされているユーザーも以下の一行で
      // 削除可能。内部で階層更新が行われているらしい。
      var result = await UserManager.DeleteAsync(target);

      if (result.Succeeded)
      {
        // 削除に成功したら Users/Index にリダイレクト
        return RedirectToAction("Index", "Users");
      }
      AddErrors(result);

      return View(target);
    }

    protected override void Dispose(bool disposing)
    {
      if (disposing)
      {
        if (_userManager != null)
        {
          _userManager.Dispose();
          _userManager = null;
        }
      }

      base.Dispose(disposing);
    }

    // ModelSate にエラー情報を追加するためのヘルパメソッド
    private void AddErrors(IdentityResult result)
    {
      foreach (var error in result.Errors)
      {
        ModelState.AddModelError("", error);
      }
    }
  }
}

上のコードは MSDN ライブラリに書いてある非同期版のメソッドを使っていますが、同期版も拡張メソッドとして定義されているようです。ケースバイケースでどちらが適切かを考えて使い分けた方が良いかもしれません。

View はコントローラをベースにスキャフォールディング機能を利用して自動生成できます。Visual Studio でアクションメソッドのコードを右クリックして[ビューを追加(D)...]を選ぶと、以下の画像のダイアログが表示されます。

View の作成

ここで Template と Model class を設定して[Add]ボタンをクリックすれば View は自動生成されます。

Data context class は必ず空白にしてください。余計な設定をすると余計なコードが自動生成されて "Multiple object sets per type are not supported." というエラーになると思います。

Tags:

MVC

JavaScript で全角数字を半角に変換

by WebSurfer 2017年9月24日 14:12

先の記事「全角数字を半角に変換」は C# のコードで書きましたが、それと同等なコードを JavaScript で実装してみました。

JavaScript で全角数字を半角に変換

JavaScript の String.prototype.replace(), String.fromCharCode(), String.prototype.charCodeAt() の使い方の備忘録ですので、記事としては面白くないと思います。スミマセン(汗)

上記のメソッドを利用して、テキストボックスに全角数字交じりの文字をタイプしてフォーカスを外すと全角数字 ⇒ 半角数字に変換するサンプルを以下に書いておきます。上の画像はその実行結果です。

<%@ Page Language="C#" %>

<!DOCTYPE html>

<script runat="server">

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title>JavaScript で全角数字 ⇒ 半角数字</title>
  <script src="/Scripts/jquery-1.10.2.js"></script>
  <script type="text/javascript">
  //<![CDATA[
    var zen2han = function(str) {
      str = str.replace(/[0-9]/g, function (s) {
        return String.fromCharCode(s.charCodeAt(0) - 0xFEE0);
      })
      return str;
    }

    $(function () {
      $("#text1").on("change", function () {
        var str = $(this).val();
        $(this).val(zen2han(str));
      });
    });
  //]]>
  </script>
</head>
<body>
  <form id="form1" runat="server">
    <h2>JavaScript で全角数字 ⇒ 半角数字</h2>
    <p>入力してフォーカスを外すと全角数字 ⇒ 半角数字に変換</p>
    <input id="text1" type="text" style="width: 350px;" />
  </form>
</body>
</html>

テキストボックスの change イベントでの書き換えのコーディングが面倒なので、その部分は jQuery を使ってますが、変換するためのメソッドは上記の JavaScript のメソッドを使っています。

replace メソッドは、第一引数の正規表現 /[0-9]/g にマッチした文字列の一部または全てを、第二引数に指定される文字列で置き換えた新しい文字列を返します。

第二引数には新しい部分文字列を生成するために実行される関数を指定することができます。上の例では匿名関数 function (s) { ... } を使っています。

全角数字の UTF-16 コードから 0xFEE0 を引くと半角数字の UTF-16 コードになるので、匿名関数 function (s) { ... } は JavaScript の charCodeAt メソッドと fromCharCode メソッドを利用して全角数字を半角数字の文字列に変換します。

具体的には (1) charCodeAt メソッドでインデックス 0 に位置する文字の UTF-16 コードを表す整数を取得、(2) それから 0xFEE0 を引いて半角数字の UTF-16 コードを取得、(3) fromCharCode メソッドで指定された UTF-16 値の文字列を取得して戻り値として返しています。

Tags: , ,

JavaScript

日付時刻と JSON 文字列

by WebSurfer 2017年8月27日 15:01

JavaScript の Date オブジェクトや .NET Framework の DataTime オブジェクトの JSON 文字列への変換について調べましたので備忘録として書いておきます。

ASP.NET ajax によるパース結果

JSON の紹介よると、その記事に書いてある value に直接設定できるのは string, number, object, array, true, false, null だけということですので、JavaScript の Date オブジェクトや .NET Framework の DataTime オブジェクトは string に変換して JSON 文字列に設定せざるを得ません。

変換は自力で行わなくても、例えば、JavaScript なら JSON.stringify() メソッド、.NET Framework なら DataContractJsonSerializer クラスを利用すれば自動的に変換してくれます。

その他、JavaScriptSerializer クラス、ASP.NET Web サービス、WCF、ASP.NET Web API でも DateTime 型を自動的に文字列に変換してくれますが、それぞれどのような結果になるかを以下にまとめておきます。

No. 方法 結果
(1) JSON.stringify() 2017-02-01T03:15:45.000Z
(2) DataContractJsonSerializer \/Date(1503727168573+0900)\/
(3) WCF 上記 (2) の結果と同じ
(4) JavaScriptSerializer \/Date(1030806000000)\/
(5) ASP.NET Web サービス 上記 (4) の結果と同じ
(6) ASP.NET Web API 2017-08-26T15:39:32.6330349+09:00

以下に上記 (1) ~ (6) のそれぞれの検証方法や備忘録として残しておいた方がよさそうな情報を書いておきます。

(1) JSON.stringify() メソッド

ECMAScript 2017 Language Specification (ECMA-262, 8th edition, June 2017) の 20.3.1.16 Date Time String Format のセクションによると、ISO 8601 Extended Format 即ち:

YYYY-MM-DDTHH:mm:ss.sssZ

という形式に変換することになっているそうです。

全てのブラウザで確認したわけではありませんが、IE11, Chrome 60.0.3112.113, Firefox 55.0.3 では確かにその通りになるのを確認しました。

なお、JavaScript の Data オブジェクトはローカルタイムとして扱われまずが、JSON.stringify() メソッドで文字列に変換すると UTC になるので注意してください(YYYY-MM-DDTHH:mm:ss.sssZ の末尾の Z は UTC であることを意味します)。

例えば、以下のコードを実行すると、

var dateTime = new Date(2017, 1, 1, 12, 15, 45);
var dateObject = { DateTime: dateTime };
var dateJson = JSON.stringify(dateObject);

dateJson は {"DateTime":"2017-02-01T03:15:45.000Z"} という JSON 文字列になります。

Date コンストラクタの引数で月を表す整数値は 0 (1月) から 11 (12月) なので、1 ⇒ 02 という結果になっています。時間 12 が 03 になるのは東京ローカルタイムが UTC に変換されるためです。

(2) DataContractJsonSerializer クラス

DataContractJsonSerializer クラスを使うと、別の記事「w2ui Grid」に書きましたように、.NET Framework の DateTime 型は:

\/Date(1503727168573+0900)\/

のような文字列に変換されます。

この例の最初の数字 1503727168573 は UTC 1970 年 1 月 1 日午前 0 時からカウントしたミリ秒、+0900 はオプションで、ローカルタイムの UTC からの時差だそうです。

詳しくは以下の MSDN ライブラリの記事「スタンドアロン JSON のシリアル化」の「高度な情報 / DateTime ワイヤ形式」のセクションの説明を見てください。

(3) WCF

先の記事「WCF と jQuery AJAX」の CarService.svc.cs のコードに以下のメソッドを追加して試してみました。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text;

namespace WebApplication1
{
    // web.config で aspNetCompatibilityEnabled="true" と設定され
    // ているので [AspNetCompatibilityRequirements(...)] が必要
    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = 
        AspNetCompatibilityRequirementsMode.Allowed)]
    public class CarService
    {
        // ・・・中略・・・

        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Wrapped)]
        public DateTimeJsonTest GetToday()
        {
            DateTimeJsonTest today = new DateTimeJsonTest();
            today.Today = DateTime.Now;
            return today;
        }
    }

    // ・・・中略・・・

    [DataContract]
    public class DateTimeJsonTest
    {
        [DataMember]
        public DateTime Today { set; get; }
    }
}

ブラウザから上記コードの GetToday を要求すると以下のような JSON 文字列が返されます:

{"GetTodayResult":{"Today":"\/Date(1503727168573+0900)\/"}}

すなわち、上記「(2) DataContractJsonSerializer クラス」の場合と同じになります。(内部的に DataContractJsonSerializer クラスを使って変換しているのであろうと思います。未確認ですが・・・)

(4) JavaScriptSerializer クラス

ASP.NET MVC の Controller クラスの Json メソッドの内部で .NET Framework のオブジェクトを JSON 文字列にシリアライズするために JavaScriptSerializer クラスが用いられているそうです。

先の記事「jQuery.ajax で JSONP」に JavaScriptSerializer クラスを使ってシリアル化を行っている例がありますので、これに少し手を加えて検証してみました。

その記事のコードを見てください。Controller の Jsonp アクションメソッドでは Address テーブルから AddressID, AddressLine1, City フィールドのデータを取得して匿名クラスのオブジェクトを作り、それを JavaScriptSerializer クラスの Serialize メソッドで JSON 文字列にシリアライズしています。

Address テーブルには ModifiedDate という datetime 型のフィールドがありますのでそれを匿名クラス address に追加してシリアライズしてみました。

Serialize(address) の結果は以下のような文字列となります。

{"AddressID":25,"AddressLine1":"9178 Jumping St.","City":"Dallas","ModifiedDate":"\/Date(1030806000000)\/"}

即ち、DateTime 型の変換結果は上記「(2) DataContractJsonSerializer クラス」とほぼ同じで、オプションのローカルタイムの UTC からの時差(上の例では +0900)が省略された形になっています。

(5) ASP.NET Web サービス

先の記事「ASP.NET AJAX と Web サービス」のコードに以下のメソッドを追加して試してみました。

<%@ WebService Language="C#" Class="CarService" %>

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.Script.Services;
using System.Collections.Generic;
using System.Linq;

// ・・・中略・・・

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class CarService : WebService
{
    // ・・・中略・・・

    [WebMethod]
    public DateTimeJsonTest GetToday()
    {
        DateTimeJsonTest today = new DateTimeJsonTest();
        today.Today = DateTime.Now;
        return today;
    }
}

public class DateTimeJsonTest
{
    public DateTime Today { set; get; }
}

上記 GetToday() メソッドを、要求ヘッダに Content-Type: application/json を追加して POST 要求すると(注)以下のような JSON 文字列が返されます:

{"d":{"__type":"DateTimeJsonTest","Today":"\/Date(1503712714770)\/"}}

(注)ASP.NET Web サービスの制約上 POST 要求しないとエラーになります。Content-Type を指定しない、または application/x-www-form-urlencoded とすると XML 形式で返されます。XML の場合は形式は上記とは異なり 2017-08-26T10:36:27.0809765+09:00 のようになります。

即ち、上記「(4) JavaScriptSerializer クラス」と同じ形式の文字列に変換されます(+0900 も同じく省略されています)。

ASP.NET AJAX を利用すると、\/Date(1503712714770)\/ という形式の文字列は、Date 型の JavaScript オブジェクトに自動的に変換されます。具体例は以下の通りです。

記事「ASP.NET AJAX と Web サービス」の「(2) JavaScript (097_ASPNETAjaxAndWebService.js)」のセクションに記載されているコードを以下のように書き換えます。

var serviceProxy;

// プロキシの初期化とコールバック関数の設定
function pageLoad() {
    serviceProxy = new CarService();
    serviceProxy.set_defaultSucceededCallback(Succeeded);
    serviceProxy.set_defaultFailedCallback(Failed);
}

// ボタンクリックで呼び出されるサービスメソッド  
function getToday() {
    serviceProxy.GetToday();
}

// AJAX 通信が成功したときに呼び出され、戻ってきたデータ
// を処置するコールバック関数。
// 引数 data は JSON 文字列ではなく、DateTimeJsonTest 型
// オブジェクト。それから Today プロパティで取得できるの
// は、文字列ではなく Date 型に変換済みのオブジェクト。
function Succeeded(data) {
    $('#output').empty();
    var now = data.Today;  // now は Date 型オブジェクト
    $('#output').append(
        "<p>" + now.getFullYear() + "年" +
        (now.getMonth() + 1) + "月" + now.getDate() + "日" +
        now.getHours() + "時" + now.getMinutes() + "分" +
        now.getSeconds() + "秒</p>"
    );
}

// ・・・以下略・・・

上の getToday() メソッドを「(3) apsx ページ (097_ASPNETAjaxAndWebService.aspx) 」のセクションに記載されているコードと同等な aspx ページから呼び出すと、Date 型オブジェクトが上記コードの now に取得でき、この記事の一番上の画像のとおり表示されます。

MSDN ライブラリの記事「スタンドアロン JSON のシリアル化」の「高度な情報 / DateTime ワイヤ形式」のセクションの説明によると、"UTC からの時差を示す部分(例: +0900)が指定されていない場合、時刻は UTC として逆シリアル化されます" とありますが、上記コードの結果はローカル時刻になります。

ASP.NET AJAX に代えて jQuery ajax を使う場合は自動的に Date オブジェクトには変換してくれませんので、自力でコードを書いて変換することになります。

具体例は以下の通りです。数字の部分を抜き出して JavaScript の Date コンストラクタの引数として渡し、Date オブジェクトを生成すれば ASP.NET AJAX と同じ結果が得られます。

function getDateByJqueryAjax() {
  $.ajax({
    type: "POST",

    url: "097_jQueryAjaxAndWebService.asmx/GetToday",

    contentType: "application/json; charset=utf-8",

    success: function (data) {
      if (data.hasOwnProperty('d')) {
          data = data.d;
      }
      $('#output').empty();
      var re = /^\/Date\(([0-9]+)\)\/$/;
      var results = re.exec(data.Today);
      var now = new Date(Number(results[1]));
      $('#output').append(
        "<p>" + now.getFullYear() + "年" +
        (now.getMonth() + 1) + "月" + now.getDate() + "日" +
        now.getHours() + "時" + now.getMinutes() + "分" +
        now.getSeconds() + "秒</p>"
      );
    },

    error: function (jqXHR, textStatus, errorThrown) {
      $('#output').text('textStatus: ' + textStatus +
                  ', errorThrown: ' + errorThrown);
    }
  });
}

(6) ASP.NET Web API

Visual Studio 2010 Professional のテンプレートを使って自動生成される ASP.NET Web API アプリのコードに、以下のメソッドを追加して試してみました。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using WebApi1.Models;

namespace WebApi1.Controllers
{
    public class HeroesController : ApiController
    {
        public DateTimeJsonTest Get()
        {
            DateTimeJsonTest today = new DateTimeJsonTest();
            today.Today = DateTime.Now;
            return today;
        }

        // ・・・中略・・・
    }
}

jQuery ajax を利用して上の Get() メソッドを呼び出すと以下のような JSON 文字列が返されます:

{"Today":"2017-08-26T15:39:32.6330349+09:00"}

DateTime 型の文字列への変換は上の「(5) ASP.NET Web サービス」の場合の XML 形式の応答の場合と同じです。

これは ASP.NET Web API 独自実装なのか、ISO 8601 などに準拠しているのかは調べ切れてません。

なお、この形式で、JavaScript の Date 型へのパースは IE11, Chrome 60.0.3112.113, Firefox 55.0.3 のいずれも可能です。例えば、jQuery ajax を使うと、success オプションに設定したコールバックの引数に上の JSON 文字列を JavaScript オブジェクトに変換して代入してくれますので、それから以下のようにして Date オブジェクトにパースできます。

success: function (data, textStatus, jqXHR) {
    var now = new Date(data.Today);
    $('#heroes').append(
        "<p>" + now.getFullYear() + "年" +
        (now.getMonth() + 1) + "月" + now.getDate() + "日" +
        now.getHours() + "時" + now.getMinutes() + "分" +
        now.getSeconds() + "秒</p>"
    );
},

Tags: , ,

AJAX

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  2018年1月  >>
31123456
78910111213
14151617181920
21222324252627
28293031123
45678910

View posts in large calendar