2013-03-19 3 views
3

Итак, у меня есть несколько общих действий, которые в настоящее время ссылаются на различные виды. Страница макета содержит вызов adfs для заполнения зарегистрированного имени пользователя, которое должно быть для каждой страницы. Похоже, это:Тот же код для каждого mvc actionresult в домашнем контроллере

  <div class="float-right"> 
       <section id="login"> 
        Hello, <span class="username">@ViewBag.GivenName @ViewBag.LastName</span>! 
       </section> 
      </div> 

В главном контроллере, что делает этот вход во имя работы этот код здесь:

public ActionResult Index() 
    { 
     ClaimsIdentity claimsIdentity = Thread.CurrentPrincipal.Identity as ClaimsIdentity; 
     Claim claimGivenName = claimsIdentity.FindFirst("http://sts.msft.net/user/FirstName"); 
     Claim claimLastName = claimsIdentity.FindFirst("http://sts.msft.net/user/LastName"); 

     if (claimGivenName == null || claimLastName == null) 
     { 
      ViewBag.GivenName = "#FAIL"; 
     } 
     else 
     { 
      ViewBag.GivenName = claimGivenName.Value; 
      ViewBag.LastName = claimLastName.Value; 
     } 


     return View(); 
    } 

Но, как упоминалось ранее, мне это нужно, чтобы отобразить, когда пользователь переходит к каждая ссылка (actionresult). Поэтому мне нужно отправить весь код выше в каждый actionresult, чтобы достичь этого.

Есть ли способ, которым это может быть применимо к каждому действию в целом, а не к дублированию кода от одного действия к другому? Я попробовал только зарегистрироваться в actionresult для моего _Layout.cshtml и сделать вызов этого частичного просмотра, но это не принесло мне благоприятных результатов. Я уверен, что это что-то простое, что мне не хватает.

Надеясь, что некоторые из вас могут помочь. Большое спасибо.

+0

@Mark ... есть каждый ActionResult в то же Класс контроллера? – MikeTWebb

+0

Все это в одном классе контроллера. Пока что. Может пересмотреть позже. Есть ли другой ответ для обоих способов? – Mark

+0

@Mark Да, если все ваши действия находятся в одном контроллере, просто переопределите метод OnActionExecuting этого контроллера. В противном случае вам необходимо рассмотреть базовые контроллеры или атрибуты. –

ответ

0

Вы можете создать базовый контроллер и наследовать от него все контроллеры. Переместите код, который задает указанные и последние имена в отдельный защищенный метод и вызовет его, когда вам нужно. Я думаю, вы могли бы вызвать функцию в методе Initialize базового контроллера. Таким образом, вам не нужно будет вызывать его непосредственно в действиях. Вы также можете создать иерархию моделей и иметь GivenName и LastName как свойства на базовой модели, вместо того, чтобы работать с ViewBag.

+0

Вышеуказанное не будет работать, потому что это вызвано через ADFS, и нет модели, для которой можно извлечь эти данные. Не перейдя с базовым контроллером, какие другие варианты? – Mark

+0

Я думал создать и заполнить вашу модель данными, которые вы уже получили из 'ADFS', но это не относится к делу. Как отметил Джесси Уэбб, вы можете выполнить код в методе «OnActionExecuting» в своем собственном контроллере, и это не потребует наследования базового контроллера. –

1

Мы используем абстрактный контроллер и переопределяем его метод OnActionExecuting для выполнения кода до вызова действительного метода. С помощью этого абстрактного контроллера все, что вам нужно сделать, это заставить другие контроллеры наследовать от него, чтобы получить его функциональность. Мы также используем этот базовый контроллер как место для определения других вспомогательных методов, которые могут использовать другие контроллеры, которые его расширяют, например GetUsernameForAuthenticatedUser().

public abstract class AbstractAuthenticationController : Controller 
{ 
    private readonly IAuthenticationService _authService; 

    protected AbstractAuthenticationController() 
    { 
     _authService = AuthenticationServiceFactory.Create(); 
    } 

    protected override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     base.OnActionExecuting(filterContext); 

     EnsureUserIsAuthenticated(); 
    } 

    internal void EnsureUserIsAuthenticated() 
    { 
     if (!_authService.IsUserAuthenticated()) 
     { 
      _authService.Login(); 
     } 
    } 

    protected string GetUsernameForAuthenticatedUser() 
    { 
     var identityName = System.Web.HttpContext.Current.User.Identity.Name; 
     var username = _authService.GetUsername(identityName); 
     if (username == null) throw new UsernameNotFoundException("No Username for " + identityName); 
     return username; 
    } 
} 

Эта функция также может быть реализована в Attribute класса, который позволяет украсить ваши контроллеры, в отличие от использования наследования, но конечный результат будет таким же. Here is an example of a custom controller attribute implementation.

+0

Итак, я мог бы просто добавить код, который мне нужен, в собственный файл .cs, а затем ссылку в моем домашнем контроллере как открытый класс HomeController: HelperController, и он автоматически возьмет код и использует его в этом контроллере?Таким образом, в каждом actionresult я бы не нуждался в коде, отмеченном выше, поскольку он был бы в том классе, от которого я наследую? – Mark

+0

@Mark Да, это правильно. Кроме того, если вы хотите прекратить использование 'ViewBag', это решение позволит вам определить свойства/методы для' GivenName' и 'LastName', которые вы могли бы использовать при заполнении' ViewModel' для вашего представления. Единственная причина, по которой этот подход лучше, чем использование «ViewBag», заключается в том, что тогда ваши значения могут быть строго типизированы. Обратите внимание на то, как мы предоставляем доступ дочерним контроллерам к пользовательскому имени пользователя ... поэтому мы можем поместить его в «ViewModel». –

0

Другой альтернативой использованию OnActionExecuting как это только для набора часть шаблона будет дать ему свой собственный метод действия, который возвращает частичное и вызвать @Html.Action()