SSブログ
前の10件 | -

活動拠点を移します

先に公開した記事が、公開と同時に消えてしまいました。

Twitter 連携をしていたので、消えた記事の名残が、Twitter にだけ虚しく残っています。

ちょっと信用ならないので、活動拠点を WordPress に移します。

https://mxlaboratory.wordpress.com/

ちなみにここで消えた記事は、上記 WordPress のひとつめの記事として復刻させました。

[Tips] 単体テスト ファイル アップロード – Unit test for file upload [ASP.NET MVC][Moq]  mx-laboratory
https://mxlaboratory.wordpress.com/2015/06/16/mvcfileupload/

この記事は消えないでよ、頼むよ。


[Note] Windows 10 Technical Preview インストール エビデンス(Windows 8.1 Pro クライアント Hyper-V) - Windows 10 Technical Preview installation evidence (Windows 8.1 Pro client Hyper-V) [Windows]

※すみません、今回の記事は当面日本語のみになります。

# Sorry, this article is only Japanese for the time being. 

先ごろ、Windows 10 が初めて正式に発表され、Technical Preview がリリースされましたね。

先日、週末の時間を利用して、手元の私用の Windows 8.1 Pro のクライアント Hyper-V 仮想マシンにインストールしました。

そのエビデンスを残します。

なお、セットアップを行う場合、多くの操作で管理者権限を要求されますので、最初から管理者権限を持つアカウントでログオンしたほうがお手軽です。

■Windows 10 Technical Preview の入手

以下のサイトから入手します。
[Windows Technical Preview - Microsoft Windows]
http://windows.microsoft.com/ja-jp/windows/preview

■復元ポイントの作成

クライアント Hyper-V の仮想環境の作成過程で、物理設定が変更されることがあります。

例えば、仮想スイッチの作成過程で、ネットワーク接続の設定が変更される場合があります。

万が一のことがあっても元に戻せるように、まずは復元ポイントを作成しておきます。

  1. チャーム バーから [検索] を選択します。
    w10tp-01.png
  2. [復元ポイントの作成] を検索して実行します。
    w10tp-02.png
  3. [システムのプロパティ] ダイアログが開きます。
    [システムの保護] タブで [作成] ボタンをクリックします。
    w10tp-03.png
  4. [復元ポイントの作成] ダイアログで、これから作成する復元ポイントにわかりやすい名前を付けて、[作成] ボタンをクリックします。
    w10tp-04.png
  5. 作成が完了するのを待ちます。
    w10tp-05.png
  6. 復元ポイントが正常に作成されたのを確認して、[閉じる] をクリックします。
    w10tp-06.png
  7. 作成された復元ポイントを確認しておきます。
    引き続き、[システムのプロパティ] ダイアログの [システムの保護] タブで、[システムの復元] ボタンをクリックします。
    w10tp-07.png
  8. [システムの復元] ウィザードが開きます。[次へ] をクリックします。
    w10tp-08.png
  9. 作成済みの復元ポイントが確認できます。[キャンセル] ボタンでキャンセルします。
    w10tp-09.png
  10. [OK] ボタンを押して、[システムのプロパティ] ダイアログを閉じます。
    w10tp-10.png

■クライアント Hyper-V の設定

Windows 8.1 Pro のクライアント Hyper-V を使用できるように設定します。

なお、PC によっては、BIOS レベルで仮想化技術が無効化されている場合があります。

その場合は、BIOS を起動し、仮想化技術を有効にしてから、以下の手順を実施します。

BIOS で仮想化技術を有効化する方法は、”bios cpu configuration virtualization technology” などをキーワードにして検索すると、情報を見つけることができます。

  1. [スタートボタン] 右クリックなどで [コントロール パネル] を開きます。
    w10tp-11.png
  2. [プログラム] をクリックします。
    w10tp-12.png
  3. [Windows の機能の有効化または無効化] をクリックします。
    w10tp-13.png
  4. [Windows の機能] ダイアログで、[Hyper-V] の設定にすべてチェックを入れ、[OK] を押します。
    w10tp-14.png

なお、[Hyper-V] のチェックボックスがグレーアウトしている場合は、BIOS の設定で仮想化を有効にする必要があります。

■Hyper-V マネージャーの起動

Hyper-V の機能を有効化したら、クライアント Hyper-V を使用できるようになります。

Hyper-V マネージャーを使用します。

  1. チャーム バーから [検索] を選択します。
    w10tp-15.png
  2. [Hyper-V マネージャー] を検索して起動します。
    w10tp-16.png
  3. [Hyper-V マネージャー] が起動します。
    [コンソール ツリー] の仮想化サーバーにローカル コンピューターが追加されていることを確認します。
    w10tp-17.png

