Truyền dữ liệu cho bố cục phổ biến cho tất cả các trang


124

Tôi có một trang web có một trang bố trí. Tuy nhiên, trang bố cục này có dữ liệu mà tất cả các mô hình trang phải cung cấp tiêu đề trang, tên trang đó và vị trí chúng tôi thực sự dành cho trình trợ giúp HTML mà tôi đã thực hiện một số hành động. Ngoài ra mỗi trang có thuộc tính mô hình xem riêng của họ.

Tôi có thể làm cái này như thế nào? Có vẻ như đó là một ý tưởng tồi để nhập một bố cục nhưng làm thế nào để tôi vượt qua các luận điểm?


10
Đối với bất kỳ ai đọc các câu trả lời ở đây, vui lòng xem stackoverflow.com/a/21130867/706346 nơi bạn sẽ thấy một giải pháp đơn giản và gọn gàng hơn nhiều mà mọi thứ được đăng ở đây.
Avrohom Yisroel

5
@AvrohomYisroel đề nghị tốt. Tuy nhiên tôi thích cách tiếp cận của @Colin Bacon vì nó được gõ mạnh và không nằm trong ViewBag. Có lẽ là một vấn đề sở thích. Nâng cao nhận xét của bạn mặc dù
JP Hellemons

cho mvc 5 xem câu trả lời này: stackoverflow.com/a/46783375/5519026
Laz Ziya

Câu trả lời:


142

Nếu bạn được yêu cầu chuyển các thuộc tính giống nhau cho mỗi trang, thì việc tạo một chế độ xem cơ sở được sử dụng bởi tất cả các mô hình chế độ xem của bạn sẽ là điều khôn ngoan. Trang bố trí của bạn sau đó có thể lấy mô hình cơ sở này.

Nếu có logic cần thiết đằng sau dữ liệu này, thì dữ liệu này sẽ được đưa vào bộ điều khiển cơ sở được sử dụng bởi tất cả các bộ điều khiển của bạn.

Có rất nhiều điều bạn có thể làm, cách tiếp cận quan trọng là không lặp lại cùng một mã ở nhiều nơi.

Chỉnh sửa: Cập nhật từ các bình luận bên dưới

Dưới đây là một ví dụ đơn giản để chứng minh khái niệm.

Tạo một mô hình khung nhìn cơ sở mà tất cả các mô hình khung nhìn sẽ kế thừa từ đó.

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

public class HomeViewModel : ViewModelBase
{
}

Trang bố trí của bạn có thể lấy điều này làm mô hình.

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

Cuối cùng thiết lập dữ liệu trong phương thức hành động.

public class HomeController
{
    public ActionResult Index()
    {
        return this.View(new HomeViewModel { Name = "Bacon" });
    }
}

12
Nhưng dữ liệu được sử dụng trong bố trí. Làm thế nào tôi có thể truyền dữ liệu để bố trí?
Rushino

2
Hoàn hảo! Tôi thấy lỗi của tôi. Tôi quên chuyển mô hình sang chế độ xem .. thật là một lỗi khập khiễng. Cảm ơn!
Rushino

7
Vấn đề với cách tiếp cận này là đôi khi không phải mọi chế độ xem đều có ViewModel, vì vậy điều này sẽ không hoạt động trong trường hợp đó: O /
Cacho Santa

16
Nhưng điều này có yêu cầu mọi bộ điều khiển và mọi hành động đều bao gồm mã {Name = "Bacon"} không? Và nếu tôi muốn thêm một thuộc tính khác vào ViewModelBase, tôi phải đến mọi bộ điều khiển và mọi hành động và thêm mã để điền vào thuộc tính đó? Bạn đã đề cập "Nếu có logic cần thiết [...] thì điều này nên được đưa vào bộ điều khiển cơ sở [...]". Làm thế nào điều này sẽ làm việc để loại bỏ mã lặp đi lặp lại này trong mọi bộ điều khiển và mọi hành động?
Lee

