Razor не видит мою закрывающую скобку

У меня возникла очень странная проблема с представлениями Razor2. Приведенный ниже код — это фактический код, на который intellisense выбрасывает красную волнистую линию, просто имена были изменены.

@model Space.ViewModels.PropertyAdminViewModel

@{
    ViewBag.Title = "Create";
    ViewBag.UmbracoTitle = "Create Property";
    Layout = "../Shared/_Layout.cshtml";

    InitView();
    AnalysePreviousState();
    SortErrorsPerStep();
    GetStepToDisplay();
}

<script src="../../Scripts/jquery-1.8.2.min.js"></script>
<script src="../../Scripts/jquery.validate.min.js"></script>
<script src="../../Scripts/jquery.validate.unobtrusive.min.js"></script>
<script src="../../Scripts/AdminScripts.js"></script>

@Html.ValidationSummary(ErrorMessage)

@using (Html.BeginForm())
{
    @Html.Hidden("CurrentStep", StepToDisplay.ToString(), new { id="CurrentStep"})
    <input id="AddressButton" type="submit" name="@Button.AddressButton.ToString()" value="Address Details" />
    <input id="DetailsButton" type="submit" name="@Button.DetailsButton.ToString()" value="Details &amp; Description" />
    <input id="MediaButton" type="submit" name="@Button.MediaButton.ToString()" value="Images &amp; Documents" />


    switch (StepToDisplay)
    {
        case Step.Address:
            Html.RenderPartial("_AddressDetailsForm", ViewData.Model.Address);
            break;
        case Step.Details:
            Html.RenderPartial("_PropertyDetailsForm", ViewData.Model);
            break;
        case Step.Media:
            Html.RenderPartial("_MediaUploadEditForm", ViewData.Model.MediaItems);
            break;
    }


    <input id="BackButton" type="submit" name="@Button.BackButton.ToString()" value="Back" />
    <input id="NextButton" type="submit" name="@Button.NextButton.ToString()" value="Next" />
    <input id="FinishButton" type="submit" name="@Button.FinishButton.ToString()" value="Finish" />

} <-- `SQUIGGLY`