[Hyper-V マネージャー] は今後多用するので、タスク バーにピン留めしておくと便利です。

■ネットワーク アダプターの設定の確認

Windows 10 Technical Preview を使い続けるために、インターネット接続環境を準備します。

このために、もしまだ仮想スイッチを作成していない場合は、ネットワーク アダプターを使用する仮想スイッチを作成します。

外部仮想スイッチの作成過程で、選択したネットワーク アダプターを使用していたネットワーク接続の設定が変更されることがあります(TCP/IP の IP・DNS・WINS などの静的な設定)。

この場合、環境によっては、仮想スイッチ作成後にネットワークが繋がらなくなるなどの問題が発生することがあります。

このような場合に備え、仮想スイッチを作成する前に、現在のネットワーク接続を確認します。

  1. [スタートボタン] 右クリックなどで [ネットワーク接続] を開きます。
    w10tp-18.png
  2. [ネットワーク接続] ウィンドウで、外部スイッチに使用する予定のネットワーク アダプターを使用しているネットワーク接続を選択し、右クリックから [プロパティ] をクリックします。
    w10tp-19.png
  3. 指定したネットワーク接続のプロパティ ダイアログが開きます。この接続でチェックされている項目と、[インターネット プロトコル バージョン 6(TCP/IPv6)] のプロパティの内容、および [インターネット プロトコル バージョン 4(TCP/IPv4)] のプロパティの内容を確認しておきます。
    w10tp-20.png

■仮想スイッチの作成

ネットワーク接続の確認を終えたので、仮想スイッチを作成します。

  1. [Hyper-V マネージャー] の [コンソール ツリー] で仮想化サーバーを右クリックし、 [仮想スイッチ マネージャー] をクリックします。
    w10tp-21.png
  2. [仮想スイッチ マネージャー] ダイアログで、[外部] を選択し、[仮想スイッチの作成] ボタンをクリックします。
    w10tp-22.png
  3. [名前] にわかりやすい仮想スイッチの名前を、[メモ] にわかりやすいメモを入力します。
    接続の種類では [外部ネットワーク] をチェックし、適切なネットワーク アダプターを選択します。
    [管理オペレーティング システムにこのネットワーク アダプターの共有を許可する] は、環境によりますが、とりあえずチェックしておいてよいと思います。
    [適用] をクリックします。
    w10tp-23.png
  4. [ネットワークの変更を適用] ダイアログが表示されます。ネットワーク接続が一時的に切断されることがあります。ネットワーク接続の設定が変更される場合があります。[はい] をクリックします。
    w10tp-24.png
  5. 変更が適用されるのを待ちます。
    w10tp-25.png
  6. [OK] をクリックして、仮想スイッチ マネージャーを終了します。
    w10tp-26.png

■仮想マシンの作成

入手した Windows 10 Technical Preview ISO ファイルを使用して、仮想マシンを作成します。

  1. [Hyper-V マネージャー] の [コンソール ツリー] で仮想化サーバーを右クリックし、 [新規] - [仮想マシン] をクリックします。
    w10tp-27.png
  2. [仮想マシンの新規作成ウィザード] が開きます。[次へ] をクリックします。
    w10tp-28.png
  3. [名前と場所の指定] が開きます。
    [名前] では、仮想マシンの名前そのものを指定します。
    仮想マシンを、既定の場所(C:\ProgramData\Microsoft\Windows\Hyper-V\)以外に配置する(例えば、別のドライブを使用する)ときは、[仮想マシンを別の場所に格納する] にチェックを入れ、[場所] にフォルダーを指定します。
    [次へ] をクリックします。
    w10tp-29.png
  4. [世代の指定] が開きます。
    最初、試しに [第 2 世代] を選んで作ってみたら、ブートに失敗してしまいました。
    [第 1 世代] を選びます。
    [次へ] をクリックします。
    w10tp-30.png
  5. [メモリの割り当て] が開きます。
    システム要件の最低値以上の値を設定します。
    [次へ] をクリックします。
    w10tp-31.png
  6. [ネットワークの構成] が開きます。
    外部仮想スイッチを指定します。
    [次へ] をクリックします。
    w10tp-32.png
  7. [仮想ハードディスクの作成] が開きます。
    [仮想ハードディスクを作成する] をチェックします。
    [名前] と [場所] はそのまま使えます。
    [サイズ] は、システム要件の最低値以上の値を設定します。
    [次へ] をクリックします。
    w10tp-33.png
  8. [インストール オプション] が開きます。
    [ブート イメージ ファイルからオペレーティング システムをインストールする] をチェックします。
    [イメージ ファイル] で、一難最初に入手した Windows 10 Technical Preview ISO ファイルを指定します。
    [次へ] をクリックします。
    w10tp-34.png
  9. [仮想マシンの新規作成ウィザードの完了] が開きます。
    [説明] の内容を確認して [完了] をクリックします。
    w10tp-35.png
  10. 新しい仮想マシンが作成されるのを待ちます。
    w10tp-36.png
  11. ブート順を変更しておきます。
    [Hyper-V マネージャー] で、仮想マシンを右クリックし、[設定] をクリックします。
    仮想マシンの設定が開きます。
    左側のペインで [BIOS] を選択します。
    右側のペインの [スタートアップ順] で [IDE] を選択し、[上へ移動] ボタンを押し続けて、一番上にします。
    [OK] ボタンをクリックしてブート順の変更を適用します。
    w10tp-37.png