5
@Lee Nếu đó là dữ liệu phổ biến trên tất cả các trang, bộ điều khiển cơ sở là nơi bạn sẽ đặt dữ liệu này. Bộ điều khiển của bạn sau đó kế thừa từ bộ điều khiển cơ sở này. ví dụ public class HomeController : BaseController. Bằng cách này, mã chung chỉ cần được viết một lần và có thể được áp dụng cho tất cả các bộ điều khiển.
Colin Bacon

73

Tôi đã sử dụng trình trợ giúp html RenderAction cho dao cạo trong bố cục.

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

Tôi cần nó cho chuỗi đơn giản. Vì vậy, hành động của tôi trả về chuỗi và viết nó dễ dàng trong xem. Nhưng nếu bạn cần dữ liệu phức tạp, bạn có thể trả về PartialViewResult và mô hình.

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

Bạn chỉ cần đặt mô hình của mình bắt đầu chế độ xem một phần '_maPartialView.cshtml' mà bạn đã tạo

@model List<WhatEverYourObjeIs>

Sau đó, bạn có thể sử dụng dữ liệu trong mô hình trong chế độ xem một phần với html.


18
Đây là câu trả lời hay nhất!
gingerbreadboy

@gingerbreadboy đồng ý nó thúc đẩy đóng gói tốt và tách biệt các mối quan tâm.
A-Dubb

35

Một tùy chọn khác là tạo một lớp LayoutModel riêng biệt với tất cả các thuộc tính bạn sẽ cần trong bố cục, sau đó đưa một thể hiện của lớp này vào ViewBag. Tôi sử dụng phương thức Controller.OnActionExecuting để điền vào nó. Sau đó, khi bắt đầu bố trí, bạn có thể kéo đối tượng này trở lại từ ViewBag và tiếp tục truy cập đối tượng được gõ mạnh này.


1
Điều này thực sự có vẻ như giải pháp ít đau đớn nhất, có bất kỳ nhược điểm? +1
formatc

2
Chắc chắn là giải pháp tốt nhất và tôi không thấy bất kỳ nhược điểm nào.
Wiktor Zychla

7
Tôi không thấy những gì nó mang lại cho bạn. Nếu bạn đã có một lớp với tất cả các thuộc tính bạn cần cho bố cục, tại sao lại chỉ thêm nó vào ViewBag để phải sử dụng lại nó? Sử dụng mô hình trong chế độ xem bố cục, bạn vẫn có thể đưa mô hình vào OnActionExecuting. Sử dụng ViewBag cũng có nghĩa là bạn mất an toàn loại trong bộ điều khiển của mình, không bao giờ là một điều tốt.
Colin Bacon

3
Điều này mang lại cho tôi là khả năng thêm một mô hình để bố trí, mà không phải cơ cấu lại tất cả các mô hình để kế thừa từ mô hình "siêu" duy nhất trong tất cả các phương thức của tất cả các bộ điều khiển, trong một dự án đã tồn tại. Nếu bạn đang bắt đầu từ đầu, thay vào đó, bạn có thể chọn lấy tất cả các mô hình của mình từ gốc chung.
DenNukem

5
@ColinBacon một lợi thế khác cho tùy chọn này là Hành động của bạn không cần phải luôn có các mô hình xem. Ngoài ra, tôi cho rằng các nhà phát triển cần biết rằng họ phải luôn kế thừa các mô hình xem của họ từ một cơ sở là một bất lợi.
Josh Noe

28

Có lẽ, trường hợp sử dụng chính cho điều này là để đưa một mô hình cơ sở vào dạng xem cho tất cả (hoặc phần lớn) các hành động của bộ điều khiển.

Do đó, tôi đã sử dụng kết hợp một vài trong số những câu trả lời này, ủng hộ chính cho câu trả lời của Colin Bacon.

Đúng là đây vẫn là bộ điều khiển logic bởi vì chúng tôi đang đưa ra một chế độ xem để quay lại chế độ xem. Do đó, vị trí chính xác để đặt cái này là trong bộ điều khiển.

