Przekaż dane do układu, które są wspólne dla wszystkich stron

125

Mam witrynę internetową, która ma układ strony. Jednak ta strona układu zawiera dane, które model wszystkich stron musi zawierać taki tytuł strony, nazwę strony i lokalizację, w której faktycznie się znajdujemy, dla pomocnika HTML, który wykonałem, który wykonał jakąś akcję. Każda strona ma również własne właściwości modeli widoku.

W jaki sposób mogę to zrobić? Wygląda na to, że wpisywanie układu jest złym pomysłem, ale jak mam przekazać te informacje?

Rushino
źródło
10
Każdy, kto czyta tutaj odpowiedzi, może odwiedzić stackoverflow.com/a/21130867/706346, gdzie zobaczysz znacznie prostsze i ładniejsze rozwiązanie niż wszystko, co tutaj opublikowano.
Avrohom Yisroel
5
@AvrohomYisroel dobra sugestia. Jednak wolę podejście @Colin Bacon, ponieważ jest silnie wpisane, a nie w formacie ViewBag. Być może kwestia preferencji. Głosował jednak za twoim komentarzem
JP Hellemons
w przypadku mvc 5 zobacz tę odpowiedź: stackoverflow.com/a/46783375/5519026
Laz Ziya

Odpowiedzi:

143

Jeśli musisz przekazać te same właściwości do każdej strony, rozsądne byłoby utworzenie podstawowego modelu widoku, który jest używany przez wszystkie modele widoku. Twoja strona układu może następnie przyjąć ten model podstawowy.

Jeśli za tymi danymi jest wymagana logika, należy je umieścić w podstawowym kontrolerze używanym przez wszystkie kontrolery.

Jest wiele rzeczy, które możesz zrobić, ale ważne podejście polega na tym, aby nie powtarzać tego samego kodu w wielu miejscach.

Edycja: aktualizacja z komentarzy poniżej

Oto prosty przykład, aby zademonstrować tę koncepcję.

Utwórz model widoku bazowego, z którego będą dziedziczyć wszystkie modele widoku.

public abstract class ViewModelBase
{
    public string Name { get; set; }
}

public class HomeViewModel : ViewModelBase
{
}

Twoja strona układu może przyjąć to jako model.

@model ViewModelBase
<!DOCTYPE html>
<html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>Test</title>
    </head>
    <body>
        <header>
            Hello @Model.Name
        </header>
        <div>
            @this.RenderBody()
        </div>
    </body>
</html>

Na koniec ustaw dane w metodzie akcji.

public class HomeController
{
    public ActionResult Index()
    {
        return this.View(new HomeViewModel { Name = "Bacon" });
    }
}
Colin Bacon
źródło
12
Ale dane są używane w układzie. Jak mogę przekazać dane do układu?
Rushino
2
Idealny! Widziałem mój błąd. Zapomniałem przekazać model do widoku .. co za kiepski błąd. Dzięki!
Rushino
7
Problem z tym podejściem polega na tym, że czasami nie każdy widok ma ViewModel, więc to nie zadziała w tym przypadku: O /
Cacho Santa
17
Ale czy nie wymagałoby to, aby każdy kontroler i każda akcja zawierały kod {Name = "Bacon"}? A gdybym chciał dodać inną właściwość do ViewModelBase, musiałbym przejść do każdego kontrolera i każdej akcji i dodać kod, aby wypełnić tę właściwość? Wspomniałeś "Jeśli jest wymagana logika [...], należy to umieścić w podstawowym kontrolerze [...]". Jak miałoby to działać, aby wyeliminować ten powtarzający się kod w każdym kontrolerze i każdej akcji?
Lee,
5
@Lee Jeśli są to wspólne dane na wszystkich stronach, należy to umieścić na podstawowym kontrolerze. Twoje kontrolery dziedziczą wtedy z tego kontrolera podstawowego. np public class HomeController : BaseController. W ten sposób wspólny kod wystarczy napisać tylko raz i można go zastosować do wszystkich kontrolerów.
Colin Bacon,
73

Użyłem pomocnika HTML RenderAction dla maszynki do golenia w układzie.

@{
   Html.RenderAction("Action", "Controller");
 }

