7

次のコードに少し困惑しています。Windows 7 の VS2010 では問題なく動作しましたが、ハードウェアを Windows 8 と VS 2012 にアップグレードしたので、動作しません。

MVC アプリケーションに次の JavaScript コードがあります。

<script language="javascript" type="text/javascript">
var today;

if("@Model.Birthday.HasValue"){
    var today = new Date("@Model.Birthday.Value.Year", "@Model.Birthday.Value.Month" - 1, "@Model.Birthday.Value.Day");
}else{
    today = new Date();
}

モデルは、次のようなプロパティを持つ ViewModel から取得しています。

    public System.DateTime? Birthday
    {
        get { return user.Birthday; }
        set { user.Birthday = value; }
    }

例外は次の行でスローされます。

var today = new Date("@Model.Birthday.Value.Year", "@Model.Birthday.Value.Month" - 1, "@Model.Birthday.Value.Day");

「Nullableオブジェクトには値が必要です」というメッセージが返されます。これは、その行にジャンプして実行する必要があります。しかし、私の if ステートメントは false を返します。行を削除してアラート ステートメントを挿入しただけでは、Birthday プロパティが null であるため、その行は実行されず、アラートも表示されません。JS が MVC コードを実行する方法が変わったようで、if ステートメントに関係なく、コード ブロック全体を評価しているようです。私も次のことを試しましたが、役に立ちませんでした:

  • W8 の Chrome でテスト済み
  • try / catch ブロックでテストされています。興味深いことに、例外をキャッチしません (JS は .NET 例外をキャッチしないと思います)。
  • @Model.Birthday.HasValue == true を明示的に指定してテスト済み
  • @Model.Birthday.Value != null に変更してテスト済み
  • デバッグ モードではなくリリース モードでテスト済み

これは単純なはずです - 値が null かどうかをテストし、そうでない場合は .NET プロパティから JS Date オブジェクトを作成し、そうである場合は新しい JS Date オブジェクトを作成しますが、何らかの理由で評価したいHasValue が false であっても、その行を実行します。

本当に困惑しました。誰もこのようなものを見たことがありますか?

4

4 に答える 4

5

一言で言えば解決策:

コードをテストしたところ、HW/SW の更新に問題はないと言えます。私はWin 7でVS 2010を実行しています。解決策は、たとえばコードをこのように変更することです。

<script language="javascript" type="text/javascript">

            @{ // C# server side part to get the dateParameters
                var dateParameters = string.Empty;
                if (Model.Birthday.HasValue)
                {
                    dateParameters = "" + @Model.Birthday.Value.Year
                                 + ", " + (@Model.Birthday.Value.Month - 1)
                                 + ", " + @Model.Birthday.Value.Day;
                }
            }
            // JS client side, later working with just created dateParameters 
            var today = new Date(@dateParameters);
            alert(today);
    </script>

詳細な説明:

答えを見つけるには、上記のスニペットを分割してみましょう。HTMLコードをレンダリングしているだけです。順を追って見ていきましょう

I.HasValue

@Model.Birthday = new Date(2012,11,4)

1) Razor は、最初の@演算子まで、応答ストリーム文字列に送信しています。

<script language="javascript" type="text/javascript">
var today;

if("

2) ここで、Razor はこの部分 @Model.Birthday.HasValue をブール値として評価し、文字列に変換するため、コードの次の部分は次のようになります。

True

3) 次の直接文字列を追加

"){
    var today = new Date("

4) @Model.Birthday.Value.Year を評価し、その文字列値を注入します

2012

5) 6) 7) ... など、Response に送信される最終結果は次のとおりです。

<script language="javascript" type="text/javascript">
    var today;

    if ("True"){
        var today = new Date("2012", "11" - 1, "4");
    } else{
        today = new Date();
    }
</script>

Ⅱ.生年月日がNULLです

@Model.Birthday = nullの場合、最初のステップ 1)、2)、および 3) は同じです。

<script language="javascript" type="text/javascript">
    var today;

    if ("True"){
        var today = new Date("

4)例外Nullable オブジェクトには値が必要です

最後に、Nullable 例外が発生する場所があります。

@Model.Birthday.Value.Year

が呼び出される

@Model.Birthday == null

于 2012-11-04T17:33:45.680 に答える
5

ここで、正しいデータをレンダリングする能力に影響を与えるいくつかのことが起こっていることがわかります。

まず、MVC 変数がサーバー側で処理されます。@Model.Birthday.Value現在の実装では、HTML を生成するために、常に Javascript のプロパティの値をレンダリングしようとしています。これは、Razor ではなくクライアント側の Javascript に依存して条件を実行するため、現在の例でプロパティが true か false かに関係なく発生します。以下は、問題の完全な動作例です。

モデルを見る

namespace MvcApplication1.Models
{
    public class TestViewModel
    {
        public DateTime? NullDate { get; set; }

        public DateTime? DateWithValue { get; set; }
    }
}

コントローラ

public ActionResult Index()
        {
            return View(new TestViewModel{DateWithValue = DateTime.Now, 
NullDate = null});
            }

意見

@model MvcApplication1.Models.TestViewModel
@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<script type="text/javascript">
    var today;
    var anotherDay;

    @{if(Model.NullDate.HasValue)
    {
        @: alert('Null date had a value!');
        @: today = new Date('@Model.NullDate.Value.Year', parseInt('@Model.DateWithValue.Value.Month') - 1, '@Model.NullDate.Value.Day');
    }else
      {
        @: alert('Null date did not have a value');
        @: today = new Date();
    }}

    @{if (Model.DateWithValue.HasValue)
      {
        @: alert('DateWithValue had a value!');
            @: anotherDay = new Date('@Model.DateWithValue.Value.Year', parseInt('@Model.DateWithValue.Value.Month') - 1, '@Model.DateWithValue.Value.Day');
          @: alert(anotherDay);
      }
      else
      {
          @: alert('DateWithValue date did not have a value');
        @: anotherDay = new Date();
    }}
</script>

明らかに、同じコントローラー アクションで Null 値と非 Null 値の両方に対して機能することを示すために、Javascript セクションでコードが複製されています。

ビューでわかるように、モデルのチェックには Razor 構文を使用し、実際のクライアント側変数の設定には Javascript を使用していることを確認しています。また、「-1」は正常に機能していたのだろうか。この例で減算を行うには、その値を Javascript から Int にキャストする必要がありましたが、これは些細なことです。

参考までに、これは VS2012、Chrome でテストされた Windows 8 Professional の MVC 4 プロジェクトです。

于 2012-11-04T17:17:09.083 に答える
1

問題は、クライアント側のコードとサーバー側のコードを混同していることです。JavaScript はクライアント側で実行されますが、サーバー側のコードがすべて完了した後でのみ実行されます。

したがって、@Model.Birthday.HasValue、@Model.Birthday.Value.Year などはすべて、ブラウザーに近づく前にサーバー側で評価されます。null オブジェクトで Model.Birthday.Value.Year を評価しようとして、サーバー側で例外が発生しているため、javascript コード (したがって、この場合は if ステートメント) はブラウザーに到達しません。

条件付きサーバー側を移動する必要があります。

@if(Model.Birthday.HasValue){
    @:today = new Date(@(Model.Birthday.Value.Year), @(Model.Birthday.Value.Month) - 1, @(Model.Birthday.Value.Day));
} else {
    @:today = new Date();
}
于 2012-11-04T13:21:29.423 に答える