Übergeben Sie Daten an ein Layout, das allen Seiten gemeinsam ist

124

Ich habe eine Website mit einer Layoutseite. Diese Layoutseite enthält jedoch Daten, für die alle Seitenmodelle den Seitentitel, den Seitennamen und den Ort angeben müssen, an dem wir uns tatsächlich für einen HTML-Helfer befinden, den ich ausgeführt habe und der eine Aktion ausführt. Außerdem hat jede Seite ihre eigenen Eigenschaften für Ansichtsmodelle.

Wie kann ich das machen? Es scheint eine schlechte Idee zu sein, ein Layout einzugeben, aber wie übergebe ich diese Informationen?

Rushino
quelle
10
Informationen zum Lesen der Antworten finden Sie unter stackoverflow.com/a/21130867/706346. Dort finden Sie eine viel einfachere und übersichtlichere Lösung als alles, was hier veröffentlicht wurde.
Avrohom Yisroel
5
@ AvrohomYisroel guter Vorschlag. Ich bevorzuge jedoch den Ansatz von @Colin Bacon, da er stark typisiert ist und nicht in der ViewBag. Vielleicht eine Frage der Vorlieben. Upvoted Ihren Kommentar
JP Hellemons
für mvc 5 siehe diese Antwort: stackoverflow.com/a/46783375/5519026
Laz Ziya

Antworten:

142

Wenn Sie an jede Seite dieselben Eigenschaften übergeben müssen, ist es ratsam, ein Basisansichtsmodell zu erstellen, das von allen Ihren Ansichtsmodellen verwendet wird. Ihre Layoutseite kann dann dieses Basismodell übernehmen.

Wenn hinter diesen Daten Logik erforderlich ist, sollte diese in einen Basiscontroller gestellt werden, der von allen Ihren Controllern verwendet wird.

Es gibt eine Menge Dinge, die Sie tun können. Der wichtige Ansatz besteht darin, denselben Code nicht an mehreren Stellen zu wiederholen.

Bearbeiten: Update von Kommentaren unten

Hier ist ein einfaches Beispiel, um das Konzept zu demonstrieren.

Erstellen Sie ein Basisansichtsmodell, von dem alle Ansichtsmodelle erben.

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

public class HomeViewModel : ViewModelBase
{
}

Ihre Layoutseite kann dies als Modell verwenden.

@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>

Stellen Sie schließlich die Daten in der Aktionsmethode ein.

public class HomeController
{
    public ActionResult Index()
    {
        return this.View(new HomeViewModel { Name = "Bacon" });
    }
}
Colin Bacon
quelle
12
Die Daten werden jedoch im Layout verwendet. Wie kann ich die Daten an das Layout übergeben?
Rushino
2
Perfekt! Ich habe meinen Fehler gesehen. Ich habe vergessen, das Modell an die Ansicht zu übergeben. Was für ein lahmer Fehler. Vielen Dank!
Rushino
7
Das Problem bei diesem Ansatz ist, dass manchmal nicht jede Ansicht ein ViewModel hat, so dass dies in diesem Fall nicht funktioniert: O /
Cacho Santa
16
Aber würde dies nicht erfordern, dass jeder Controller und jede Aktion den Code {Name = "Bacon"} enthält? Und wenn ich ViewModelBase eine weitere Eigenschaft hinzufügen wollte, musste ich zu jedem Controller und jeder Aktion gehen und den Code hinzufügen, um diese Eigenschaft zu füllen? Sie erwähnten "Wenn Logik erforderlich ist, [...] sollte diese in einen Basis-Controller [...] eingefügt werden". Wie würde dies funktionieren, um diesen wiederholten Code in jedem Controller und jeder Aktion zu eliminieren?
Lee
5
@Lee Wenn es sich um gemeinsame Daten auf allen Seiten handelt, können Sie dies auf einem Basis-Controller ablegen. Ihre Controller erben dann von diesem Basis-Controller. zB public class HomeController : BaseController. Auf diese Weise muss der gemeinsame Code nur einmal geschrieben werden und kann auf alle Controller angewendet werden.
Colin Bacon
73

Ich habe den RenderAction HTML-Helfer für Rasiermesser im Layout verwendet.

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

Ich brauchte es für eine einfache Saite. Meine Aktion gibt also einen String zurück und schreibt ihn einfach in der Ansicht auf. Wenn Sie jedoch komplexe Daten benötigen, können Sie PartialViewResult und model zurückgeben.

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

Sie müssen Ihr Modell nur an den Anfang der von Ihnen erstellten Teilansicht '_maPartialView.cshtml' setzen

@model List<WhatEverYourObjeIs>