■Windows 10 Technical Preview インストール

作成した仮想マシンに対して、インストールを行います。

  1. [Hyper-V マネージャー] で、仮想マシンを右クリックし、[接続] をクリックします。
    w10tp-38.png
  2. 仮想マシンに接続されたことを確認します。
    w10tp-39.png
  3. [Hyper-V マネージャー] で、仮想マシンを右クリックし、[起動] をクリックします。
    w10tp-40.png
  4. 仮想マシンがブートに成功するのを確認します。
    w10tp-41.png
  5. [Windows Setup] が表示されます。内容を確認して [Next] ボタンを押します。
    w10tp-42.png
  6. [Install now] をクリックします。
    w10tp-43.png
  7. [License terms] が表示されます。
    内容を確認後、[I accept the license terms] をチェックし、[Next] ボタンを押します。
    w10tp-44.png
  8. [Which type of installation do you want?] で、[Custom: Install Windows only (advanced)] をクリックします。
    w10tp-45.png
  9. [Where do you want to install Windows?] で、インストールするハードディスクを指定します。
    w10tp-46.png
  10. [Installing Windows] を待ちます。
    w10tp-47.png
  11. インストールが完了すると、自動的にリブートがかかります。
    w10tp-48.png

■Windows 10 Technical Preview の設定

初回起動時に行う(と、思われる)各種の設定を行います。

  1. リブートの完了を待ちます。
  2. [Settings] が表示されます。[Use express settings] をクリックします。
    w10tp-49.png
  3. [Sign in to your Microsoft account] が表示されます。
    Microsoft アカウントの ID とパスワードを入力して [Next] をクリックします。
    この手続きはスキップできないようなので、外部インターネットに疎通していないと、ここで止まるかもしれません。
    w10tp-50.png
  4. [Help us protect your info] が表示されます。
    Windows 10 Technical Preview 起動の流れの中に、Microsoft からメールで送信されるコードを入力するコード検証があります。
    ここでは、そのコードが記載されたメールを受け取るためのメールアドレスを入力し、[Next] をクリックします。
    w10tp-51.png
  5. [Enter the code you received] が表示されます。
    直前に入力したメールアドレスが正しければ、すぐにコードがメールで送信されてきます。
    ここでは、そのコードを入力し、[Next] をクリックします。
    w10tp-52.png
  6. [How should we set up your PC?] が表示されます。
    設定や Windows ストア アプリを既存の PC からコピーするか、それとも新規に構築するかを尋ねています。
    どれかを選んで [Next] をクリックします。
    w10tp-53.png
  7. 一連の起動が始まります。
    起動の間、何度かメッセージが変わります。
    w10tp-54.png
  8. 起動しました。
    w10tp-56.png

おつかれさまでした。

追って Windows 10 Technical Preview の使用感なども記事にしようと思います。


[Tips] IE10 で td に colspan や rowspan を使うとボーダーが表示されない問題 - The issue of invisible borders using colspan or rowspan to td in IE10 [Internet Explorer]

Internet Explorer 10 固有の問題です(追記:このエントリーを書いた時点の最新の IE は IE11 です)

It is a problem peculiar to Internet Explorer 10 (postscript: the latest IE when I wrote this entry is IE11). 

table 内の td タグで colspan や rowspan を使った場合、他の IE やブラウザーではきちんとボーダーが表示されるのに、IE10 でのみボーダーが期待通りに表示されないことがあります。

When you use colspan attr or rowspan attr in td tag, some borders may not be displayed as expected only in IE10, against the other IE versions.

開発者ツールを使って原因を調べようとすると、マウス オーバーした途端に再描画が走ってちゃんとボーダーが表示されたりするので、イラッとします。

If you use the F12 Developper Tool to check the cause of this issue, you will become nervous because the trouble does not happen as expected; the borders will be drawn as usual by unexpected being redrawn.

こういうシチュエーションで発生します。

It occurs in following situations.