@{
    private enum Button
    {
        None,
        AddressButton,
        DetailsButton,
        MediaButton,
        NextButton,
        BackButton,
        FinishButton,
        CancelButton
    }

   public enum Step
   {
       Address,
       Details,
       Media,
       UpperBound
   }

   private const Step AddressStep = Step.Address;
   private const Step DetailsStep = Step.Details;
   private const Step MediaStep = Step.Media;
   private const Step First_Step = AddressStep;
   private const Step Last_Step = MediaStep;
   private const string CurrentStep = "CurrentStep";
   private const string DisabledAttribute = "disabled='disabled'";

   private string BackButtonState = string.Empty;
   private string NextButtonState = string.Empty;
   private string ErrorMessage = "Please correct the errors and try again.";
   private Button ButtonPressed = Button.None;
   private Step PreviousStepDisplayed = AddressStep;
   private Step StepToDisplay = AddressStep;
   private ModelStateDictionary[] StepModelState = new ModelStateDictionary[(int)Step.UpperBound];

   private void InitView()
   {
       // Create a ModelState for each individual step
        for (int key = (int)First_Step; key <= (int)Last_Step; key++)
        {
            StepModelState[key] = new ModelStateDictionary();
        }
   }

   /// <summary>
   /// Check form variables from the last HTTP_POST to figure where the wizard needs to be
   /// Grab the current step string along with which button was pressed
   /// </summary>
   private void AnalysePreviousState()
   {
       if (!string.IsNullOrEmpty(Request[CurrentStep]))
       {
           PreviousStepDisplayed = (Step)Enum.Parse(typeof(Step), Request[CurrentStep], true);
       }

       if (!string.IsNullOrEmpty(Request[Button.FinishButton.ToString()]))
       {
           ButtonPressed = Button.FinishButton;
       }

       if (!string.IsNullOrEmpty(Request[Button.CancelButton.ToString()]))
       {
           ButtonPressed = Button.CancelButton;
       }

       if (!string.IsNullOrEmpty(Request[Button.NextButton.ToString()]))
       {
           ButtonPressed = Button.NextButton;
       }

       if (!string.IsNullOrEmpty(Request[Button.BackButton.ToString()]))
       {
           ButtonPressed = Button.BackButton;
       }

       if (!string.IsNullOrEmpty(Request[Button.AddressButton.ToString()]))
       {
           ButtonPressed = Button.AddressButton;
       }

       if (!string.IsNullOrEmpty(Request[Button.DetailsButton.ToString()]))
       {
           ButtonPressed = Button.DetailsButton;
       }

       if (!string.IsNullOrEmpty(Request[Button.MediaButton.ToString()]))
       {
           ButtonPressed = Button.MediaButton;
       }
   }

   /// <summary>
   /// Sort all modelstate errors into the right step
   /// </summary>
   private void SortErrorsPerStep()
   {
       foreach (KeyValuePair<string, ModelState> entry in ViewData.ModelState)
       {
           foreach (int key in Enum.GetValues(typeof(Step)))
           {
               //Compare the start of each error's key with the name of a step
               //if they match then that error belongs to that step
               if (entry.Key.StartsWith(((Step)key).ToString()))
               {
                   StepModelState[key].Add(entry);
                   break;
               }
           }
       }

       ViewData.ModelState.Clear();
   }

   /// <summary>
   /// Look at the previous step to get any errors and which button was clicked
   /// and decide which step needs to be displayed now
   /// </summary>
   private void GetStepToDisplay()
   {
       //if the user tried to jump steps or finish, display the first step that has errors
       //this ensures that the wizard is completed in the intended sequence
       if (ButtonPressed != Button.NextButton && ButtonPressed != Button.BackButton)
       {
           ErrorMessage = "There are errors in the data provided. Please correct the errors and try again.";

           for (Step key = First_Step; key <= Last_Step; key++)
           {
               if (!StepModelState[(int)key].IsValid)
               {
                   DisplayStep(key, true);
                   return;
               }
           }
       }

       //if the last step has errors and the user has not hit the back button then stay on page and show the errors
       //user can go back through steps but not forward until errors are resolved
       if (!StepModelState[(int)PreviousStepDisplayed].IsValid && ButtonPressed != Button.BackButton)
       {
           DisplayStep(PreviousStepDisplayed, true);
           return;
       }

       //Otherwise move as per user request
       Step stepToDisplay = PreviousStepDisplayed;

       switch (ButtonPressed)
       {
           case Button.BackButton:
               stepToDisplay--;
               break;
           case Button.NextButton:
               stepToDisplay++;
               break;
           case Button.AddressButton:
               stepToDisplay = AddressStep;
               break;
           case Button.DetailsButton:
               stepToDisplay = DetailsStep;
               break;
           case Button.MediaButton:
               stepToDisplay = MediaStep;
               break;  
       }

       stepToDisplay = (Step)Math.Max((int)stepToDisplay, (int)First_Step);
       stepToDisplay = (Step)Math.Min((int)stepToDisplay, (int)Last_Step);

       DisplayStep(stepToDisplay, false);
   }

   private void DisplayStep(Step stepToDisplay, bool displayErrors)
   {
       StepToDisplay = stepToDisplay;
       BackButtonState = stepToDisplay == First_Step ? DisabledAttribute : string.Empty;
       NextButtonState = stepToDisplay >= Last_Step ? DisabledAttribute : string.Empty;

       //page number

       if (displayErrors)
       {
           foreach (KeyValuePair<string, ModelState> entry in StepModelState[(int)stepToDisplay])
           {
               ViewData.ModelState.Add(entry.Key, entry.Value);
           }
       }
   }


}

Когда я наводил курсор на Viewbag, я получаю обычное всплывающее окно intellisense, а наведение курсора на Title объясняет нормальное «оценивание во время выполнения».

Кто-нибудь сталкивался с этой проблемой? Я просмотрел другие вопросы, но все они содержали опечатки в коде или настоящие ошибки. Я знаю, что это не проблема со ссылкой на сборку, иначе Intellisense не знал бы, что такое Viewbag.

ОБНОВЛЕНИЕ

Похоже, у Intellisense возникла проблема с динамическими назначениями. Обычный серверный код не сталкивается с описанной выше проблемой, тогда как что-либо вроде назначений Viewbag или указания макета в @{//code здесь} кажется неработающим. Также обратите внимание, что это происходит только в одном из моих файлов .cshtml, а остальные не затрагиваются.

ОБНОВЛЕНИЕ 2 Это результат тестирования представления. Исходный файл — это сгенерированный файл кода во временных файлах ASP.NET.

Compiler Error Message: CS1513: } expected

Source Error:

Line 259:            #line default
Line 260:            #line hidden
Line 261:WriteLiteral("\r\n");
Line 262:

И это код, относящийся к вышеуказанной ошибке в скомпилированном временном файле:

WriteLiteral(" value=\"Finish\"");

WriteLiteral(" /> \r\n");


    #line 46 "F:....Create.cshtml"

} <-- see the brace!? It's right there so why does the compiler freak out?

    #line default
    #line hidden
WriteLiteral("\r\n");            