Dann können Sie Daten im Modell in dieser Teilansicht mit HTML verwenden.

Burk
quelle
18
Dies ist bei weitem die beste Antwort!
Lebkuchenjunge
@gingerbreadboy stimmte zu, dass es eine gute Verkapselung und eine Trennung von Bedenken fördert.
A-Dubb
35

Eine weitere Option besteht darin, eine separate LayoutModel-Klasse mit allen Eigenschaften zu erstellen, die Sie im Layout benötigen, und anschließend eine Instanz dieser Klasse in ViewBag einzufügen. Ich benutze die Controller.OnActionExecuting-Methode, um sie zu füllen. Zu Beginn des Layouts können Sie dieses Objekt dann aus ViewBag zurückziehen und weiterhin auf dieses stark typisierte Objekt zugreifen.

DenNukem
quelle
1
Das klingt tatsächlich nach einer am wenigsten schmerzhaften Lösung. Gibt es Nachteile? +1
Format
2
Auf jeden Fall die beste Lösung und ich sehe keine Nachteile.
Wiktor Zychla
7
Ich verstehe nicht, was dir das gibt. Wenn Sie eine Klasse mit allen Eigenschaften haben, die Sie für das Layout benötigen, warum sollten Sie sie dann zum ViewBag hinzufügen, um sie erneut zurücksetzen zu müssen? Verwenden Sie das Modell in der Layoutansicht. Sie können das Modell dennoch in füllen OnActionExecuting. Die Verwendung von ViewBag bedeutet auch, dass Sie die Typensicherheit in Ihrem Controller verlieren, was niemals gut ist.
Colin Bacon
3
Dies gibt mir die Möglichkeit, ein Modell für das Layout hinzuzufügen, ohne alle Modelle neu strukturieren zu müssen, um sie in einem bereits vorhandenen Projekt in allen Methoden aller Controller vom einzelnen "Super" -Modell zu erben. Wenn Sie bei Null anfangen, können Sie stattdessen alle Ihre Modelle aus dem gemeinsamen Stamm ableiten.
DenNukem
5
@ColinBacon Ein weiterer Vorteil dieser Option ist, dass Ihre Aktionen nicht immer Ansichtsmodelle haben müssen. Außerdem würde ich argumentieren, dass Entwickler, die wissen müssen, dass sie ihre Ansichtsmodelle immer von einer Basis erben müssen, ein Nachteil sind.
Josh Noe
28

Vermutlich besteht der Hauptanwendungsfall hierfür darin, ein Basismodell für alle (oder die meisten) Controller-Aktionen in die Ansicht zu bringen.

Angesichts dessen habe ich eine Kombination aus mehreren dieser Antworten verwendet, wobei ich mich hauptsächlich auf Colin Bacons Antwort stützte.

Es ist richtig, dass dies immer noch Controller-Logik ist, da wir ein Ansichtsmodell füllen, um zu einer Ansicht zurückzukehren. Daher ist der richtige Ort, um dies zu platzieren, in der Steuerung.

Wir möchten, dass dies auf allen Controllern geschieht, da wir dies für die Layoutseite verwenden. Ich verwende es für Teilansichten, die auf der Layoutseite gerendert werden.

Wir möchten auch weiterhin den zusätzlichen Vorteil eines stark typisierten ViewModel

Daher habe ich ein BaseViewModel und einen BaseController erstellt. Alle ViewModels-Controller erben von BaseViewModel bzw. BaseController.

Der Code:

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!";
    }
}

Beachten Sie die Verwendung von OnActionExecuted aus diesem SO-Beitrag

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>

Hoffentlich hilft das.

drizzie
quelle
2
Ich habe diesen Ansatz verwendet, erbe aber lieber von einer Schnittstelle als von einer Basisklasse. Also habe ich gemacht: var model = filterContext.Controller.ViewData.Model als IBaseViewModel if (model! = Null) {model.AwesomeModelProperty = "Awesome Property Value"; }
Tom Gerken
2
tolle Antwort, ich habe diese allen anderen vorgezogen.
Jynn
1
Tolle Antwort, aber ich habe eine Frage. "Was ist, wenn ich einige Ansichten habe, die keine ViewModels haben ...?"
Isma Haro
Versuchte dies, aber bei der Indexaktion füllt OnActionExecuted das FooterModel und dann wird ein neues HomeIndexModel mit einem Null-FooterModel erstellt :(
SteveCav
1
@drizzie: In Ihrem Basis-Controller ist model eine lokale Variable in der Filter-Methode: var model = filterContext.Controller.ViewData.Model als BaseViewModel. Ich verstehe nicht, wie MVC versteht, dass diese lokale Variable mit dem Modell identisch ist, das HomeController zur Ansicht sendet.
Hooman Bahreini
9

Sie müssen sich nicht mit Aktionen herumschlagen oder das Modell ändern, sondern nur einen Basis-Controller verwenden und den vorhandenen Controller aus dem Kontext der Layoutansicht umwandeln.

Erstellen Sie einen Basis-Controller mit den gewünschten gemeinsamen Daten (Titel / Seite / Speicherort usw.) und der Aktionsinitialisierung ...

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

    protected override void OnActionExecuting(ActionExecutingContext filterContext) {

        MyCommonValue = 12345;

        base.OnActionExecuting(filterContext);
    }
}