<style type="text/css">
table {
    border-collapse: collapse;
}
td {
    border: 1px solid black;
}
</style>
<table>
    <tr>
        <td id="td1">・・・</td>
        <td id="td2">・・・</td>
        <td id="td3">・・・</td>
    </tr>
    <tr>
        <td id="td4" colspan="3">・・・</td>
    </tr>
</table>

このようなマークアップだと、よく上段の td2 と td3 の下のボーダーが表示されなくなります。

In such above markup, a border under td2 and also a border under td3 are not displayed.

また、同じ css を使うとして、以下のような場合でも発生します。 

In addition, same trouble occurs by the following markup too .

<table>
    <tr>
        <td id="td5" rowspan="3">・・・</td>
        <td id="td6">・・・</td>
    </tr>
    <tr>
        <td id="td7">・・・</td>
    </tr>
    <tr>
        <td id="td8">・・・</td>
    </tr>
</table>

このようなマークアップだと、よく右側の td7 の左のボーダーが表示されなくなります。

In such a markup, the left-side border of right td7 is not displayed.

対処法は地味ですが簡単で、大きいほうの td の(表示されない)ボーダーを描画しないようにします。 

The actions to be taken are time-consuming, but simple and  easy. You do not draw the border of the larger td.

<table>
    <tr>
        <td id="td1">・・・</td>
        <td id="td2">・・・</td>
        <td id="td3">・・・</td>
    </tr>
    <tr>
        <td id="td4" colspan="3" style="border-top: none;">・・・</td>
    </tr>
</table>
<table>
    <tr>
        <td id="td5" rowspan="3" style="border-right: none;">・・・</td>
        <td id="td6">・・・</td>
    </tr>
    <tr>
        <td id="td7">・・・</td>
    </tr>
    <tr>
        <td id="td8">・・・</td>
    </tr>
</table>

面倒ですが、他のブラウザーでの見た目も違和感がない状態で対応できます。

It is a troublesome method, but a problem does not occur by all browsers.


[Note] 来ちゃったね、iOS8 - The iOS8 came. [iOS]

来ちゃったね、iOS8。

The iOS8 came.

まだ更新はしてませんが、いろいろ問題があるみたいですね。

I've already heard several troubles about new iOS, so I've not update it yet.

また仕事で大量に最新 iOS 対応案件が降ってくるのかな。

Does the iOS8 make many jobs on me again?

やりがいがありそうです。

I'm excited with expectation.

そういう仕事が来たら、また問題と解決方法を模索して、記事にしたいと思います。

If such a work comes, I grope for the issues and  solutions again and want to write an article about it.


タグ:IOS

[Note] jQuery を困らせる製品 - A certain product against the jQuery [jQuery]

突然ですが、jQuery セレクターといえども、指定されたセレクターを解決できずに、降参することがあるよ、という話です。

I'm sure that there are some cases that the jQuery selector can't work as usual and should throw something exceptions, because jQuery doesn't support some strange usages.

自分が経験したのは、ASP.NET Web フォーム用の、某サードパーティ製コントロール コンポーネントの場合。

I experienced one of the situation when I used the control component product by the certain third party, for the ASP.NET Web Form.

なかなかよさそうなコンポーネントで、次にリリースするシステムに採用しました。

When I saw the demonstration, I felt good about the product, and I decided to adopt the product in my next Web App project.

一応、ユーザー要求として、エラーが発生したコントロールの外観を目立つようにしてほしい、ということで。

On the other hand, the system users required me to change the appearances of the error controls to attract attention.

jQuery を使って、定型的な実装を組み込みました。

Using jQuery, I incorporated typical implementation.

Page_Validators の中で IsValid が false の Validator の controltovalidate の色を変えるってやつです。

The process I implemented looked for the error controls with watching the IsValid property of Validators in Page_Validators, and set the appearance of the element specified by the controltovalidate property of the Validator as the id.

ところが、特定のコントロールでエラーを発生させると、外観変更部の jQuery セレクターが例外をスローするんです。

But, when the particular control's error occurred, the jQuery selector in above process threw the exception.

ちょっと調べてみたら、マークアップで ControlToValidate 属性に設定したコントロールのクライアント ID と、クライアントの controltovalidate プロパティの内容が違っていて。

After some my trace, I found  there was a difference between the "ControlToValidate" attribute in aspx markup for Validator Control and the "controltovalidate" property in the Client Validator Control.

controltovalidate には、たぶん内部の編集用エレメントの id なんでしょうが、知らない文字列が設定されている。

I didn't know the content of the "controltovalidate"; I thought it should be the client id of the something inner editable element among the component control.

その文字列の中に、文字としてコロン(:)があったりして。

And I found some colons (:) as the letter of the client id string.

jQuery セレクターに渡す文字列の中のコロンはフィルターのプレフィックスですから、id 文字列の中にコロンが含まれるのはまずいですよね。

