Как выставить глобальный объект, например @User, в виде бритвы?

Как/Где я могу объявить объект, такой как @User, чтобы он мог ссылаться глобально в любом виде бритвы, используя @?

Нечто похожее на:

_LoginPartial.cshtml:

@if(Request.IsAuthenticated) {
    <text>Signed In As  <strong>@User.Identity.Name</strong> |

но вместо этого ссылайтесь на мой объект:

  @if(this && that) { <text>@MyObject.GetData</text> }

Ответы

Ответ 1

Вы можете изменить базовый тип страницы Razor на свой собственный, например:

public class UserAwareViewPage : System.Web.Mvc.WebViewPage
{
  public IPrincipal User { get { return Thread.CurrentPrincipal; } }
}

И затем измените свой файл конфигурации следующим образом:

<system.web.webPages.razor>
  <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, 
  System.Web.Mvc, Version=3.0.0.0, 
  Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
  <pages pageBaseType="Your.Namespace.UserAwareViewPage">
    <namespaces>
      <add namespace="System.Web.Mvc" />
      <add namespace="System.Web.Mvc.Ajax" />
      <add namespace="System.Web.Mvc.Html" />
      <add namespace="System.Web.Routing" />
    </namespaces>
  </pages>
</system.web.webPages.razor>

Фил Хаак имеет очень хорошее сообщение в блоге об этом здесь.

В качестве альтернативы вы можете добавить метод расширения System.Web.Mvc.WebViewPage (базовый тип для бритвенных страниц) и использовать его.

public static IPrincipal User(this System.Web.Mvc.WebViewPage page)
{
  return Thread.CurrentPrincipal;
}

Что можно использовать так:

@if(Request.IsAuthenticated) {
<text>Signed In As  <strong>@User().Identity.Name</strong>

Лично я предпочитаю первый подход, но думал, что я предоставил второй вариант для альтернативного варианта.

Ответ 2

Синтаксис @ никак не ссылается на значения, он просто указывает механизму представления, что вы начинаете блок кода на стороне сервера.

В этом нет ничего "глобального". В этом случае User является свойством в абстрактном классе System.Web.WebPages.WebPageRenderingBase, который используется механизмом просмотра при визуализации представлений как они наследуют от него.

Я предполагаю, что вы можете расширить классы WebViewPage или WebViewPage<>, чтобы добавить к ним свойства. Однако может быть лучший способ добиться того, что вы пытаетесь сделать, не изменяя их. Если вы пытаетесь передать данные в представление, не должны ли эти данные быть частью ViewModel?

В идеале вы должны предоставить все потребности View в пользовательской ViewModel, и View наследует от WebViewPage<CustomViewModel>.

В синтаксисе Razor я думаю, что вы начнете CSHTML с чем-то вроде:

@model CustomViewModel

Затем вы получите доступ к свойствам, использующим свойство Model:

@Model.SomeProperty

Ответ 3

Возможно, вы можете сделать что-то подобное в своем представлении:

@Html.ViewContext.HttpContext.User.Identity.Name

Я бы рекомендовал против этого, и добавьте эту информацию в ViewModel. Например:

public ActionResult SomeController()
{
    var model = new MyViewModel
    {
        Username = User.Identity.Name
    }
    return View(model);
}

Теперь в представлении вы можете отобразить эту информацию:

@Model.Username

Ответ 4

Или для менее навязчивого подхода, и это работает для любой страницы Razor просто по умолчанию:

@Context.User.Identity.IsAuthenticated

Конечно, вы можете настроить быстрый псевдоним переменной, если вам нравится в верхней части вашего файла Razor (_Layout или иначе):

@{
  var User = Context.User;
}

но на самом деле ненужно, если у вас нет объекта custome IPrincipal в этом случае:

@{
  var User = (MyAuthenticatedUser)Context.User;
}

и это работает, и я использую:)