Chúng tôi muốn điều này xảy ra trên tất cả các bộ điều khiển vì chúng tôi sử dụng điều này cho trang bố cục. Tôi đang sử dụng nó cho các chế độ xem một phần được hiển thị trong trang bố cục.

Chúng tôi cũng vẫn muốn lợi ích gia tăng của một ViewModel được gõ mạnh

Vì vậy, tôi đã tạo một BaseViewModel và BaseContoder. Tất cả các Bộ điều khiển ViewModels sẽ kế thừa từ BaseViewModel và BaseContoder tương ứng.

Mật mã:

Trình điều khiển cơ sở

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

Lưu ý việc sử dụng OnActionExecuted như được lấy từ bài SO này

HomeContoder

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

Giao diện.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>

Hy vọng điều này sẽ giúp.


2
Tôi đã sử dụng phương pháp này, nhưng thích kế thừa từ một giao diện hơn là một lớp cơ sở. Vì vậy, tôi đã làm: var model = filterContext.Controll.ViewData.Model là IBaseViewModel if (model! = Null) {model.Aw đũaModelProperty = "Giá trị tài sản tuyệt vời"; }
Tom Gerken

2
Câu trả lời tuyệt vời, tôi thích cái này hơn tất cả những cái khác.
Jynn

1
Câu trả lời tuyệt vời, nhưng tôi có một câu hỏi. "Điều gì xảy ra nếu tôi có một số chế độ xem không có ViewModels ...?"
Isma Haro

Đã thử điều này nhưng trên Index Action, OnActionExecuted sẽ điền vào FooterModel và sau đó một Home IndexModel mới được tạo bằng FooterModel null :(
SteveCav

1
@drizzie: trong bộ điều khiển cơ sở của bạn, mô hình là một biến cục bộ trong phương thức Filter: var model = filterContext.Contoder.ViewData.Model là BaseViewModel. Tôi không hiểu làm thế nào MVC hiểu rằng biến cục bộ này giống với mô hình mà HomeContoder đang gửi để xem.
Hooman Bahreini

9

Bạn không phải lộn xộn với các hành động hoặc thay đổi mô hình, chỉ cần sử dụng bộ điều khiển cơ bản và bỏ bộ điều khiển hiện có từ khung nhìn bố cục.

Tạo bộ điều khiển cơ sở với dữ liệu chung mong muốn (tiêu đề / trang / vị trí, v.v.) và khởi tạo hành động ...

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

    protected override void OnActionExecuting(ActionExecutingContext filterContext) {

        MyCommonValue = 12345;

        base.OnActionExecuting(filterContext);
    }
}

Đảm bảo mọi bộ điều khiển đều sử dụng bộ điều khiển cơ sở ...

public class UserController:_BaseController {...

Truyền bộ điều khiển cơ sở hiện có từ ngữ cảnh xem trong _Layout.cshmltrang của bạn ...

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

Bây giờ bạn có thể tham khảo các giá trị trong bộ điều khiển cơ sở từ trang bố trí của bạn.

@myController.MyCommonValue

CẬP NHẬT

Bạn cũng có thể tạo một phần mở rộng trang cho phép bạn sử dụng 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;
}

Sau đó, bạn chỉ phải nhớ sử dụng this.Controller()khi bạn muốn bộ điều khiển.

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

hoặc bộ điều khiển cụ thể kế thừa từ _BaseController...

@{
    var myController = this.Controller<MyControllerType>();
}

Tương đương của điều này trong lõi .net là gì? Vì ViewContext.Controll không có mặt và có một số thay đổi trong chuỗi thừa kế
Jayanth Thyagarajan

4

nếu bạn muốn vượt qua toàn bộ mô hình, hãy thực hiện theo cách bố trí:

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

và thêm phần này vào bộ điều khiển:

public ActionResult _Header(ViewAsModelBase model)

4

Tôi không nghĩ bất kỳ câu trả lời nào trong số này là đủ linh hoạt cho một ứng dụng cấp doanh nghiệp lớn. Tôi không phải là người thích lạm dụng ViewBag, nhưng trong trường hợp này, vì tính linh hoạt, tôi sẽ tạo ra một ngoại lệ. Đây là những gì tôi sẽ làm ...