I knew jQuery selector parses colon as the prefix for the filters, so I understood it was bad situation for jQuery.

こういう状態のエレメントを id から抽出しようとすると、jQuery セレクターはお手上げです。

When the jQuery selector was called with such above id, it should throw an exception.

他の文字ならまだしも、よりによってコロンを使わなくてもいいでしょうに。

I accept the secret tricks, but using colon as a letter of the id string of elements is bad.

なお、そういう id を持つエレメントでも、Native JavaScript の getElementById とかだと、ちゃんと取得してくれます。

In addition, the Native JavaScript getElementById method accepts even the elements having such id.

今回のケースでは、空の jQuery セレクターに対して、controltovalidate プロパティで特定されるエレメントを getElementById で取得して追加していくという方法を取りました。

With this case, I took the method that I got the element identified by controltovalidate property with getElementById method and added it into empty jQuery selector.

まあ…サードパーティ製コンポーネントも、いろいろ拡張機能を提供してくれるのはうれしいんですが。

I am glad that the component made in a third party provides various extensions, but ...

ここだけの話、こっそりつまんねー小細工すんなよ ... と思いました。

However, I never want bad secret tricks of their products.


[Tips] 元に戻らない TimeSpan - TimeSpan which is not deserialized [.NET Framework]

.NET Framework です。

About NET Framework.

JavaScriptSerializer の Serialize・Deserialize で、TimeSpan が元に戻らなかったという話題です。

TimeSpan was not deserialized with JavaScriptSerializer as expected.

ASP.NET Web アプリケーションで使用するためのライブラリの単体テストを作っていたところ、不本意な失敗が起こるのに気がつきました。

I was creating the library and simple test for an ASPNET Web application, and found an unexpected failure happened.

どうやら、TimeSpan 型のプロパティをメンバーに持つクラスを、 JsonSerializer を使って、Serialize → Deserialize と処理すると、TimeSpan が元に戻らないようなのです。

TimeSpan, a member of a certain class, was not deserialised as expected.

調べてみたところ、シリアライズ前の TimeSpan と、シリアライズ後の JSON の内容は期待通りでした。

I was sure that contents were as expected in TimeSpan before Serializing and JSON after Serializing.

しかし、JSON からデシリアライズ後に作成された TimeSpan 構造体インスタンスに、JSON の内容が反映されていませんでした(Ticks = 0)。

However, I found that contents of TimeSpan after Deserializing were not reflected from JSON(Ticks = 0).

そこで、最小構成の単体テストを作ってみました。

Therefore I created a simple test of the smallest construction.

    // ランダムな Ticks で TimeSpan を作成
    TimeSpan tsBefore = new TimeSpan(ticks);
    JavaScriptSerializer serializer = new JavaScriptSerializer();
    string json = serializer.Serialize(tsBefore);
    TimeSpan tsAfter = serializer.Deserialize<TimeSpan>(json);
    Console.WriteLine("JSON:[{0}]", json);
    Console.WriteLine("シリアライズ以前の TimeSpan:[{0}]", tsBefore); // 例: [9776666.12:30:35.4369536]
    Console.WriteLine("デシリアライズ後の TimeSpan:[{0}]", tsAfter);  // 例: [00:00:00]
    Assert.AreNotEqual(tsBefore, tsAfter);
    Assert.IsTrue(tsAfter.Ticks == 0);

以下は出力結果です。

The output results are as follows.

JSON:[{"Ticks":4134101591365946880,"Days":4784839,"Hours":19,"Milliseconds":594,"Minutes":18,"Seconds":56,"TotalDays":4784839.804821698,"TotalHours":114836155.31572074,"TotalMilliseconds":413410159136594.69,"TotalMinutes":6890169318.9432449,"TotalSeconds":413410159136.59467}]
シリアライズ以前の TimeSpan:[4784839.19:18:56.5946880]
デシリアライズ後の TimeSpan:[00:00:00]

ダメか・・・。

Bad ...

で、TimeSpan を調べていて、いまさら気づいたんですが。

Well, I searched about TimeSpan more and noticed at the time.

TimeSpan は、ISerializable インターフェイスを実装してないんですね・・・。

TimeSpan had not implemented ISerializable interface ...

しかし JSON 変換は ISerializable ではなく、JavaScriptConverter 型コンバーターを使用したコンバートのはず。

But, JSON conversion should use the JavaScriptConverter type converter, not ISerializable.

また、個別のカスタム型コンバーターを実装する方法も記憶にありました。

In addition, I remembered that the JSON conversion could use the individual custom type converter.

そこで実験、TimeSpan 用のカスタム型コンバーターを作ります。

Therefore I created a custom type converter for TimeSpan.