person AutoGibbon    schedule 07.05.2013    source источник
comment
Код выполняется?   -  person Robert Harvey    schedule 07.05.2013
comment
Вы сохранили, закрыли и снова открыли файл? Иногда intellisense теряет интеллектуальную часть своего имени.   -  person Tommy    schedule 07.05.2013
comment
попробуйте хоть раз убрать фигурные скобки и сказать @ViewBag.Title = Page; и посмотрите, дает ли это все еще эту красную волнистую форму?   -  person Nirman    schedule 07.05.2013
comment
@Nirman, удаляющий фигурные скобки и просто добавляющий строки кода сервера с префиксом «@», работает так, как должен, но я бы предпочел не делать этого для фрагмента кода сервера в представлении.   -  person AutoGibbon    schedule 08.05.2013
comment
На самом деле у меня есть огромный кусок серверного кода ниже назначений viewbag, и IS не возражает против него. Только первый раздел, который вы видите выше.   -  person AutoGibbon    schedule 08.05.2013
comment
Вы уверены, что это не просто побочный эффект того факта, что Viewbag.Title должно быть ViewBag.Title?   -  person Ant P    schedule 09.05.2013
comment
@AntP просто опечатка в посте, извините. Это меня очень раздражает. Удаление файла и повторная запись с нуля тоже ничего не решили!   -  person AutoGibbon    schedule 09.05.2013
comment
@AutoGibbon Возможно, вам следует опубликовать фактический код, а не что-то очень близкое к нему, поскольку в коде в вашем сообщении нет ничего плохого.   -  person Ant P    schedule 09.05.2013


Ответы (2)


Ты нуждаешься в этом:

@switch (StepToDisplay)

Он видит скобку переключателя закрытия как близкую к вашей предыдущей. Возможно, вам даже придется заключить переключатель в блок кода бритвы @{ switch(){} }.

Кроме того, если бы вы использовали ReSharper, он выделил бы фактический блок кода, как он есть, и вы бы увидели, где, по мнению Razor, должен быть конец блока.

РЕДАКТИРОВАТЬ:

Это должно выглядеть так:

@using (Html.BeginForm())
{
    // remove the @ from before the Html on this line
    Html.Hidden("CurrentStep", StepToDisplay.ToString(), new { id="CurrentStep"})
    // This html causes razor to switch back to "html mode"
    <input id="AddressButton" type="submit" name="@Button.Step1Button.ToString()"...

    ...

    // Add an @ here, because razor is now in Html mode
    @switch (StepToDisplay)
    {
        ...
    }

    // Back in html mode again, so we need @'s
    <input id="BackButton" type="submit" name="@Button.BackButton.ToString()"...
    ...
}
person Erik Funkenbusch    schedule 09.05.2013
comment
Добавление @ перед оператором switch дает следующий результат: Unexpected "switch" keyword after "@" character. Once inside code, you do not need to prefix constructs like "switch" with "@". - person AutoGibbon; 09.05.2013
comment
@AutoGibbon - проблема в том, что он переключается обратно в режим HTML из-за html перед ним. У вас не должно быть @Html в первой строке после первой фигурной скобки. - person Erik Funkenbusch; 09.05.2013
comment
Выполнение того, что вы предлагаете, по-прежнему вызывает ошибку компиляции unexpected "switch".... Там четко указано, что это не обязательно. Кстати, размещение сгенерированного кода из временных файлов asp.net в редакторе VS2012 показывает, что сгенерированный код имеет ошибку, как показано в OP. - person AutoGibbon; 09.05.2013
comment
@AutoGibbon - тогда проблема в том, что вы не показываете. Это проблема упрощения кода. Вы пытались использовать код, который вы разместили здесь, и посмотреть, работает ли он? Это должно показать вам, что проблема не в этом коде. - person Erik Funkenbusch; 09.05.2013

Я понятия не имел, что вы не можете написать обычный код C # в представлениях Razor.

person AutoGibbon    schedule 09.05.2013
comment
Не знаю, что вы имеете в виду. Вы не можете объявлять методы или классы, потому что представление — это, по сути, метод. Это было бы похоже на попытку объявить метод или класс внутри другого метода, что недопустимо. Итак, это обычный код С#, но вы должны учитывать контекст, в котором он работает. Если вам нужны методы, вы должны изменить класс, который наследует представление, а затем сделать это в виде отдельного файла. - person Erik Funkenbusch; 09.05.2013
comment
До написания этого поста я понимал синтаксис представления Razor так, что мог написать любой серверный код, если он был объявлен в блоке @{}. Не тот случай. - person AutoGibbon; 09.05.2013
comment
Бесполезный комментарий. - person Tom Baxter; 12.06.2018