Bạn nên có một bộ điều khiển cơ bản trên tất cả các bộ điều khiển của bạn. Thêm dữ liệu Bố cục của bạn OnActionExecuting trong bộ điều khiển cơ sở của bạn (hoặc OnActionExecuted nếu bạn muốn trì hoãn điều đó) ...

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

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

Sau đó, trong _Layout.cshtml của bạn, hãy kéo ViewModel của bạn khỏi ViewBag ...

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

<h1>@model.Title</h1>

Hoặc là...

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

Làm điều này không can thiệp vào mã hóa cho bộ điều khiển trang hoặc mô hình xem của bạn.


Tôi thích ý tưởng của bạn nhưng nếu bạn có một MyLayoutViewModelđộng lực được tạo ra, làm thế nào tôi có thể truyền một số tham số cho OnActionExecutingphương thức?
Rajmond Burgaj

1
Uh, bạn vẫn cần base.OnActionExecuting(filterContext)trong OnActionExecutingphương pháp của bạn !!!
ErikE

4

Tạo chế độ xem cơ sở đại diện cho mô hình chế độ xem Bố cục là một cách tiếp cận khủng khiếp. Hãy tưởng tượng rằng bạn muốn có một mô hình đại diện cho điều hướng được xác định trong bố cục. Bạn sẽ làm CustomersViewModel : LayoutNavigationViewModelgì Tại sao? Tại sao bạn nên chuyển dữ liệu mô hình điều hướng qua từng mô hình xem duy nhất mà bạn có trong giải pháp?

Mô hình khung nhìn Bố cục nên được dành riêng, và không nên buộc các mô hình khung nhìn còn lại phụ thuộc vào nó.

Thay vào đó, bạn có thể làm điều này, trong _Layout.cshtmltệp của bạn :

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

Quan trọng nhất, chúng tôi không cần new LayoutViewModel()và chúng tôi sẽ nhận được tất cả các phụ thuộc LayoutViewModelđã giải quyết cho chúng tôi.

ví dụ

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

    public LayoutViewModel(DataContext dataContext, ApplicationUserManager userManager)
    {
    }
}

Nơi nào bạn điền mô hình này? Trong một BaseContoder là tốt?
ndberg

Tôi tưởng tượng điều này sẽ là một ý tưởng tốt cho một Scopedđối tượng mô hình bố cục trong ASP..Net Core.
James Wilkins

Tôi sẽ không có quan điểm đi tìm một phụ thuộc. Đó chắc chắn không phải là "MVC". Dịch vụ định vị là một mô hình chống .
Jiveman

Trái với suy nghĩ của nhiều người, Service Locator không phải là một mô hình chống và thực sự điều này không liên quan gì đến MVC, bạn chỉ đang ném vào những từ buzz @Jiveman? blog.gauffin.org/2012/09/service-locator-is-not-an-anti-potype
hyankov

Điểm chính của Jgauffin trong bài viết đó dường như là thuật ngữ "chống mẫu" không nên được áp dụng cho Trình định vị dịch vụ, vì có thể có ít nhất một số cách sử dụng SL hợp lệ. Một điểm công bằng. Tuy nhiên, như đã thấy rõ trong một số ý kiến ​​thảo luận của riêng mình, ông cho rằng mặc dù SL có thể là một cách tiếp cận hợp lệ khi xây dựng thư viện và khung, nhưng không nhất thiết phải xây dựng các ứng dụng (mà tôi sẽ xem xét câu hỏi của OP và cuộc thảo luận này ở đây Xoay quanh).
Jiveman

3

Các câu trả lời khác đã trình bày khá nhiều thứ về cách chúng ta có thể chuyển mô hình đến trang bố cục của mình. Nhưng tôi đã tìm thấy một cách sử dụng mà bạn có thể chuyển các biến vào trang bố trí của mình một cách linh hoạt mà không cần sử dụng bất kỳ mô hình hoặc chế độ xem một phần nào trong bố cục của bạn. Hãy để chúng tôi nói bạn có mô hình này -

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