// TimeSpan 用カスタム型コンバーター
public class CustomTimeSpanConverter : JavaScriptConverter
{
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new ReadOnlyCollection<Type>(new List<Type>(new Type[] { typeof(TimeSpan) })); }
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        TimeSpan ts = (TimeSpan)obj;
        Dictionary<string, object> result = new Dictionary<string, object>();
        result["Ticks"] = ts.Ticks;
        return result;
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        if (dictionary == null)
            throw new ArgumentNullException("dictionary");
        if (type == typeof(TimeSpan))
        {
            long ticks = Convert.ToInt64(dictionary["Ticks"]);
            TimeSpan ts = new TimeSpan(ticks);
            return ts;
        }
        return TimeSpan.MinValue;
    }
}

テスト内の変換部で、JavaScriptSerializer クラス インスタンスに、先ほど作った TimeSpan 構造体用カスタム型コンバーターを登録します。

In a conversion code in the test, I registered the custom type converter with JavaScriptSerializer class instance.

    // ランダムな Ticks で TimeSpan を作成
    TimeSpan tsBefore = new TimeSpan(ticks);
    JavaScriptSerializer serializer = new JavaScriptSerializer();
    serializer.RegisterConverters(new JavaScriptConverter[] {
        new CustomTimeSpanConverter()
    });  // カスタム型コンバーター
    string json = serializer.Serialize(tsBefore);
    TimeSpan tsAfter = serializer.Deserialize<TimeSpan>(json);
    Console.WriteLine("JSON:[{0}]", json);
    Console.WriteLine("シリアライズ以前の TimeSpan:[{0}]", tsBefore); // 例: [9776666.12:30:35.4369536]
    Console.WriteLine("デシリアライズ後の TimeSpan:[{0}]", tsAfter);  // 例: [9776666.12:30:35.4369536]
    Assert.AreEqual(tsBefore, tsAfter); // 成功

出力結果です。

The output results are as follows.

JSON:[{"Ticks":4134101591365946880}]
シリアライズ以前の TimeSpan:[4784839.19:18:56.5946880]
デシリアライズ後の TimeSpan:[4784839.19:18:56.5946880]

期待通りになりました。

It became as good as expected.

しかし、最初にテストで失敗したときは、あるクラス内のメンバーとして TimeSpan を使っています。

However, I used TimeSpan as a certain intraclass member when I failed on a test first.

このような状況に対しても、上記の TimeSpan カスタム型コンバーターを登録するだけで対応できるかどうか確認しておきます。

So I had to confirm that the custom conversion could convert a interclass TimeSpan as expected.

まず、TimeSpan 構造体をメンバーとして使用するクラスを作成します。

At first I created a class using TimeSpan structure as a member.

public class TimeSpanContainer
{
    public TimeSpan InnerTimeSpan { get; set; }
}

このクラスを使用して、シリアライズ前とデシリアライズ後のインスタンスを比較します。

With this class, I compared the instance after deserializing with the instance before serializing.

    // ランダムな Ticks で TimeSpan を作成
    TimeSpan tsBefore = new TimeSpan(ticks);
    TimeSpanContainer tscBefore = new TimeSpanContainer();
    tscBefore.InnerTimeSpan = tsBefore;
    JavaScriptSerializer serializer = new JavaScriptSerializer();
    serializer.RegisterConverters(new JavaScriptConverter[] {
        new CustomTimeSpanConverter()
    });  // カスタム コンバーター
    string json = serializer.Serialize(tscBefore);
    TimeSpanContainer tscAfter = serializer.Deserialize<TimeSpanContainer>(json);
    TimeSpan tsAfter = tscAfter.InnerTimeSpan;
    Console.WriteLine("JSON:[{0}]", json);
    Console.WriteLine("シリアライズ以前の TimeSpan:[{0}]", tsBefore); // 例: [9776666.12:30:35.4369536]
    Console.WriteLine("デシリアライズ後の TimeSpan:[{0}]", tsAfter);  // 例: [9776666.12:30:35.4369536]
    Assert.AreEqual(tsBefore, tsAfter); // 成功

出力結果です。

The output results are as follows.

JSON:[{"InnerTimeSpan":{"Ticks":2785614643002932224}}]
シリアライズ以前の TimeSpan:[3224091.00:31:40.2932224]
デシリアライズ後の TimeSpan:[3224091.00:31:40.2932224]

・・・無事に一件落着しそうです。

... This issue seems to be settled in the safety.

よかった、よかった。

Was good.


[Note] スクリプトに繊細な IE - IE is delicate to a script [Internet Explorer]

IE の JavaScript エンジンが、連想配列の最後の要素の後のコンマでエラーになることは有名ですが。

It is famous that the script engine of the IE disallow the comma (,) after the last element of an associative array.

今回は、違うパターンでハマった話です。