Potrzebowałem go do prostego sznurka. Więc moja akcja zwraca łańcuch i łatwo go zapisuje. Ale jeśli potrzebujesz złożonych danych, możesz zwrócić PartialViewResult i modelować.

 public PartialViewResult Action()
    {
        var model = someList;
        return PartialView("~/Views/Shared/_maPartialView.cshtml", model);
    }

Wystarczy, że umieścisz swój model na początku utworzonego widoku częściowego „_maPartialView.cshtml”

@model List<WhatEverYourObjeIs>

Następnie możesz użyć danych w modelu w tym częściowym widoku za pomocą html.

Burk
źródło
18
To zdecydowanie najlepsza odpowiedź!
gingerbreadboy
@gingerbreadboy zgodził się, że promuje dobrą hermetyzację i oddzielenie problemów.
A-Dubb
35

Inną opcją jest utworzenie oddzielnej klasy LayoutModel ze wszystkimi właściwościami, których będziesz potrzebować w układzie, a następnie włóż wystąpienie tej klasy do ViewBag. Używam metody Controller.OnActionExecuting, aby ją wypełnić. Następnie na początku układu możesz wyciągnąć ten obiekt z powrotem z ViewBag i kontynuować dostęp do tego silnie wpisanego obiektu.

DenNukem
źródło
1
To faktycznie brzmi jak najmniej bolesne rozwiązanie, czy są jakieś wady? +1
formatc
2
Zdecydowanie najlepsze rozwiązanie i nie widzę żadnych wad.
Wiktor Zychla
7
Nie rozumiem, co ci to daje. Jeśli masz klasę ze wszystkimi właściwościami potrzebnymi do układu, po co zawracać sobie głowę dodawaniem jej do ViewBag tylko po to, aby ponownie ją przesłać? Użyj modelu w widoku układu, nadal możesz wypełnić model OnActionExecuting. Korzystanie z ViewBag oznacza również utratę bezpieczeństwa typu w kontrolerze, co nigdy nie jest dobre.
Colin Bacon,
3
Daje mi to możliwość dodania modelu do układu bez konieczności zmiany struktury wszystkich modeli w celu dziedziczenia z jednego „super” modelu we wszystkich metodach wszystkich kontrolerów w projekcie, który już istnieje. Jeśli zaczynasz od zera, możesz zamiast tego wyprowadzić wszystkie modele ze wspólnego katalogu głównego.
DenNukem
5
@ColinBacon kolejną zaletą tej opcji jest to, że Twoje akcje nie muszą zawsze mieć modeli widoku. Twierdzę również, że programiści, którzy muszą wiedzieć, że muszą zawsze dziedziczyć swoje modele widoku z bazy, jest wadą.
Josh Noe
28

Przypuszczalnie podstawowym przypadkiem użycia tego jest pobranie modelu podstawowego do widoku dla wszystkich (lub większości) akcji kontrolera.

Biorąc to pod uwagę, użyłem kombinacji kilku z tych odpowiedzi, głównie w oparciu o odpowiedź Colina Bacona.

To prawda, że ​​nadal jest to logika kontrolera, ponieważ zapełniamy model widoku, aby powrócić do widoku. Dlatego właściwym miejscem do umieszczenia tego jest kontroler.

Chcemy, aby miało to miejsce na wszystkich kontrolerach, ponieważ używamy tego na stronie układu. Używam go do częściowych widoków renderowanych na stronie układu.

Nadal chcemy również dodatkowej korzyści z silnie wpisanego ViewModel

W ten sposób utworzyłem BaseViewModel i BaseController. Wszystkie kontrolery ViewModels będą dziedziczyć odpowiednio po BaseViewModel i BaseController.

Kod:

BaseController

public class BaseController : Controller
{
    protected override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);

        var model = filterContext.Controller.ViewData.Model as BaseViewModel;

        model.AwesomeModelProperty = "Awesome Property Value";
        model.FooterModel = this.getFooterModel();
    }

    protected FooterModel getFooterModel()
    {
        FooterModel model = new FooterModel();
        model.FooterModelProperty = "OMG Becky!!! Another Awesome Property!";
    }
}

