すべてのページに共通のレイアウトにデータを渡す


124

レイアウトページのあるウェブサイトを持っています。ただし、このレイアウトページには、すべてのページモデルがそのようなページタイトル、ページ名、およびアクションを実行するHTMLヘルパーの実際の場所を提供する必要があるデータがあります。また、各ページには独自のビューモデルプロパティがあります。

これどうやってするの?レイアウトを入力するのは悪い考えのようですが、どうすればこれらの情報を渡すことができますか?


10
ここで返信を読んでいる人は、stackoverflow.com / a / 21130867/706346を参照してください。ここに投稿されたものよりもはるかにシンプルでわかりやすいソリューションが表示されます。
Avrohom Yisroel

5
@AvrohomYisroel良い提案。ただし、@ Colin Baconのアプローチは、強い型付けがされており、ViewBag。おそらく好みの問題です。しかし、コメントに賛成しました
JP Hellemons

MVC 5のためにこの回答を参照してください。stackoverflow.com/a/46783375/5519026
ラズZiya

回答:


142

各ページに同じプロパティを渡す必要がある場合は、すべてのビューモデルで使用されるベースビューモデルを作成するのが賢明です。レイアウトページは、この基本モデルを取ることができます。

このデータの背後に必要なロジックがある場合、これは、すべてのコントローラーで使用される基本コントローラーに配置する必要があります。

できることはたくさんありますが、重要なアプローチは、同じコードを複数の場所で繰り返さないことです。

編集:以下のコメントから更新

これは、概念を示すための簡単な例です。

すべてのビューモデルが継承するベースビューモデルを作成します。

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

public class HomeViewModel : ViewModelBase
{
}

レイアウトページでは、これをモデルとして使用できます。

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

最後に、アクションメソッドにデータを設定します。

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

12
ただし、データはレイアウトで使用されます。データをレイアウトに渡すにはどうすればよいですか?
ルシノ

2
パーフェクト!エラーを見ました。モデルをビューに渡すのを忘れました。ありがとう!
ルシノ

7
このアプローチの問題は、すべてのビューにViewModelがあるとは限らない場合があるため、この場合は機能しないことです
。O

16
しかし、これにはすべてのコントローラーとすべてのアクションに{Name = "Bacon"}コードが含まれている必要があるのではないでしょうか。また、ViewModelBaseに別のプロパティを追加したい場合、すべてのコントローラーとすべてのアクションに移動し、そのプロパティを設定するコードを追加する必要がありますか?「必要なロジックがある場合は[...]これをベースコントローラに配置する必要があります[...]」すべてのコントローラーとすべてのアクションでこの繰り返しコードを排除するためにこれはどのように機能しますか?
リー

5
@Leeすべてのページで共通のデータである場合、これを配置するのはベースコントローラです。次に、コントローラーはこの基本コントローラーを継承します。例えばpublic class HomeController : BaseController。このようにして、共通コードは一度だけ作成する必要があり、すべてのコントローラーに適用できます。
Colin Bacon 14

73

レイアウトでかみそりにRenderAction htmlヘルパーを使用しました。

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

単純な文字列に必要でした。だから私の行動は文字列を返し、それをビューに簡単に書き留めます。ただし、複雑なデータが必要な場合は、PartialViewResultとモデルを返すことができます。

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

作成した部分ビュー '_maPartialView.cshtml'で始まるモデルを配置するだけです

@model List<WhatEverYourObjeIs>

次に、HTMLを使用して、その部分ビューでモデルのデータを使用できます。


18
これは断然最良の答えです!
gingerbreadboy

@gingerbreadboyは、カプセル化と懸念の分離を促進することに同意しました。
A-Dubb

35

別のオプションは、レイアウトに必要なすべてのプロパティを備えた別のLayoutModelクラスを作成し、このクラスのインスタンスをViewBagに詰め込むことです。Controller.OnActionExecutingメソッドを使用して、データを設定します。次に、レイアウトの開始時に、このオブジェクトをViewBagからプルバックして、この強く型付けされたオブジェクトに引き続きアクセスできます。


1
これは実際には最も痛みの少ない解決策のように聞こえますが、欠点はありますか?+1
formatc

2
間違いなく最良の解決策であり、私にはマイナス面は見られません。
Wiktor Zychla、2015年