This article is about a trouble in another pattern.

つい先日、はじめて ASP.NET AJAX 対応の ユーザー コントロールを作りました。

A few days ago, I created an user control of ASP.NET that supported ASP.NET AJAX client framework, for the first time.

そこで、どうにも納得できない状態になりました。

And I faced the trouble that I couldn't understand.

aspx マークアップ内のスクリプト ブロックに書いた特定のスクリプトが反応しないんです。

The specified script in the script block of an aspx markup did not work.

Visual Studio デバッグ実行のときは問題なく動いていたのに、デプロイしたら動かないんです。

It had worked in the Visual Studio debug running, but it did not work after deploying.

せめて IE がエラーを出してくれれば問題を見つけやすいのですが、なにも言ってくれない。

I was sure that I could find the problem faster if IE told me something about the error, but the IE told me nothing.

さんざん調べてみたんですが、決定的な原因は見つからず。

I looked for the decisive cause of the trouble badly, but I couldn't.

でも、何行か文末にセミコロン(;)がない行が見つかって、気持ち悪いから直してみたら…。

By the way, I found some script lines had no semicolon (;) at the end of line, and modified it ...

動きました。

It worked.

そんな理由?

Was it caused by such a reason?

『最後のコンマ』の場合は、IE がエラーで教えてくれるから、まだ助かります。

The IE tells me about the "last comma" as an error, I'll notice it.

今回の『セミコロンの欠落』は、なにも教えてもらえなかっただけに、何時間も無駄にしました。

In this case "lost semicolon", I wasted much time because IE told me nothing.

気をつけよう。

I'll be careful in future.


[Note] 厄介な JavaScript コメント - Troublesome JavaScript comment [Internet Explorer]

ある Web システムで、IE8、IE11、iPad ではちゃんと動くんですが。 

A certain Web system worked on IE8, IE11, or iPad.

IE9 と IE10 だけ動きませんでした。 

But it didn't work on IE9, or IE10.

なんで? なにが起きた? どういうコードになってるの? 

Why? What's happened? How was it coded?

例外をキャッチして分析してみたら、JavaScript ファイルの中に、以下のような一連のコメントがありました。 

I caught the exception, and analyzed it, then I found that there are a series of comments in a javascript file as following;

/*@cc_on
var doc = document;
eval('var document = doc');
@*/

この一連のコメントはよく知られたテクニックで、スクリプトの高速化のために使われます。 

These a series of comments are well known technique, they are used for the speedup of the script.

IE8 では、これらのコメントは JScript の @cc_on ステートを以ってスクリプトに解釈され、そのコードが window.document オブジェクトの再定義を行います。 

On IE8, the series of comments is parsed to script with "@cc_on" statement of the "JScript", and the parsed codes redefine the window.document object with "eval" function.

これでスクリプトが高速になるんです。 

It makes the script faster.

しかし、IE9 と IE10 では、この一連のコメントは IE8 同様にスクリプトに解釈されますが、window.document オブジェクトを再定義しようとした時点で例外がスローされます。

However, On IE9 or IE10, the series of comments is parsed to script with "@cc_on" statement same as IE8, but the exception is thrown when the window.document object is redefined.

IE9 と IE10 では、window.document オブジェクトは const として定義されているので、再定義できないんです。

On IE9 and IE10, the window.document object has been defined as "const", it's impossible to be redefined.

IE11 の場合、これらのコメント自体が解釈されません。IE11 が @cc_on をサポートしていないためです。 

On IE11, the series of comments is NOT parsed, because IE11 does NOT support the "@cc_on" statement.

なので、 window.document オブジェクトの再定義は実行されません。

Then, redefining of the window.document object never be done.

iPad の場合、Microsoft の製品ではないので、JScript も "@cc_on" もわかりません。 

On iPad, Safari Mobile knows neither JScript nor "@cc_on", because it is not Microsoft's products.

これがすべてです。 

That's the reason at all.

このテクニックはおもしろいし、特定の局面ではふさわしい解決方法になりえると確信しますが。 

I think that this technique is interesting, and I'm sure that it can become a good solution in the special situation.

でも、もしこう独特のテクニックを使う場合は、 使う側の責務として、動作要件に最大限の注意を払うべきと思います。

But, when we use an odd technique such as this, we must pay the greatest attention to operating requirements.

ちなみにこのコード、あってもなくても変わりませんでした。 

By the way, with or without this technique, the script execution speed did not change with IE8.

そもそもいらねーじゃんというお話です。 

It was unnecessary implementation, in the first place.


[Note] iPad で $.ajax の失敗 - Failure of $.ajax in iPad [iOS]

jQuery の $.ajax を使っている Web システムで、iPad だと特定の操作で特定のエラーメッセージが出現することが発覚しました。