Zwróć uwagę na użycie OnActionExecuted wzięte z tego postu SO

HomeController

public class HomeController : BaseController
{
    public ActionResult Index(string id)
    {
        HomeIndexModel model = new HomeIndexModel();

        // populate HomeIndexModel ...

        return View(model);
    }
}

BaseViewModel

public class BaseViewModel
{
    public string AwesomeModelProperty { get; set; }
    public FooterModel FooterModel { get; set; }
}

HomeViewModel

public class HomeIndexModel : BaseViewModel
{

    public string FirstName { get; set; }

    // other awesome properties
}

FooterModel

public class FooterModel
{
    public string FooterModelProperty { get; set; }
}

Layout.cshtml

@model WebSite.Models.BaseViewModel
<!DOCTYPE html>
<html>
<head>
    < ... meta tags and styles and whatnot ... >
</head>
<body>
    <header>
        @{ Html.RenderPartial("_Nav", Model.FooterModel.FooterModelProperty);}
    </header>

    <main>
        <div class="container">
            @RenderBody()
        </div>

        @{ Html.RenderPartial("_AnotherPartial", Model); }
        @{ Html.RenderPartial("_Contact"); }
    </main>

    <footer>
        @{ Html.RenderPartial("_Footer", Model.FooterModel); }
    </footer>

    < ... render scripts ... >

    @RenderSection("scripts", required: false)
</body>
</html>

_Nav.cshtml

@model string
<nav>
    <ul>
        <li>
            <a href="@Model" target="_blank">Mind Blown!</a>
        </li>
    </ul>
</nav>

Mam nadzieję, że to pomoże.