7
これで何がもたらされるのかわかりません。レイアウトに必要なすべてのプロパティを備えたクラスがある場合、再度キャストする必要があるだけで、なぜそれをViewBagに追加する必要があるのでしょうか。レイアウトビューでモデルを使用しても、モデルをに読み込むことができますOnActionExecuting。ViewBagを使用することは、コントローラーのタイプセーフを失うことも意味し、決して良いことではありません。
コリンベーコン

3
これにより、既存のプロジェクトで、すべてのコントローラーのすべてのメソッドの単一の「スーパー」モデルから継承するためにすべてのモデルを再構築する必要なく、レイアウト用のモデルを追加できます。ゼロから始める場合は、代わりにすべてのモデルを共通のルートから派生させることを選択できます。
DenNukem

5
@ColinBaconこのオプションのもう1つの利点は、アクションが常にビューモデルを持っている必要がないことです。また、開発者は常にベースからビューモデルを継承する必要があることを知る必要があることは不利だと主張します。
Josh Noe

28

おそらく、これの主な使用例は、すべて(または大部分)のコントローラーアクションのビューに基本モデルを取得することです。

それを踏まえて、私はこれらの回答のいくつかを組み合わせて使用​​しました。主な便乗は、コリンベーコンの回答です。

ビューモデルにデータを入力してビューに戻るので、これは依然としてコントローラーロジックです。したがって、これを配置する適切な場所は、コントローラ内です。

これをレイアウトページに使用するため、すべてのコントローラーでこれが発生するようにします。レイアウトページでレンダリングされる部分ビューに使用しています。

強く型付けされたViewModelの追加の利点も必要です

したがって、私はBaseViewModelとBaseControllerを作成しました。すべてのViewModelsコントローラは、それぞれBaseViewModelおよびBaseControllerを継承します。

コード:

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

このSO投稿から取得したOnActionExecutedの使用に注意してください

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>

うまくいけば、これが役立ちます。


2
私はこのアプローチを使用しましたが、基本クラスではなくインターフェースからの継承を好みます。だから私はしました:var model = filterContext.Controller.ViewData.Model as IBaseViewModel if(model!= null){model.AwesomeModelProperty = "Awesome Property Value"; }
Tom Gerken、2016年

2
すばらしい答えです。私はこれを他のすべてよりも優先しました。
Jynn 2017

1
すばらしい答えですが、質問があります。「ViewModelsがないビューがある場合はどうなりますか?」
Isma Haro 2017

これを試してみましたが、インデックスアクションでは、OnActionExecutedがFooterModelを入力し、新しいHomeIndexModelがnull FooterModel:(
SteveCav

1
@drizzie:ベースコントローラでは、modelはFilterメソッドのローカル変数です:var model = filterContext.Controller.ViewData.Model as BaseViewModel。このローカル変数がHomeControllerが表示するために送信しているモデルと同じであることをMVCがどのように理解しているかはわかりません。
Hooman Bahreini 2017

9

アクションをいじったりモデルを変更したりする必要はありません。基本コントローラーを使用して、レイアウトビューのコンテキストから既存のコントローラーをキャストするだけです。

必要な共通データ(タイトル/ページ/場所など)とアクションの初期化を使用して基本コントローラーを作成します...

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

    protected override void OnActionExecuting(ActionExecutingContext filterContext) {

        MyCommonValue = 12345;

        base.OnActionExecuting(filterContext);
    }
}

すべてのコントローラーが基本コントローラーを使用していることを確認してください...

public class UserController:_BaseController {...

_Layout.cshmlページのビューコンテキストから既存のベースコントローラーをキャストします...

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

これで、レイアウトページからベースコントローラの値を参照できます。

@myController.MyCommonValue

更新

を使用できるようにするページ拡張を作成することもできます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;
}

次にthis.Controller()、コントローラが必要なときに使用することを覚えておけば十分です。

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

またはから継承する特定のコントローラ_BaseController...

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

.netコアでこれに相当するものは何ですか?ViewContext.Controllerが存在せず、継承チェーンにいくつかの変更があるため
Jayanth Thyagarajan

4

モデル全体を渡したい場合は、レイアウトで次のようにします。

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

これをコントローラーに追加します:

public ActionResult _Header(ViewAsModelBase model)

4

これらの回答のいずれも、大規模なエンタープライズレベルのアプリケーションに対して十分な柔軟性があるとは思いません。私はViewBagを使いすぎるのは好きではありませんが、この場合、柔軟性のために例外を設けます。これが私がすることです...

