MVC4 Razor запутался в брекетах - PullRequest
10 голосов
/ 20 февраля 2012

У меня довольно простой вопрос для всех экспертов по Razor. Я пытаюсь сделать jQuery $ .ajax () для вызова URL, используя Url.Content (), чтобы преобразовать относительный к дому путь в относительный к корню путь. При этом Razor немного запутывается в том, где находится конец моего @section. Я бы предпочел иметь возможность указать встроенный URL-адрес, но когда я это сделаю, Razor считает, что конец списка параметров $ .ajax () - это конец моего @section. Я использую @section, потому что я хочу использовать макеты, чтобы разместить свой JavaScript внизу каждого файла. Почему Бритва так запуталась? Я даже пытался использовать @ (Url.Content (...)), но это тоже не работает.

Кроме того, это лучший способ решить проблему? Я использую ASP.NET MVC 4 Preview.

Это работает:

@section Scripts {
    <script type="text/javascript">        
        var getMessagesUrl = '@Url.Content("~/Logging/GetMessages")';

        $(document).ready(function () {
            $.ajax({
                url: getMessagesUrl,
                dataType: 'html',
                success: function (result) {
                    $('tbody').html(result);
                }
            });
        });
    </script>
}

Это не:

@section Scripts {
    <script type="text/javascript">        
        $(document).ready(function () {
            $.ajax({
                url: '@Url.Content("~/Logging/GetMessages")',
                dataType: 'html',
                success: function (result) {
                    $('tbody').html(result);
                }
            }); //Razor thinks this is the curly-brace that ends the section!
        });
    </script>
}

Ответы [ 5 ]

9 голосов
/ 20 февраля 2012

Это, скорее всего, связано с поведением парсера. Когда он встречает символ @, синтаксический анализатор переключается в режим кода и читает неявное выражение Url.Content("~/Logging.GetMessages") (ну, на самом деле он будет считывать до символа ', определит, что он не является допустимым символом в выражении, и отслеживать возвращаться до конца ). Именно после этого этапа анализатор немного запутывается с вашим представлением, потому что он, скорее всего, находится в режиме кода, когда встречает последний символ } и думает, что это конец диапазон кода.

Реальность такова, что вы должны быть очень осторожны при использовании javascript в бритвенном представлении с C #. Переходы к коду явные, например, @ и после {, но переходы к разметке определить немного сложнее.

Кроме бритвы, я бы рекомендовал вставить код приложения javascript во внешний файл и использовать атрибуты data- * для передачи метаинформации в код приложения, например:

<script id="messageScript" type="text/javascript"
    src="/Scripts/messages.js" 
    data-messages="@Url.Content("~/Logging/GetMessages")"></script>

К которому вы можете получить доступ как:

(function($) {

    $(function() {
        var $this = $("#messageScript");
        $.ajax({
            url: $this.attr("data-messages"),
            type: "html",
            success: function(result) {
                $("tbody").html(result);
            }
        });
    });

})(window.jQuery);
4 голосов
/ 21 февраля 2012

Обновление: Символ «меньше» Дейва не вызывал проблему, он добавил его в свой вопрос только в иллюстративных целях.

На MVC4 мне удалось выделить проблему. Это не скомпилирует:

<script type="text/javascript">
  $(document).ready(function () {
    $.ajax({
      url: '@Url.Content("~/Logging/GetMessages")',
      dataType: 'html',
      success: function (result) {
        $('tbody').html(result);
      }
    }); //<-- test
  });
</script>

Но это будет:

<script type="text/javascript">
  $(document).ready(function () {
    $.ajax({
      url: '@Url.Content("~/Logging/GetMessages")',
      dataType: 'html',
      success: function (result) {
        $('tbody').html(result);
      }
    }); //-- test
  });
</script>

Похоже, это был просто <</strong> в комментарии, который его выбросил.

1 голос
/ 01 февраля 2013

Кажется, все еще проблема с финальным MVC4 / Visual Studio 2010, но вот мое исправление:

@section jQueryDocumentReady
{
  @{
  <text>
     // All the javascript and bracers you want here
  </text>
  }
}
1 голос
/ 21 февраля 2012

Ответ Мэтью в значительной степени объясняет поведение (хотя, если честно, я не могу воспроизвести вашу проблему - и не вижу, почему она не сработает - оба ваших примера работают отлично).Для другого подхода вы можете выделить действие / представление для сгенерированных переменных javascript (URL, настроек, локализованных текстов и т. Д.), Например:

// Could/should be OutputCached depending on the scenario
public ActionResult Globals()
{
   var model = new ClientGlobalsModel();

   // ClientGlobalsModel has a single (could be more) Dictionary<string, string>
   // (Urls) and a ToJSON() method which uses JavaScriptSerializer to serialize 
   // the object:
   model.Urls.Add("GetMessages", Url.Content("~/Logging/GetMessages"));

   // I mostly use this method for e.g. actions:
   model.Urls.Add("UploadImage", Url.Action("Upload", "Image"));

   Response.ContentType = "text/javascript";

   return View(model);
}

Globals.cshtml:

@model ClientGlobalsModel
@{
    Layout = null; // If you have a layout supplied in e.g. _ViewStart
}
var GLOBALS = @Model.ToJSON()

Да, это мог бы быть простой Content() результат, а не представление - но когда у вас больше глобальных объектов (например, настройки + URL-адреса + тексты), вы можете захотеть упростить контроль над выводом скрипта и, возможно, сериализовать каждый словарь индивидуально.Может также потребоваться указать пространство имен этой переменной «GLOBALS» в некотором общем пространстве имен приложения, чтобы избежать загрязнения глобальной области.

(например) Index.cshtml:

<script src="@Url.Action("Globals", "Client")"></script>
<script src="@Url.Content("~/Scripts/main.js")"></script>

..., которая просто включаетвывод из / Client / Globals.И "main.js", в который мы теперь переместили остальную часть вашего скрипта:

main.js (статический):

$(document).ready(function () {
   $.ajax({
      url: GLOBALS.Urls.GetMessages,
      dataType: 'html',
      success: function (result) {
         $('tbody').html(result);
      }
   });
});

Вы, конечно, можете использовать то же самоетакой подход, чтобы вывести несколько пользовательских / контекстных / видовых настроек прямо в вид.Для нескольких URL или данных подход data- * может быть лучше в зависимости от ваших вкусов.Я не фанат добавления тонн того, что в основном настраивается в атрибуты на каждой странице HTML.

0 голосов
/ 25 февраля 2012

Спасибо за помощь, ребята.

Похоже, что это была ошибка в ASP.NET MVC 4 Preview. Я только что обновил бета-версию ASP.NET MVC 4, вышедшую 15 февраля, и проблема полностью исчезла.

...