Và bạn muốn có được thành phố và nhà nước năng động. Ví dụ

trong index.cshtml của bạn, bạn có thể đặt hai biến này trong ViewBag

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

Và sau đó trong layout.cshtml của bạn, bạn có thể truy cập các biến viewbag đó

<div class="text-wrap">
    <div class="heading">@ViewBag.City @ViewBag.State</div>
</div>

Điều này hoạt động rất tốt, @stun_Gravy có sự sụp đổ khi sử dụng ViewBag để truyền dữ liệu như vai trò hoặc cấp độ truy cập của người dùng?
3not3

3

Có một cách khác để xử lý việc này. Có thể không phải là cách sạch nhất từ ​​quan điểm kiến ​​trúc, nhưng nó tránh được rất nhiều nỗi đau liên quan đến các câu trả lời khác. Đơn giản chỉ cần tiêm một dịch vụ trong bố trí Dao cạo và sau đó gọi một phương thức lấy dữ liệu cần thiết:

@inject IService myService

Sau đó, trong chế độ xem bố trí:

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

Một lần nữa, không rõ ràng về mặt kiến ​​trúc (rõ ràng dịch vụ không nên được đưa trực tiếp vào chế độ xem), nhưng nó hoàn thành công việc.


Không phải cách sạch nhất? Tôi không đồng ý. Tôi nghĩ rằng điều này là sạch như nó có được: đối tượng được truyền từ nơi nó được tạo thẳng đến nơi bạn muốn, mà không "làm ô nhiễm" các bộ điều khiển khác với các mục mà họ không cần phải nhìn thấy. Sử dụng @injectlà giải pháp tốt nhất, theo ý kiến ​​của tôi.
dasblinkenlight

1
Suy nghĩ về điều này nhiều hơn có lẽ bạn đúng. Thực tế là phương pháp này tránh được quá nhiều đau đớn là một dấu hiệu cho thấy có lẽ đó là cách sạch nhất. Tôi đã làm việc trên một ứng dụng ASP.NET Core rất lớn và tôi đang sử dụng mẫu này cho những thứ như logic điều hướng bánh mì, dữ liệu tiêu đề có trên hầu hết các trang, những thứ tương tự. Tôi đã tránh được rất nhiều nỗi đau bằng cách làm theo cách này thay vào đó.
Andrew

2

Bạn cũng có thể sử dụng RenderSection , nó giúp bạn đưa Modeldữ liệu của mình vào _Layoutchế độ xem.

Bạn có thể tiêm View Modeldữ liệu, Json, Script, CSS, HTMLvv

Trong ví dụ này, tôi đang chuyển Jsontừ IndexChế độ xem sang LayoutChế độ xem.

Index.chtml

@section commonLayoutData{

    <script>

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

    </script>

    }

_Layout.cshtml

@RenderSection("commonLayoutData", false)

Điều này giúp loại bỏ sự cần thiết phải tạo một Base riêng biệt View Model.

Hy vọng giúp được ai đó.


1
Giải pháp hoàn hảo khi bạn chỉ cần kết xuất một cái gì đó cụ thể cho một vài lượt xem.
Kunal

1

những gì tôi đã làm rất đơn giản và nó hoạt động

Khai báo thuộc tính tĩnh trong bất kỳ bộ điều khiển nào hoặc bạn có thể tạo một lớp dữ liệu với các giá trị tĩnh nếu bạn muốn như thế này:

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

Các giá trị này có thể được cập nhật bởi các bộ điều khiển dựa trên các hoạt động. sau này bạn có thể sử dụng chúng trong _Layout của bạn

Trong _layout.cshtml

@project_name.Controllers.HomeController.username
@project_name.Controllers.HomeController.UserType

1
Nó luôn hữu ích thêm một số lời giải thích cho câu trả lời của bạn, để làm cho nó rõ ràng và dễ hiểu hơn. Vui lòng đọc stackoverflow.com/help/how-to-answer .
32cupo

0

Tại sao không ai đề xuất các phương thức mở rộng trên ViewData?