すべてのコントローラーに基本コントローラーが必要です。レイアウトデータOnActionExecutingをベースコントローラーに追加します(または、延期したい場合はOnActionExecutedです)...

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

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

次に、_Layout.cshtmlでViewModelをViewBagから取得します...

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

<h1>@model.Title</h1>

または...

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

これを行うことは、ページのコントローラーまたはビューモデルのコーディングに干渉しません。


私はあなたのアイデアが好きですが、MyLayoutViewModel動的に作成した場合はどうすれば、いくつかのパラメーターをOnActionExecutingメソッドに渡すことができますか?
Rajmond Burgaj 2017

1
ええと、あなたはまだbase.OnActionExecuting(filterContext)あなたのOnActionExecuting方法で必要です!!!
ErikE 2017

4

レイアウトビューモデルを表すベースビューを作成するのはひどいアプローチです。レイアウトで定義されたナビゲーションを表すモデルが必要だと想像してください。しますかCustomersViewModel : LayoutNavigationViewModel?どうして?ソリューションにあるすべての単一のビューモデルを通じてナビゲーションモデルデータを渡す必要があるのはなぜですか?

レイアウトビューモデルは、それ自体を専用にする必要があり、残りのビューモデルがそれに依存するように強制してはなりません。

代わりに、あなたの_Layout.cshtmlファイルでこれを行うことができます:

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

最も重要なことは、それを行う必要はなく、解決されたnew LayoutViewModel()すべての依存関係を取得LayoutViewModelすることです。

例えば

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

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

このモデルはどこに記入しますか?BaseControllerでも?
ndberg 2017年

これはScopedASP..Net Coreのレイアウトモデルオブジェクトにも適していると思います。
James Wilkins

私はビューに依存関係を取得させません。それは間違いなく「MVC」ではありません。Service Locatorはアンチパターンです。
Jiveman、2018

一般に信じられていることとは逆に、Service Locatorはアンチパターンではなく、実際にはこれはMVCとは関係ありません。blog.gauffin.org/2012/09/service-locator-is-not-an-anti-pattern
hyankov '21

その記事でのJgauffinの主なポイントは、少なくともいくつかの有効なSLの使用が存在する可能性があるため、「アンチパターン」という用語をService Locatorに適用すべきではないということです。公正なポイント。ただし、彼自身のディスカッションコメントの一部で明らかなように、ライブラリやフレームワークを構築する場合はSLが有効なアプローチである可能性がある一方で、アプリケーションを構築する場合は必ずしも推奨されるわけではないことを示唆しています(OPの質問とこのディスカッションは回転)。
Jiveman、2018年

3

他の回答では、モデルをレイアウトページに渡す方法に関するほとんどすべてをカバーしています。しかし、レイアウトでモデルや部分ビューを使用せずに、レイアウトページに動的に変数を渡す方法を見つけました。あなたがこのモデルを持っているとしましょう-

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

そして、都市と州を動的に取得したいとします。例えば

index.cshtmlでは、これら2つの変数をViewBagに配置できます

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

そして、あなたのlayout.cshtmlであなたはそれらのviewbag変数にアクセスできます

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

これはうまくいきます、@ stun_Gravy ViewBagを使用してロールやユーザーアクセスレベルなどのデータを渡すのに失敗はありますか?
3not3

3

これを処理する別の方法があります。おそらく、アーキテクチャの観点からは最もクリーンな方法ではありませんが、他の回答に伴う多くの苦痛を回避できます。Razorレイアウトにサービスを注入し、必要なデータを取得するメソッドを呼び出すだけです。

@inject IService myService

その後、後でレイアウトビューで:

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

繰り返しますが、アーキテクチャの点ではクリーンではありません(もちろん、サービスをビューに直接注入するべきではありません)が、それで仕事が完了します。


最もクリーンな方法ではないですか?同意しません。これは非常にクリーンだと思います。オブジェクトは、オブジェクトが作成された場所から希望の場所に直接渡されます。他のコントローラを、見る必要のないアイテムで「汚染」することはありません。@inject私の意見では、使用することが最善の解決策です。
dasblinkenlight