Stellen Sie sicher, dass jeder Controller den Basis-Controller verwendet ...

public class UserController:_BaseController {...

Übertragen Sie den vorhandenen Basis-Controller aus dem Ansichtskontext auf Ihrer _Layout.cshmlSeite ...

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

Jetzt können Sie auf Ihrer Layoutseite auf Werte in Ihrem Basis-Controller verweisen.

@myController.MyCommonValue

AKTUALISIEREN

Sie können auch eine Seitenerweiterung erstellen, die Sie verwenden können 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;
}

Dann müssen Sie nur noch daran denken, this.Controller()den Controller zu verwenden, wenn Sie ihn möchten.

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

oder spezifischer Controller, der von _BaseController... erbt .

@{
    var myController = this.Controller<MyControllerType>();
}
Carter Medlin
quelle
Was entspricht dem im .net-Kern? Da ViewContext.Controller nicht vorhanden ist und sich die Vererbungskette
geändert hat
4

Wenn Sie ein ganzes Modell übergeben möchten, gehen Sie wie folgt in das Layout:

@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>

und fügen Sie dies in der Steuerung hinzu:

public ActionResult _Header(ViewAsModelBase model)
Yakir Manor
quelle
4

Ich denke nicht, dass eine dieser Antworten für eine große Anwendung auf Unternehmensebene flexibel genug ist. Ich bin kein Fan von übermäßigem Gebrauch des ViewBag, aber in diesem Fall würde ich aus Gründen der Flexibilität eine Ausnahme machen. Folgendes würde ich tun ...

Sie sollten einen Basis-Controller auf allen Ihren Controllern haben. Fügen Sie Ihre Layoutdaten OnActionExecuting in Ihrem Basis-Controller hinzu (oder OnActionExecuted, wenn Sie dies verschieben möchten) ...

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

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

Ziehen Sie dann in Ihrer _Layout.cshtml Ihr ViewModel aus dem ViewBag ...

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

<h1>@model.Title</h1>

Oder...

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

Dadurch wird die Codierung für die Controller oder Ansichtsmodelle Ihrer Seite nicht beeinträchtigt.

Jack Sutherland
quelle
Ich mag Ihre Idee, aber was ist, wenn Sie eine MyLayoutViewModeldynamisch erstellte haben, wie kann ich einige Parameter an die OnActionExecutingMethode übergeben?
Rajmond Burgaj
1
Äh, du brauchst noch base.OnActionExecuting(filterContext)in deiner OnActionExecutingMethode !!!
ErikE
4

Das Erstellen einer Basisansicht, die das Modell der Layoutansicht darstellt, ist ein schrecklicher Ansatz. Stellen Sie sich vor, Sie möchten ein Modell haben, das die im Layout definierte Navigation darstellt. Würden Sie tun CustomersViewModel : LayoutNavigationViewModel? Warum? Warum sollten Sie die Navigationsmodelldaten durch jedes einzelne Ansichtsmodell leiten, das Sie in der Lösung haben?

Das Layout-Ansichtsmodell sollte eigenständig dediziert sein und den Rest der Ansichtsmodelle nicht dazu zwingen, davon abhängig zu sein.

Stattdessen können Sie dies in Ihrer _Layout.cshtmlDatei tun :

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

Am wichtigsten ist, wir müssen nicht new LayoutViewModel()und wir werden alle Abhängigkeiten bekommen LayoutViewModel, die für uns gelöst wurden.