drizzie
źródło
2
Użyłem tego podejścia, ale wolę dziedziczenie z interfejsu niż z klasy bazowej. Zrobiłem więc: var model = filterContext.Controller.ViewData.Model as IBaseViewModel if (model! = Null) {model.AwesomeModelProperty = "Niesamowita wartość właściwości"; }
Tom Gerken
2
świetna odpowiedź, wolałem tę od wszystkich innych.
Jynn,
1
Świetna odpowiedź, ale mam pytanie. „A co, jeśli mam widoki, które nie mają modeli ViewModels ...?”
Isma Haro,
Próbowałem tego, ale w akcji indeksu OnActionExecuted wypełnia FooterModel, a następnie tworzony jest nowy HomeIndexModel z null FooterModel :(
SteveCav
1
@drizzie: w kontrolerze podstawowym model jest zmienną lokalną w metodzie Filter: var model = filterContext.Controller.ViewData.Model as BaseViewModel. Nie rozumiem, jak MVC rozumie, że ta zmienna lokalna jest taka sama jak model, który HomeController wysyła do wyświetlenia.
Hooman Bahreini
9

Nie musisz majstrować przy akcjach ani zmieniać modelu, po prostu użyj kontrolera podstawowego i rzutuj istniejący kontroler z kontekstu widoku układu.

Utwórz podstawowy kontroler z żądanymi wspólnymi danymi (tytuł / strona / lokalizacja itp.) I inicjalizacją akcji ...

public abstract class _BaseController:Controller {
    public Int32 MyCommonValue { get; private set; }

    protected override void OnActionExecuting(ActionExecutingContext filterContext) {

        MyCommonValue = 12345;

        base.OnActionExecuting(filterContext);
    }
}

Upewnij się, że każdy kontroler używa kontrolera podstawowego ...

public class UserController:_BaseController {...

Przerzuć istniejący kontroler podstawowy z kontekstu widoku na twojej _Layout.cshmlstronie ...

@{
    var myController = (_BaseController)ViewContext.Controller;
}

Teraz możesz odwoływać się do wartości w kontrolerze podstawowym ze strony układu.

@myController.MyCommonValue

AKTUALIZACJA

Możesz także utworzyć rozszerzenie strony, które pozwoliłoby ci używać this.

//Allows typed "this.Controller()." in cshtml files
public static class MyPageExtensions {
    public static _BaseController Controller(this WebViewPage page) => Controller<_BaseController>(page);
    public static T Controller<T>(this WebViewPage page) where T : _BaseController => (T)page.ViewContext.Controller;
}

Wtedy musisz tylko pamiętać, aby używać this.Controller()kontrolera, gdy chcesz.

@{
    var myController = this.Controller(); //_BaseController
}

lub określony kontroler, który dziedziczy po _BaseController...

@{
    var myController = this.Controller<MyControllerType>();
}
Carter Medlin
źródło
Jaki jest odpowiednik tego w .net core? Ponieważ ViewContext.Controller nie jest obecny i nastąpiła pewna zmiana w łańcuchu dziedziczenia
Jayanth Thyagarajan
4

jeśli chcesz przekazać cały model, postępuj tak w układzie:

@model ViewAsModelBase
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta charset="utf-8"/>
    <link href="/img/phytech_icon.ico" rel="shortcut icon" type="image/x-icon" />
    <title>@ViewBag.Title</title>
    @RenderSection("styles", required: false)    
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
    @RenderSection("scripts", required: false)
    @RenderSection("head", required: false)
</head>
<body>
    @Html.Action("_Header","Controller", new {model = Model})
    <section id="content">
        @RenderBody()
    </section>      
    @RenderSection("footer", required: false)
</body>
</html>

i dodaj to w kontrolerze:

public ActionResult _Header(ViewAsModelBase model)
Yakir Manor
źródło
4

Nie sądzę, aby żadna z tych odpowiedzi była wystarczająco elastyczna dla dużej aplikacji na poziomie przedsiębiorstwa. Nie jestem fanem nadużywania ViewBag, ale w tym przypadku dla elastyczności zrobiłbym wyjątek. Oto, co bym zrobił ...

Powinieneś mieć podstawowy kontroler na wszystkich kontrolerach. Dodaj dane układu OnActionExecuting w kontrolerze podstawowym (lub OnActionExecuted, jeśli chcesz to odroczyć) ...

public class BaseController : Controller
{
    protected override void OnActionExecuting(ActionExecutingContext     
        filterContext)
    {
        ViewBag.LayoutViewModel = MyLayoutViewModel;
    }
}

public class HomeController : BaseController
{
    public ActionResult Index()
    {
        return View(homeModel);
    }
}

Następnie w swoim _Layout.cshtml ściągnij swój ViewModel z ViewBag ...

@{
  LayoutViewModel model = (LayoutViewModel)ViewBag.LayoutViewModel;
}

<h1>@model.Title</h1>

Lub...

<h1>@ViewBag.LayoutViewModel.Title</h1>

Nie wpływa to na kodowanie kontrolerów strony ani modeli widoków.

Jack Sutherland
źródło
Podoba mi się twój pomysł, ale co jeśli masz MyLayoutViewModeldynamicznie utworzony, jak mogę przekazać niektóre parametry do OnActionExecutingmetody?
Rajmond Burgaj
1
Uh, nadal potrzebujesz base.OnActionExecuting(filterContext)swojej OnActionExecutingmetody !!!
ErikE
4

Tworzenie widoku podstawowego, który reprezentuje model widoku Układ, jest okropnym podejściem. Wyobraź sobie, że chcesz mieć model, który reprezentuje nawigację zdefiniowaną w układzie. Zrobiłbyś to CustomersViewModel : LayoutNavigationViewModel? Czemu? Dlaczego należy przekazywać dane modelu nawigacji przez każdy model widoku znajdujący się w rozwiązaniu?

Model widoku układu powinien być dedykowany samodzielnie i nie powinien zmuszać pozostałych modeli widoku do polegania na nim.

Zamiast tego możesz to zrobić w swoim _Layout.cshtmlpliku:

@{ var model = DependencyResolver.Current.GetService<MyNamespace.LayoutViewModel>(); }

Co najważniejsze, nie musimy tego robić new LayoutViewModel()i otrzymamy wszystkie zależności, które LayoutViewModelzostały rozwiązane za nas.

na przykład

public class LayoutViewModel
{
    private readonly DataContext dataContext;
    private readonly ApplicationUserManager userManager;

    public LayoutViewModel(DataContext dataContext, ApplicationUserManager userManager)
    {
    }
}
hyankov
źródło
Gdzie wypełniasz ten model? Również w BaseController?
ndberg
Wyobrażam sobie, że byłby to dobry pomysł na Scopedobiekt modelu układu w ASP..Net Core, jak również.
James Wilkins
Nie chciałbym, żeby widok pobierał zależność. To zdecydowanie nie jest „MVC”. Service Locator to anty-wzór .
Jiveman,
Wbrew powszechnemu przekonaniu Service Locator nie jest anty-wzorcem i właściwie nie ma to nic wspólnego z MVC, czy po prostu wrzucasz modne słowa @Jiveman? blog.gauffin.org/2012/09/service-locator-is-not-an-anti-pattern
hyankov
Wydaje się, że głównym punktem Jgauffina w tym artykule jest to, że termin „anty-wzorzec” nie powinien być stosowany do Lokalizatora usług, ponieważ może istnieć przynajmniej kilka ważnych zastosowań SL. Słuszna uwaga. Jednak, jak widać w niektórych jego komentarzach do dyskusji, sugeruje on, że chociaż SL może być prawidłowym podejściem do budowania bibliotek i frameworków, niekoniecznie jest zalecane przy budowaniu aplikacji (co uważam za pytanie OP i tę dyskusję tutaj) kręci się wokół).
Jiveman
3

Inne odpowiedzi obejmowały prawie wszystko, w jaki sposób możemy przekazać model do naszej strony układu. Ale znalazłem sposób, za pomocą którego można dynamicznie przekazywać zmienne do strony układu, bez korzystania z żadnego modelu lub częściowego widoku w układzie. Powiedzmy, że masz ten model -

public class SubLocationsViewModel
{
    public string city { get; set; }
    public string state { get; set; }
}

I chcesz dynamicznie uzyskiwać miasto i stan. Np

w pliku index.cshtml możesz umieścić te dwie zmienne w ViewBag

@model  MyProject.Models.ViewModel.SubLocationsViewModel
@{
    ViewBag.City = Model.city;
    ViewBag.State = Model.state;
}

Następnie w pliku layout.cshtml możesz uzyskać dostęp do tych zmiennych widoku

<div class="text-wrap">
    <div class="heading">@ViewBag.City @ViewBag.State</div>
</div>
Chirag K
źródło
to działa świetnie, @stun_Gravy czy użycie ViewBag do przekazywania danych, takich jak rola lub poziom dostępu użytkownika, jest wadą?
3not3
3

Jest inny sposób, aby sobie z tym poradzić. Może nie jest to najczystszy sposób z architektonicznego punktu widzenia, ale pozwala uniknąć wielu problemów związanych z innymi odpowiedziami. Po prostu wstrzyknij usługę w układzie Razor, a następnie wywołaj metodę, która pobiera niezbędne dane:

@inject IService myService

Następnie w widoku układu:

@if (await myService.GetBoolValue()) {
   // Good to go...
}

Ponownie, nie jest czysty pod względem architektury (oczywiście usługa nie powinna być wstrzykiwana bezpośrednio w widoku), ale wykonuje swoje zadanie.

Andrzej
źródło
Nie najczystszy sposób? Nie zgadzam się. Myślę, że jest to tak czyste, jak to tylko możliwe: obiekt jest przekazywany z miejsca, w którym został utworzony, prosto do miejsca, w którym ma się znajdować, bez "zanieczyszczania" innych kontrolerów przedmiotami, których nie muszą widzieć. @injectMoim zdaniem najlepszym rozwiązaniem jest używanie .
dasblinkenlight
1
Myśląc o tym więcej, może masz rację. Fakt, że ta metoda pozwala uniknąć tak dużego bólu, świadczy o tym, że być może jest to najczystszy sposób. Pracowałem nad bardzo dużą aplikacją ASP.NET Core i używam tego wzorca do takich rzeczy, jak logika nawigacyjna, dane nagłówka, które znajdują się na większości stron, takie rzeczy. Zamiast tego uniknąłem tylu bólu, robiąc to w ten sposób.
Andrew
2

Możesz także skorzystać z RenderSection , który pomoże Ci wprowadzić Modeldane do _Layoutwidoku.

Możesz wstrzyknąć View Modeldane Json,Script , CSS, HTMLetc

W tym przykładzie wstrzykuję Jsonz mojegoIndex widoku do Layoutwidoku.

Index.chtml

@section commonLayoutData{

    <script>

        var products = @Html.Raw(Json.Encode(Model.ToList()));

    </script>

    }

_Layout.cshtml

@RenderSection("commonLayoutData", false)

Eliminuje to potrzebę tworzenia oddzielnej Bazy View Model.

Nadzieja pomaga komuś.

shaijut
źródło
1
Idealne rozwiązanie, gdy potrzebujesz tylko renderować coś konkretnego dla kilku widoków.
Kunal
1

to, co zrobiłem, jest bardzo proste i działa

Zadeklaruj właściwość statyczną w dowolnym kontrolerze lub możesz utworzyć klasę danych z wartościami statycznymi, jeśli chcesz w ten sposób:

public static username = "Admin";
public static UserType = "Administrator";

Wartości te mogą być aktualizowane przez kontrolery na podstawie operacji. później możesz ich użyć w swoim _Layout

W pliku _layout.cshtml

@project_name.Controllers.HomeController.username
@project_name.Controllers.HomeController.UserType
E Biznes
źródło
1
Zawsze pomocne jest wyjaśnienie odpowiedzi, aby była ona bardziej jasna i zrozumiała. Przeczytaj stackoverflow.com/help/how-to-answer .
32cupo
0

Dlaczego nikt nie zasugerował metod rozszerzających w ViewData?

Opcja 1

Wydaje mi się zdecydowanie najmniej inwazyjnym i najprostszym rozwiązaniem problemu. Żadnych ciągów zakodowanych na stałe. Brak narzuconych ograniczeń. Żadnego magicznego kodowania. Bez skomplikowanego kodu.

public static class ViewDataExtensions
{
    private const string TitleData = "Title";
    public static void SetTitle<T>(this ViewDataDictionary<T> viewData, string value) => viewData[TitleData] = value;
    public static string GetTitle<T>(this ViewDataDictionary<T> viewData) => (string)viewData[TitleData] ?? "";
}

Ustaw dane na stronie

ViewData.SetTitle("abc");

Opcja 2

Inna opcja, ułatwiająca deklarację pola.

public static class ViewDataExtensions
{
    public static ViewDataField<string, V> Title<V>(this ViewDataDictionary<V> viewData) => new ViewDataField<string, V>(viewData, "Title", "");
}

public class ViewDataField<T,V>
{
    private readonly ViewDataDictionary<V> _viewData;
    private readonly string _field;
    private readonly T _defaultValue;

    public ViewDataField(ViewDataDictionary<V> viewData, string field, T defaultValue)
    {
        _viewData = viewData;
        _field = field;
        _defaultValue = defaultValue;
    }

    public T Value {
        get => (T)(_viewData[_field] ?? _defaultValue);
        set => _viewData[_field] = value;
    }
}

Ustaw dane na stronie. Deklaracja jest łatwiejsza niż pierwsza opcja, ale składnia użycia jest nieco dłuższa.

ViewData.Title().Value = "abc";

Opcja nr 3

Następnie można to połączyć z zwróceniem pojedynczego obiektu zawierającego wszystkie pola związane z układem z ich wartościami domyślnymi.

public static class ViewDataExtensions
{
    private const string LayoutField = "Layout";
    public static LayoutData Layout<T>(this ViewDataDictionary<T> viewData) => 
        (LayoutData)(viewData[LayoutField] ?? (viewData[LayoutField] = new LayoutData()));
}

public class LayoutData
{
    public string Title { get; set; } = "";
}

Ustaw dane na stronie

var layout = ViewData.Layout();
layout.Title = "abc";

Ta trzecia opcja ma kilka zalet i myślę, że w większości przypadków jest najlepszą opcją:

  • Najprostsza deklaracja pól i wartości domyślnych.

  • Najprostsza składnia użycia podczas ustawiania wielu pól.

  • Umożliwia ustawienie różnego rodzaju danych w ViewData (np. Layout, Header, Navigation).

  • Zezwala na dodatkowy kod i logikę w klasie LayoutData.

PS Nie zapomnij dodać przestrzeni nazw ViewDataExtensions w _ViewImports.cshtml

Etienne Charland
źródło
0

Możesz utworzyć plik razor w folderze App_Code, a następnie uzyskać do niego dostęp ze stron widoku.

Projekt> Repozytorium / IdentityRepository.cs

namespace Infrastructure.Repository
{
    public class IdentityRepository : IIdentityRepository
    {
        private readonly ISystemSettings _systemSettings;
        private readonly ISessionDataManager _sessionDataManager;

        public IdentityRepository(
            ISystemSettings systemSettings
            )
        {
            _systemSettings = systemSettings;
        }

        public string GetCurrentUserName()
        {
            return HttpContext.Current.User.Identity.Name;
        }
    }
}

Projekt> App_Code / IdentityRepositoryViewFunctions.cshtml:

@using System.Web.Mvc
@using Infrastructure.Repository
@functions
{
    public static IIdentityRepository IdentityRepositoryInstance
    {
        get { return DependencyResolver.Current.GetService<IIdentityRepository>(); }
    }

    public static string GetCurrentUserName
    {
        get
        {
            var identityRepo = IdentityRepositoryInstance;
            if (identityRepo != null)
            {
                return identityRepo.GetCurrentUserName();
            }
            return null;
        }
    }
}

Projekt> Widoki / Shared / _Layout.cshtml (lub dowolny inny plik .cshtml)

<div>
    @IdentityRepositoryViewFunctions.GetCurrentUserName
</div>
Joel Wiklund
źródło
-1

zamiast przechodzić przez to, zawsze możesz zastosować inne podejście, które również jest szybkie

utwórz nowy widok częściowy w katalogu udostępnionym i nazwij swój widok częściowy w układzie jako

@Html.Partial("MyPartialView")

w częściowym widoku możesz zadzwonić do swojej bazy danych i wykonać to, co chcesz

@{
    IEnumerable<HOXAT.Models.CourseCategory> categories = new HOXAT.Models.HOXATEntities().CourseCategories;
}

<div>
//do what ever here
</div>

zakładając, że dodano bazę danych Entity Framework

Asad Ali
źródło
1
Obniżanie, ponieważ nigdy nie powinno być obowiązkiem Widza, aby uzyskać swój własny Model.
Oxonhammer
-1

To niesamowite, że nikt tego tutaj nie powiedział. Przekazywanie modelu widoku przez podstawowy kontroler to bałagan. Używamy oświadczeń użytkowników, aby przekazywać informacje do strony układu (na przykład do wyświetlania danych użytkownika na pasku nawigacyjnym). Jest jeszcze jedna zaleta. Dane są przechowywane za pomocą plików cookie, więc nie ma potrzeby pobierania danych w każdym żądaniu za pośrednictwem częściowych. Po prostu wyszukaj w Google „oświadczenia o tożsamości netto”.

makore
źródło
@CodeSmith what? Dostarczam rozwiązanie.
makore
Mój błąd, myślałem, że to pytanie, ale zobacz, że to odpowiedź teraz, usunięte.
CodeSmith
Jeśli jest to próba odpowiedzi na pytanie, należy to wyjaśnić. Komentarz jest tolerowany, ale nie powinien dominować w całej odpowiedzi; również wskazówki, co należy wygooglować, nie stanowią prawidłowej odpowiedzi.
tripleee
-6

Możesz użyć w ten sposób:

 @{ 
    ApplicationDbContext db = new ApplicationDbContext();
    IEnumerable<YourModel> bd_recent = db.YourModel.Where(m => m.Pin == true).OrderByDescending(m=>m.ID).Select(m => m);
}
<div class="col-md-12">
    <div class="panel panel-default">
        <div class="panel-body">
            <div class="baner1">
                <h3 class="bb-hred">Recent Posts</h3>
                @foreach(var item in bd_recent)
                {
                    <a href="/BaiDangs/BaiDangChiTiet/@item.ID">@item.Name</a>
                }
            </div>
        </div>
    </div>
</div>
Ngô Đức Tuấn
źródło
7
Połączenie z bazą danych na widoku to naprawdę zły pomysł.
1_bug,