1
これについてもっと考えてみてください。この方法がそれほど多くの苦痛を回避するという事実は、おそらくそれが最もクリーンな方法であることを示しています。私は非常に大きなASP.NET Coreアプリで作業しており、ナビゲーションのパンくずロジック、ほとんどのページにあるヘッダーデータなどにこのパターンを使用しています。代わりにこの方法でそれを行うことにより、多くの苦痛を回避しました。
アンドリュー

2

RenderSectionを利用することもできます。これModelは、_Layoutビューにデータを注入するのに役立ちます。

あなたは、注入することができView Model、データ、JsonScriptCSSHTMLなど

この例ではJsonIndexビューからLayoutビューに注入しています。

Index.chtml

@section commonLayoutData{

    <script>

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

    </script>

    }

_Layout.cshtml

@RenderSection("commonLayoutData", false)

これにより、別個のBaseを作成する必要がなくなりView Modelます。

希望は誰かを助けます。


1
いくつかのビューに固有のレンダリングのみが必要な場合の完璧なソリューション。
Kunal

1

私がしたことは非常に簡単で、うまくいきました

任意のコントローラーで静的プロパティを宣言するか、次のようにしたい場合は静的値でデータクラスを作成できます。

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

これらの値は、操作に基づいてコントローラーによって更新できます。後で_Layoutで使用できます

_layout.cshtml

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

1
回答をより明確で理解しやすくするために、回答に説明を追加すると常に役立ちます。stackoverflow.com/help/how-to-answerをお読みください。
32cupo

0

ViewDataで拡張メソッドが提案されていないのはなぜですか?

オプション1

私にとっては、この問題に対する最も煩わしくなく、最も簡単な解決策のようです。ハードコードされた文字列はありません。課された制限はありません。魔法のコーディングはありません。複雑なコードはありません。

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

ページにデータを設定する

ViewData.SetTitle("abc");

オプション#2

フィールド宣言を簡単にする別のオプション。

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

ページにデータを設定します。宣言は最初のオプションより簡単ですが、使用構文は少し長くなります。

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

オプション#3

次に、それを組み合わせて、すべてのレイアウト関連フィールドとデフォルト値を含む単一のオブジェクトを返すことができます。

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

ページにデータを設定する

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

この3番目のオプションにはいくつかの利点があり、ほとんどの場合、私は最良のオプションだと思います。

  • フィールドとデフォルト値の最も簡単な宣言。

  • 複数のフィールドを設定する場合の最も簡単な使用法の構文。

  • ViewDataでさまざまな種類のデータを設定できます(レイアウト、ヘッダー、ナビゲーションなど)。

  • LayoutDataクラス内で追加のコードとロジックを許可します。

PS _ViewImports.cshtmlにViewDataExtensionsの名前空間を追加することを忘れないでください


0

App_Codeフォルダーにかみそりファイルを作成し、ビューページからアクセスできます。

プロジェクト> 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;
        }
    }
}

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

Project> Views / Shared / _Layout.cshtml(またはその他の.cshtmlファイル)

<div>
    @IdentityRepositoryViewFunctions.GetCurrentUserName
</div>

-1

これを通過する代わりに、常に高速な別のアプローチを使用できます

共有ディレクトリに新しい部分ビューを作成し、次のようにレイアウトで部分ビューを呼び出します

@Html.Partial("MyPartialView")

部分ビューでは、dbを呼び出して、やりたいことを実行できます

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

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

Entity Frameworkデータベースを追加したと仮定します


1
独自のモデルを取得することはビューの責任ではないため、ダウンキャスト。
オクソンハンマー2017

-1

ここでこれを誰も言ったことがないのは信じられないことです。ベースコントローラーを介してビューモデルを渡すのはごちゃごちゃです。ユーザークレームを使用して、レイアウトページに情報を渡します(ナビゲーションバーにユーザーデータを表示するためなど)。もう1つ利点があります。データはCookieを介して保存されるため、パーシャルを介して各リクエストのデータを取得する必要はありません。グーグルで「ASPネットIDクレーム」を実行してください。


@CodeSmithなに?ソリューションを提供しています。
makore

私の悪い、これは質問だと思ったが、削除されたので、今はそれが応答であることを確認してください。
CodeSmith

これが質問への回答の試みである場合は、それを明確にする必要があります。解説は許容されますが、回答全体を支配するべきではありません。また、Googleへのヒントは有効な回答にはなりません。
tripleee 2018

-6

次のように使用できます:

 @{ 
    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
ビューでデータベースに接続することは本当に悪い考えです。
1_bug 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.