I found that the Web system which used $.ajax of jQuery output specific error message by specific operation.

メッセージ文字列から追跡したところ、$.ajax を自作の JavaScript オブジェクトで隠ぺいし、エラーハンドラー内で決められた文字列を alert するようハード コーディングされていたため、この隠ぺいされた独自の Ajax が失敗すると、冒頭の特定のエラーメッセージが出ていたことがわかりました。

I traced the problem by the message string, then I found the concealed someone's own making code including $.ajax, and the code had a hardcoded error handler with "alert", so if the $.ajax failed the error handler output above specific error message.

また、ユーザーが値を入力できるほとんどのエレメントでフォーカス アウト系イベントをトラップし、無条件でこの独自の Ajax を実行していました。

And, most editable elements' focus out events were trapped to call the concealed own Ajax process unconditionally.

この時点で、こういう作り自体がナンセンスなんだけど。

I was sure that such a process is nothing but nonsense.

では、なぜ特定の操作で必ず $.ajax がエラーとなるのか。

Then, why did this system fail invariably with $.ajax by specific operation?

追調査した結果、$.ajax のリクエスト処理中にページのアンロードがかかると、xmlHttpRequest が status = 0 で失敗していました。

With more trace, if page unload occurred in the period of the $.ajax, the $.ajax failed with xmlHttpRequest status = 0.

ページのアンロードを誘発する遷移に関する操作が、この現象のトリガーでした。

Operation about the page transition to cause the page unload was the trigger of this problem.

ネットで調べてみたところ、ページのアンロード時に status = 0 になる現象は、特定のブラウザーと jQuery のバージョンの組み合わせで起きるようです(2.0.0 以降では起きないとか???)。

According to articles in the net, the problem that the $.ajax is fail with status = 0 at the time of page unload will be happened by the specific combination of the browser and the jQuery version(this problem fixed with 2.0.0?).

手元の環境では、iOS 6.x および iOS 7.0.x と、jQuery 1.8.2 の組み合わせで問題が起きていました。

In my case, the problem occurred by a combination of jQuery 1.8.2 and iOS 6.x or iOS 7.0.x.

とはいえ、以前記事にした通り、iPad では beforeunload を捕まえられないし、代わりのイベントの pagehide も発生条件が一定でないので、$.ajax を中断するにもキッカケがありません。

But, as I took an article the other day, iPad Safari Mobile doesn't fire beforeunload event, and the outbreak condition of pagehide event is not constant, so there is no opportunity to abort $.ajax.

本件のケースでは納期が迫っていたため、エラーメッセージの出力を抑制するフラグを仕込んで逃げました。

In this case, there was no enough time by the deadline, I evaded this problem by creating the flag which controlled the output of the error message.

ライブラリにはバグがあると思えということと、内部処理とプレゼンテーション処理は分離しろ、ということですね。

A library has a bug, and the processes should be separated in internal and presentation. 


【Note】iPad の pagehide の厄介ごと - awkward "pagehide" in iPad [iOS]

今回は、試しに英語の文章も併記します。間違えていたらごめんなさい、教えてください。

I write contents by English jointly for trial in this time. If I'm wrong, please tell me by comment.

IPad Safari Mobile でページのアンロードを扱う方法については、以前記事にしました。

The other day I wrote an article about how to handle the "page unload" in "iPad Safari Mobile".

ページのアンロードを処理のトリガーにする Web システムを iPad に対応させたい場合は、pagehide イベントしか使えません。

Only "pagehide" event is usable to start some kind of processing in "page unload" in iPad.

しかしこの pagehide、iOS のバージョンによって発生条件が違ったりします。

However, outbreak condition of "pagehide" depends on iOS version.

例えば、複数のタブがあり、タブ A がアクティブでタブ B が非アクティブだとします。

Please imagine, there are 2 tabs, tab A is active and tab B is not.

ユーザーがタブ B を見ようとして、タブ B をタッチした瞬間に…

Then a user touches tab B to watch it, and an active tab is changed; ...

  • iOS 6 ではタブ A の pagehide が発生しません。
  • iOS 7 ではタブ A の pagehide が発生します。
  • "pagehide" of tab A does NOT occur in iOS 6.
  • "pagehide" of tab A occurs in iOS 7.

・・・なんてことに(あれ? 逆だったかな?)。

... awkward(It may be reverse ?)

他のイベントでも、バージョンや環境に依存して挙動が違うものがあるのかもしれませんが。

Similarly, there may be the event that a condition changes under the influence of a version or environment.

ページのアンロード系を処理のトリガーにするのは、やっぱり最初の考え方が間違っているんじゃないかなあ。

I think that it is wrong to start some kind of processing in "page unload".

前の10件 | -

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。