z.B

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

    public LayoutViewModel(DataContext dataContext, ApplicationUserManager userManager)
    {
    }
}
Hyankov
quelle
Wo füllst du dieses Modell? Auch in einem BaseController?
Ndberg
Ich stelle mir vor, dass dies auch eine gute Idee für ein ScopedLayoutmodellobjekt in ASP..Net Core wäre.
James Wilkins
Ich würde die Ansicht nicht dazu bringen, eine Abhängigkeit abzurufen. Das ist definitiv nicht "MVC". Service Locator ist ein Anti-Pattern .
Jiveman
Entgegen der landläufigen Meinung ist Service Locator kein Anti-Pattern und hat eigentlich nichts mit MVC zu tun. Wirfst du nur Schlagworte @Jiveman ein? blog.gauffin.org/2012/09/service-locator-is-not-an-anti-pattern
hyankov
Jgauffins Hauptpunkt in diesem Artikel scheint zu sein, dass der Begriff "Anti-Pattern" nicht auf Service Locator angewendet werden sollte, da es zumindest einige gültige Verwendungen von SL geben kann. Ein fairer Punkt. Wie jedoch in einigen seiner eigenen Diskussionskommentare deutlich wird, schlägt er vor, dass SL zwar ein gültiger Ansatz beim Erstellen von Bibliotheken und Frameworks sein könnte, jedoch nicht unbedingt beim Erstellen von Anwendungen empfohlen wird (was ich als OP-Frage und diese Diskussion hier betrachten würde) rund um).
Jiveman
3

Andere Antworten haben so ziemlich alles darüber behandelt, wie wir das Modell an unsere Layoutseite übergeben können. Ich habe jedoch einen Weg gefunden, mit dem Sie Variablen dynamisch an Ihre Layoutseite übergeben können, ohne ein Modell oder eine Teilansicht in Ihrem Layout zu verwenden. Nehmen wir an, Sie haben dieses Modell -

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

Und Sie wollen Stadt und Staat dynamisch bekommen. Zum Beispiel

In Ihrer index.cshtml können Sie diese beiden Variablen in ViewBag einfügen

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

Und dann können Sie in Ihrer layout.cshtml auf diese Viewbag-Variablen zugreifen

<div class="text-wrap">
    <div class="heading">@ViewBag.City @ViewBag.State</div>
</div>
Chirag K.
quelle
Dies funktioniert hervorragend. @stun_Gravy Gibt es einen Nachteil bei der Verwendung von ViewBag zum Übergeben von Daten wie Rolle oder Benutzerzugriffsebene?
3not3
3

Es gibt noch einen anderen Weg, damit umzugehen. Aus architektonischer Sicht vielleicht nicht der sauberste Weg, aber es vermeidet viel Schmerz, der mit den anderen Antworten verbunden ist. Fügen Sie einfach einen Dienst in das Razor-Layout ein und rufen Sie dann eine Methode auf, die die erforderlichen Daten abruft:

@inject IService myService

Dann später in der Layoutansicht:

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

Wiederum nicht sauber in Bezug auf die Architektur (offensichtlich sollte der Dienst nicht direkt in die Ansicht eingefügt werden), aber er erledigt den Job.

Andrew
quelle
Nicht der sauberste Weg? Ich bin nicht einverstanden. Ich denke, das ist so sauber wie es nur geht: Das Objekt wird von dem Ort, an dem es erstellt wurde, direkt an den Ort übergeben, an dem es sein soll, ohne andere Controller mit Elementen zu "verschmutzen", die sie nicht sehen müssen. Verwenden @injectist meiner Meinung nach die beste Lösung.
dasblinkenlight
1
Wenn Sie mehr darüber nachdenken, haben Sie vielleicht Recht. Die Tatsache, dass diese Methode so viel Schmerz vermeidet, ist ein Zeichen dafür, dass es vielleicht der sauberste Weg ist. Ich habe an einer sehr großen ASP.NET Core-App gearbeitet und verwende dieses Muster für Dinge wie Navigations-Breadcrumb-Logik, Header-Daten auf den meisten Seiten und ähnliches. Ich habe so viel Schmerz vermieden, indem ich es stattdessen so gemacht habe.
Andrew
2

Sie können auch RenderSection verwenden . Es hilft Ihnen, Ihre ModelDaten in die _LayoutAnsicht einzufügen .

Sie können injizieren View ModelDaten, Json, Script, CSS, HTMLusw.

In diesem Beispiel spritze Jsonich von IndexAnsicht zu LayoutAnsicht.

Index.chtml

@section commonLayoutData{

    <script>

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

    </script>

    }

_Layout.cshtml

@RenderSection("commonLayoutData", false)

Dadurch entfällt die Notwendigkeit, eine separate Basis zu erstellen View Model.

Hoffnung hilft jemandem.

Shaijut
quelle
1
Perfekte Lösung, wenn Sie nur für einige Ansichten etwas Bestimmtes rendern müssen.
Kunal
1

Was ich getan habe, ist sehr einfach und es funktioniert