Lựa chọn 1

Dường như với tôi cho đến nay giải pháp ít xâm phạm nhất và đơn giản nhất cho vấn đề. Không có chuỗi mã hóa cứng. Không áp đặt hạn chế. Không có mã hóa ma thuật. Không có mã phức tạp.

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

Đặt dữ liệu trong trang

ViewData.SetTitle("abc");

Lựa chọn 2

Một lựa chọn khác, làm cho khai báo trường dễ dàng hơn.

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

Đặt dữ liệu trong trang. Khai báo dễ hơn tùy chọn đầu tiên, nhưng cú pháp sử dụng dài hơn một chút.

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

Lựa chọn số 3

Sau đó, có thể kết hợp điều đó với việc trả về một đối tượng duy nhất chứa tất cả các trường liên quan đến bố cục với các giá trị mặc định của chúng.

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

Đặt dữ liệu trong trang

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

Tùy chọn thứ ba này có một số lợi ích và tôi nghĩ là tùy chọn tốt nhất trong hầu hết các trường hợp:

  • Khai báo đơn giản nhất các trường và giá trị mặc định.

  • Cú pháp sử dụng đơn giản nhất khi thiết lập nhiều trường.

  • Cho phép thiết lập các loại dữ liệu khác nhau trong ViewData (ví dụ: Bố cục, Tiêu đề, Điều hướng).

  • Cho phép mã và logic bổ sung trong lớp LayoutData.

PS Đừng quên thêm không gian tên của ViewDataExtensions trong _ViewImports.cshtml


0

Bạn có thể tạo tệp dao cạo trong thư mục App_Code và sau đó truy cập tệp đó từ các trang xem của bạn.

Dự án> Kho lưu trữ / Nhận dạngRep repository.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;
        }
    }
}

Dự án> App_Code / IdentityRep repositoryViewFiances.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;
        }
    }
}

Dự án> Lượt xem / Chia sẻ / _Layout.cshtml (hoặc bất kỳ tệp .cshtml nào khác)

<div>
    @IdentityRepositoryViewFunctions.GetCurrentUserName
</div>

-1

thay vì trải qua điều này, bạn luôn có thể sử dụng một cách tiếp cận khác cũng nhanh chóng

tạo chế độ xem một phần mới trong Danh bạ chung và gọi chế độ xem một phần trong bố cục của bạn là

@Html.Partial("MyPartialView")

trong chế độ xem một phần của bạn, bạn có thể gọi db của mình và thực hiện những gì bạn muốn làm

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

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

giả sử bạn đã thêm Cơ sở dữ liệu khung thực thể


1
Downcasting vì nó không bao giờ là trách nhiệm của Chế độ xem để có được Mô hình của chính nó.
Oxonhammer

-1

Thật đáng kinh ngạc khi không ai nói điều này ở đây. Truyền một viewmodel qua bộ điều khiển cơ sở là một mớ hỗn độn. Chúng tôi đang sử dụng khiếu nại của người dùng để chuyển thông tin đến trang bố cục (ví dụ để hiển thị dữ liệu người dùng trên thanh điều hướng). Có một lợi thế nữa. Dữ liệu được lưu trữ thông qua cookie, do đó không cần phải lấy dữ liệu trong mỗi yêu cầu thông qua các hạt. Chỉ cần thực hiện một số "yêu cầu nhận dạng asp net".


@CodeSmith là gì? Tôi đang cung cấp một giải pháp.
makore

Thật tệ, tôi nghĩ đây là một câu hỏi nhưng bây giờ đã thấy nó là một câu trả lời.
CodeSmith

Nếu đây là một nỗ lực trả lời câu hỏi, nó cần được làm rõ. Bình luận được dung thứ nhưng không nên chi phối toàn bộ câu trả lời; Ngoài ra, lời khuyên cho những gì để google không tạo thành một câu trả lời hợp lệ.
tripleee

-6

Bạn có thể sử dụng như thế này:

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

7
Kết nối với cơ sở dữ liệu trong xem là ý tưởng thực sự xấu.
1_ bọ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.