Deklarieren Sie die statische Eigenschaft in einem beliebigen Controller, oder Sie können eine Datenklasse mit statischen Werten erstellen, wenn Sie dies möchten:

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

Diese Werte können von den Controllern basierend auf Operationen aktualisiert werden. später können Sie sie in Ihrem _Layout verwenden

In _layout.cshtml

@project_name.Controllers.HomeController.username
@project_name.Controllers.HomeController.UserType
E Geschäft
quelle
1
Es ist immer hilfreich, Ihrer Antwort eine Erklärung hinzuzufügen, um sie klarer und verständlicher zu machen. Bitte lesen Sie stackoverflow.com/help/how-to-answer .
32cupo
0

Warum hat niemand Erweiterungsmethoden für ViewData vorgeschlagen?

Option 1

Scheint mir bei weitem die am wenigsten aufdringliche und einfachste Lösung für das Problem. Keine fest codierten Zeichenfolgen. Keine auferlegten Einschränkungen. Keine magische Kodierung. Kein komplexer Code.

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] ?? "";
}

Stellen Sie die Daten auf der Seite ein

ViewData.SetTitle("abc");

Option 2

Eine weitere Option, die die Felddeklaration erleichtert.

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;
    }
}

Stellen Sie die Daten auf der Seite ein. Die Deklaration ist einfacher als die erste Option, aber die Verwendungssyntax ist etwas länger.

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

Option 3

Dann können Sie dies mit der Rückgabe eines einzelnen Objekts kombinieren, das alle layoutbezogenen Felder mit ihren Standardwerten enthält.

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; } = "";
}

Stellen Sie die Daten auf der Seite ein

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

Diese dritte Option hat mehrere Vorteile und ich denke, sie ist in den meisten Fällen die beste Option:

  • Einfachste Deklaration von Feldern und Standardwerten.

  • Einfachste Verwendungssyntax beim Festlegen mehrerer Felder.

  • Ermöglicht das Festlegen verschiedener Arten von Daten in den ViewData (z. B. Layout, Header, Navigation).

  • Ermöglicht zusätzlichen Code und Logik innerhalb der LayoutData-Klasse.

PS Vergessen Sie nicht, den Namespace von ViewDataExtensions in _ViewImports.cshtml hinzuzufügen

Etienne Charland
quelle
0

Sie können eine Rasiermesserdatei im Ordner App_Code erstellen und dann über Ihre Ansichtsseiten darauf zugreifen.

Projekt> Repository / 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> Ansichten / Freigegeben / _Layout.cshtml (oder eine andere .cshtml-Datei)

<div>
    @IdentityRepositoryViewFunctions.GetCurrentUserName
</div>
Joel Wiklund
quelle
-1

Anstatt dies durchzugehen, können Sie immer einen anderen Ansatz verwenden, der auch schnell ist

Erstellen Sie eine neue Teilansicht im freigegebenen Verzeichnis und rufen Sie Ihre Teilansicht in Ihrem Layout als auf

@Html.Partial("MyPartialView")

In Ihrer Teilansicht können Sie Ihre Datenbank aufrufen und ausführen, was immer Sie möchten

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

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

Angenommen, Sie haben Ihre Entity Framework-Datenbank hinzugefügt

Asad Ali
quelle
1
Downcasting, da es niemals in der Verantwortung der Ansicht liegen sollte, ein eigenes Modell zu erhalten.
Oxonhammer
-1

Es ist unglaublich, dass hier niemand das gesagt hat. Das Übergeben eines Ansichtsmodells durch einen Basis-Controller ist ein Chaos. Wir verwenden Benutzeransprüche , um Informationen an die Layoutseite zu übergeben (zum Beispiel zum Anzeigen von Benutzerdaten in der Navigationsleiste). Es gibt noch einen Vorteil. Die Daten werden über Cookies gespeichert, sodass die Daten in jeder Anfrage nicht über Teilabrufe abgerufen werden müssen. Googeln Sie einfach ein bisschen "asp net identity Claims".

makore
quelle
@ CodeSmith was? Ich biete eine Lösung.
Makore
Mein schlechtes, dachte, das wäre eine Frage, aber siehe, es ist jetzt eine Antwort, gelöscht.
CodeSmith
Wenn dies ein Versuch ist, die Frage zu beantworten, sollte dies geklärt werden. Kommentare werden toleriert, sollten aber nicht die gesamte Antwort dominieren. Tipps für Google sind keine gültige Antwort.
Tripleee
-6

Sie können wie folgt verwenden:

 @{ 
    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
quelle
7
Eine Verbindung mit der angezeigten Datenbank ist wirklich eine schlechte Idee.
1_bug