Get Data From Database From MVC Shared View - c#

I have a shared _Layout.cshtml where I call the following #Html.Partial("TopMenu");
in TopMenu.cshtml I have an markup for website top menu.
<ul class="menu">
<li class="menu-item">menu item 1</li>
<li class="menu-item">menu item 2</li>
<li class="menu-item">menu item 3</li>
<li class="menu-item">menu item 4</li>
</ul>
I want to bind that menu from database.
I'm new to MVC. Should I create controller for that view?
This menu should be present in all of my pages. Give me an idea, how it's implemented in mvc. I'm from asp.net web forms country.
FUNCTION
public IEnumerable<Category> GetCategories(Guid? id)
{
return context.Categories.Where(c => c.CategoryID == id || !id.HasValue).ToList();
}
UPDATE
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public PartialViewResult TopMenu()
{
using (var ctx = new eventzEntities())
{
CategoryManager catMan = new CategoryManager(ctx);
var listOfCat = catMan.GetCategories(null);
return PartialView(listOfCat);
}
}
}
AND
#Html.Action("TopMenu","Home")
<div class="secondary-navigation">
<nav id="navigation">
<ul id="menu-main-navigation" class="menu sf-js-enabled">
#foreach (var cat in Model)
{
<li class="menu-item menu-item-type-taxonomy menu-item-object-category ">
#cat.CategoryName
</li>
}
...

Since all your views/pages will require this I suggest you create a base controller which will fetch the menu structure from the database and then provided it to all of your inheriting controllers. So for example you will make a base controller like this:
public class BaseController : Controller
{
public MenuModel Menu { get; set; }
protected override void Initialize(RequestContext requestContext)
{
// This get's your menu structure from the database via some service layer you need to create yourself.
// Keep in mind that this call will happen on every postback so if performance is an issue you might want to cache the menu in some way, maybe per user.
Menu = _menuServiceLogic.GetMenuItems();
ViewBag.Menu = Menu;
}
Once you have this then all your controller which generate views that contain the menu need to inherit from this base controller:
public class HomeController : BaseController
{
// Controller logic in here...
}
so now you have access to the menu on all of your controllers so all that is left is to pass it on to the view in some good way. I suggest you look into how to make a custom razor view class. There is a great article by Phil Haacked on this topic:
http://haacked.com/archive/2011/02/21/changing-base-type-of-a-razor-view.aspx
But in short every Razor view by default inherits from the System.Web.Mvc.WebViewPage. We are going to replace that class with our own implementation:
namespace YourApp.Website.Views
{
public abstract class CustomWebViewPage : WebViewPage
{
private MenuModel _menu;
public MenuModel Menu
{
get
{
try
{
_menu = (MenuModel)ViewBag.Menu;
}
catch (Exception)
{
_menu = null;
}
return _menu;
}
}
}
public abstract class CustomWebViewPage<TModel> : WebViewPage<TModel> where TModel : class
{
private MenuModel _menu;
public MenuModel Menu
{
get
{
try
{
_menu = (MenuModel)ViewBag.Menu;
}
catch (Exception)
{
_menu = null;
}
return _menu;
}
}
}
}
Now all you need to do is modify this line in your web.config:
<pages pageBaseType="System.Web.Mvc.WebViewPage">
to this:
<pages pageBaseType="YourApp.Website.Views.CustomWebViewPage">
and you can now do the following in your views in order to reference your menu:
#Menu
The Menu variable is strongly typed (in my example it's of type MenuModel) and you can access all the properties of your menu on every controller actions/views that inherits from your base controller.

You can do this by passing strongly typed model to the partial view _TopMenu
#model IEnumerable<Category>
<ul class="menu">
#foreach(var category in Model)
{
<li class="menu-item">#category.Category.Name</li>
}
</ul>
How to pass?
You will simply do it as below:
#Html.Action("TopMenu","ControllerName")
Here, controllerName is the name of the controller where you have defined this method. I recommend you keeping this controller away from other controllers. You can simply call it as a PageController or something.
Have no idea how it should work?
You will define a controller method that returns the partial view with strongly typed model as below:
public ActionResult TopMenu()
{
return PartialView(db.Categories.ToList());
}

You need to make sure the menu is a partial view then call
#Html.Partial("location/to/view", modeL)
and then in the view code it should be
#model someDataModel.Models.Thing
<ul class="menu">
<li class="menu-item">#Model.item1</li>
<li class="menu-item">#Model.item2</li>
<l
i class="menu-item">#Model.item3
#Model.item4
A good tutorial for this can be found here
http://mvc4beginner.com/Tutorial/MVC-Partial-Views.html
You do not need a controller necessarily for a partial view.
If you want that TopMenu to be a view then you need to get a controller made for that

You can store your menu items in a ViewBag and access it in your view.
So in your controller you will have this :
ViewBag.Menus = ...
And in your TopMenu.cshtml
<ul class="menu">
#foreach(string menu in ViewBag.Menus){
<li class="menu-item">#menu</li>
}
</ul>

Related

return View(model: MyModel); equivalent in ASP.Net Core Razor Pages

I expected to see something like return Page(model: MyModel); in ASP Razor Pages. instead the Page(); has no parameter.
So I can return Pages which does not have PageModel class.
I cant use TempData as MyModel is a complex type.
How do I get the same functionality we have with ASP MVC return View(model: MyModel);
Please, The question is not for all MVC developers but experienced ASP.Net Core Razor Page developers.
Thank you.
Ok here is an example from a simple Restaurant app.
As you can see the Restaurant object is a property inside the DetailModel. Once i set it inside the OnGet() method. I am able to access its data inside my Razor Page View.
public class DetailModel : PageModel
{
private readonly IRestaurantData restaurantData;
[TempData]
public string Message { get; set; }
public Restaurant Restaurant { get; set; }
public DetailModel(IRestaurantData restaurantData)
{
this.restaurantData = restaurantData;
}
public IActionResult OnGet(int restaurantId)
{
Restaurant = restaurantData.GetById(restaurantId);
if(Restaurant == null)
{
return RedirectToPage("./NotFound");
}
return Page();
}
}
and the view from the page.
#page "{restaurantId:int}"
#model MyProject.Pages.Restaurants.DetailModel
#{
ViewData["Title"] = "Detail";
}
<h2>#Model.Restaurant.Name</h2>
<div>
Id: #Model.Restaurant.Id
</div>
<div>
Location: #Model.Restaurant.Location
</div>
<div>
Cuisine: #Model.Restaurant.Cuisine
</div>
#if(Model.Message != null)
{
<div class="alert alert-info">#Model.Message</div>
}
<a asp-page="./List" class="btn btn-default">All Restaurants</a>
Really Razor pages work as one so you do not have to return the Model. You just bind it and you have access inside the page.
Does this makes sense?
Please also read the DOCS for more information: https://learn.microsoft.com/en-us/aspnet/core/razor-pages/?view=aspnetcore-3.1&tabs=visual-studio

Linking PartialView to View returns System.Web.Mvc.WebViewPage<TModel>.Model.get returned null

I looked up everywhere and tried multiple solutions but none of them would work. In my MVC website, I have a cart section and a checkout section. I want to make it so inside my checkout section, i have a small cart section to show the cart.
This is my partial view _CartItems.cshtml
#model IEnumerable<ArrowDefenseSystems.Models.Cart>
#{
ViewBag.Title = "Your Cart";
}
#if (Model != null)
{
foreach (var item in Model)
{
<div class="itemInfo row">
<img class="col-md-3" src="#Url.Content("~/Content/" + #Html.DisplayFor(modelItem => item.productImage))" height="100px">
<div class="CartItemText col-md-9">
<h3>#Html.DisplayFor(modelItem => item.productName)</h3>
<i>$#Html.DisplayFor(modelItem => item.productPrice)</i><br>
Quantity : #Html.DisplayFor(modelItem => item.quantityChosen)<br>
</div>
</div>
<hr />
}
}
When I launch the Partial View by itself, it shows the items fine and everything runs correctly.
This is how I'm linking the partial view to the view Checkout.cshtml
#model ArrowDefenseSystems.Models.ParentViewModel
...
...
#Html.Partial("_CartItems", Model.Cart)
When I run this code i get the following error on the code above:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
System.Web.Mvc.WebViewPage<TModel>.Model.get returned null.
ParentViewModel:
public class ParentViewModel
{
public Checkout Checkout { get; set; }
public Cart Cart { get; set; }
}
Checkout Controller (theres more but its unnecessary):
[HttpGet]
public ActionResult _CartItems()
{
return PartialView(db.Carts.ToList());
}
public ActionResult Checkout()
{
return View();
}
I've tried many solutions but all return the same error. What am I missing?
I think there is a fundamental misunderstanding here: #Html.Partial("_CartItems", Model.Cart) will not call your _CartItems() action. Instead, it will create a new instance of the _CartItems.cshtml partial view, and use your Model.Cart parameter as it's Model.
In this case, there are two problems:
_CartItems.cshtml is expecting a model with a type of IEnumerable<ArrowDefenseSystems.Models.Cart>, whereas you are passing it a model with a type of Cart (via the Model.Cart parameter)
Model.Cart is not being instantiated in your Checkout action
So, to fix this, you should first change your ParentViewModel to be:
public class ParentViewModel
{
public Checkout Checkout { get; set; }
public IEnumerable<Cart> Carts { get; set; }
}
Then, update your Checkout action to be:
public ActionResult Checkout()
{
var viewModel = new ParentViewModel
{
Carts = db.Carts.ToList()
}
return View(viewModel);
}
And change your usage of Model.Cart to Model.Carts (due to the rename above)
After that, you can remove your _CartItems action as it is no longer used.

How to separate ViewBag information that is common to multiple Controllers? [duplicate]

I have a website which have a layout page. However this layout page have data which all pages model must provide such page title, page name and the location where we actually are for an HTML helper I did which perform some action. Also each page have their own view models properties.
How can I do this? It seems that its a bad idea to type a layout but how do I pass theses infos?
If you are required to pass the same properties to each page, then creating a base viewmodel that is used by all your view models would be wise. Your layout page can then take this base model.
If there is logic required behind this data, then this should be put into a base controller that is used by all your controllers.
There are a lot of things you could do, the important approach being not to repeat the same code in multiple places.
Edit: Update from comments below
Here is a simple example to demonstrate the concept.
Create a base view model that all view models will inherit from.
public abstract class ViewModelBase
{
public string Name { get; set; }
}
public class HomeViewModel : ViewModelBase
{
}
Your layout page can take this as it's 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>
Finally set the data in the action method.
public class HomeController
{
public ActionResult Index()
{
return this.View(new HomeViewModel { Name = "Bacon" });
}
}
I used RenderAction html helper for razor in layout.
#{
Html.RenderAction("Action", "Controller");
}
I needed it for simple string. So my action returns string and writes it down easy in view.
But if you need complex data you can return PartialViewResult and model.
public PartialViewResult Action()
{
var model = someList;
return PartialView("~/Views/Shared/_maPartialView.cshtml", model);
}
You just need to put your model begining of the partial view '_maPartialView.cshtml' that you created
#model List<WhatEverYourObjeIs>
Then you can use data in the model in that partial view with html.
Another option is to create a separate LayoutModel class with all the properties you will need in the layout, and then stuff an instance of this class into ViewBag. I use Controller.OnActionExecuting method to populate it.
Then, at the start of layout you can pull this object back from ViewBag and continue to access this strongly typed object.
Presumably, the primary use case for this is to get a base model to the view for all (or the majority of) controller actions.
Given that, I've used a combination of several of these answers, primary piggy backing on Colin Bacon's answer.
It is correct that this is still controller logic because we are populating a viewmodel to return to a view. Thus the correct place to put this is in the controller.
We want this to happen on all controllers because we use this for the layout page. I am using it for partial views that are rendered in the layout page.
We also still want the added benefit of a strongly typed ViewModel
Thus, I have created a BaseViewModel and BaseController. All ViewModels Controllers will inherit from BaseViewModel and BaseController respectively.
The 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!";
}
}
Note the use of OnActionExecuted as taken from this SO post
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>
Mind Blown!
</li>
</ul>
</nav>
Hopefully this helps.
There's another way to handle this. Maybe not the cleanest way from an architectural point of view, but it avoids a lot of pain involved with the other answers. Simply inject a service in the Razor layout and then call a method that gets the necessary data:
#inject IService myService
Then later in the layout view:
#if (await myService.GetBoolValue()) {
// Good to go...
}
Again, not clean in terms of architecture (obviously the service shouldn't be injected directly in the view), but it gets the job done.
You don't have to mess with actions or change the model, just use a base controller and cast the existing controller from the layout viewcontext.
Create a base controller with the desired common data (title/page/location etc) and action initialization...
public abstract class _BaseController:Controller {
public Int32 MyCommonValue { get; private set; }
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
MyCommonValue = 12345;
base.OnActionExecuting(filterContext);
}
}
Make sure every controller uses the base controller...
public class UserController:_BaseController {...
Cast the existing base controller from the view context in your _Layout.cshml page...
#{
var myController = (_BaseController)ViewContext.Controller;
}
Now you can refer to values in your base controller from your layout page.
#myController.MyCommonValue
UPDATE
You could also create a page extension that would allow you to use 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;
}
Then you only have to remember to use this.Controller() when you want the controller.
#{
var myController = this.Controller(); //_BaseController
}
or specific controller that inherits from _BaseController...
#{
var myController = this.Controller<MyControllerType>();
}
I do not think any of these answers are flexible enough for a large enterprise level application. I'm not a fan of overusing the ViewBag, but in this case, for flexibility, I'd make an exception. Here's what I'd do...
You should have a base controller on all of your controllers. Add your Layout data OnActionExecuting in your base controller (or OnActionExecuted if you want to defer that)...
public class BaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext
filterContext)
{
ViewBag.LayoutViewModel = MyLayoutViewModel;
}
}
public class HomeController : BaseController
{
public ActionResult Index()
{
return View(homeModel);
}
}
Then in your _Layout.cshtml pull your ViewModel from the ViewBag...
#{
LayoutViewModel model = (LayoutViewModel)ViewBag.LayoutViewModel;
}
<h1>#model.Title</h1>
Or...
<h1>#ViewBag.LayoutViewModel.Title</h1>
Doing this doesn't interfere with the coding for your page's controllers or view models.
if you want to pass an entire model go like so in the 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>
and add this in the controller:
public ActionResult _Header(ViewAsModelBase model)
Creating a base view which represents the Layout view model is a terrible approach. Imagine that you want to have a model which represents the navigation defined in the layout. Would you do CustomersViewModel : LayoutNavigationViewModel? Why? Why should you pass the navigation model data through every single view model that you have in the solution?
The Layout view model should be dedicated, on its own and should not force the rest of the view models to depend on it.
Instead, you can do this, in your _Layout.cshtml file:
#{ var model = DependencyResolver.Current.GetService<MyNamespace.LayoutViewModel>(); }
Most importantly, we don't need to new LayoutViewModel() and we will get all the dependencies that LayoutViewModel has, resolved for us.
e.g.
public class LayoutViewModel
{
private readonly DataContext dataContext;
private readonly ApplicationUserManager userManager;
public LayoutViewModel(DataContext dataContext, ApplicationUserManager userManager)
{
}
}
Other answers have covered pretty much everything about how we can pass model to our layout page. But I have found a way using which you can pass variables to your layout page dynamically without using any model or partial view in your layout. Let us say you have this model -
public class SubLocationsViewModel
{
public string city { get; set; }
public string state { get; set; }
}
And you want to get city and state dynamically. For e.g
in your index.cshtml you can put these two variables in ViewBag
#model MyProject.Models.ViewModel.SubLocationsViewModel
#{
ViewBag.City = Model.city;
ViewBag.State = Model.state;
}
And then in your layout.cshtml you can access those viewbag variables
<div class="text-wrap">
<div class="heading">#ViewBag.City #ViewBag.State</div>
</div>
You can also make use of RenderSection , it helps to you to inject your Model data into the _Layout view.
You can inject View Model Data, Json, Script , CSS, HTML etc
In this example I am injecting Json from my Index View to Layout View.
Index.chtml
#section commonLayoutData{
<script>
var products = #Html.Raw(Json.Encode(Model.ToList()));
</script>
}
_Layout.cshtml
#RenderSection("commonLayoutData", false)
This eliminates the need of creating a separate Base View Model.
Hope helps someone.
Why hasn't anyone suggested extension methods on ViewData?
Option #1
Seems to me by far the least intrusive and simplest solution to the problem. No hardcoded strings. No imposed restrictions. No magic coding. No complex 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] ?? "";
}
Set data in the page
ViewData.SetTitle("abc");
Option #2
Another option, making the field declaration easier.
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;
}
}
Set data in the page. Declaration is easier than first option, but usage syntax is slightly longer.
ViewData.Title().Value = "abc";
Option #3
Then can combine that with returning a single object containing all layout-related fields with their default values.
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; } = "";
}
Set data in the page
var layout = ViewData.Layout();
layout.Title = "abc";
This third option has several benefits and I think is the best option in most cases:
Simplest declaration of fields and default values.
Simplest usage syntax when setting multiple fields.
Allows setting various kinds of data in the ViewData (eg. Layout, Header, Navigation).
Allows additional code and logic within LayoutData class.
P.S. Don't forget to add the namespace of ViewDataExtensions in _ViewImports.cshtml
The best way to use static strings such as page title, page name and the location etc, is to define via ViewData. Just define required ViewData in ViewStart.cshtml
#{
Layout = "_Layout";
ViewData["Title"] = "Title";
ViewData["Address"] = "1425 Lane, Skardu,<br> Pakistan";
}
and call whenever require like
<div class="rn-info-content">
<h2 class="rn-contact-title">Address</h2>
<address>
#Html.Raw(ViewData["Address"].ToString())
</address>
</div>
You could create a razor file in the App_Code folder and then access it from your view pages.
Project>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 (or any other .cshtml file)
<div>
#IdentityRepositoryViewFunctions.GetCurrentUserName
</div>
In .NET Core, you can use View Components to do this.
https://learn.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-5.0
From the link above, add a class Inheriting from ViewComponent
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents
{
public class PriorityListViewComponent : ViewComponent
{
private readonly ToDoContext db;
public PriorityListViewComponent(ToDoContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db.ToDo.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
}
Then in your view (_layout in my case)
#await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })
If you need a view, make a folder at ~/Views/Shared/Components/<Component Name>/Default.cshtml. You need to make the folder Components then in that, make a folder with your component name. In the example above, PriorityList.
instead of going through this
you can always use another approach which is also fast
create a new partial view in the Shared Directory and call your partial view in your layout as
#Html.Partial("MyPartialView")
in your partial view you can call your db and perform what ever you want to do
#{
IEnumerable<HOXAT.Models.CourseCategory> categories = new HOXAT.Models.HOXATEntities().CourseCategories;
}
<div>
//do what ever here
</div>
assuming you have added your Entity Framework Database
what i did is very simple and it's works
Declare Static property in any controller or you can make a data-class with static values if you want like this:
public static username = "Admin";
public static UserType = "Administrator";
These values can be updated by the controllers based on operations.
later you can use them in your _Layout
In _layout.cshtml
#project_name.Controllers.HomeController.username
#project_name.Controllers.HomeController.UserType
It's incredible that nobody has said this over here. Passing a viewmodel through a base controller is a mess. We are using user claims to pass info to the layout page (for showing user data on the navbar for example).
There is one more advantage. The data is stored via cookies, so there is no need to retrieve the data in each request via partials.
Just do some googling "asp net identity claims".
You can use like this:
#{
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)
{
#item.Name
}
</div>
</div>
</div>
</div>

PartialView with a ViewModel on _Layout.cshtml

I have a layout page which has a partial view. The partial view needs to loop through a property on the view model to show a list of categories. When a category is displayed I need to show a list of documents in that category. /Home/Index works, but when I try to view /Documents/Category/{id}, I get an error:
Additional information: The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[ViewModels.DocumentViewModel]', but this dictionary requires a model item of type 'ViewModels.HomeViewModel'.
_Layout.cshtml
...
<body>
#Html.Partial("_CategoryViewModel")
<div class="content">
#RenderBody()
</div>
HomeViewModel.cs
public class HomeViewModel {
...
public ICollection<DocumentCategory> Categories { get; set; }
public ICollection<Documents> Documents { get; set; }
...
}
_CategoryViewModel.cshtml (this should show a list of all categories)
#model ViewModels.HomeViewModel
...
#foreach (DocumentCategory item in Model.Categories)
{
<li>
<a href="#Url.Action("Category", "Documents", new { #id = #item.CategoryId })" title="View documents in the #item.Name category">
<span class="fa fa-files-o"></span> #item.Name
</a>
</li>
}
DocumentsController.cs
public ActionResult Category(int id)
{
var thisCategory = _ctx.Categories.Get(c => c.CategoryId == id).FirstOrDefault();
IEnumerable<DocumentViewModel> docs = null;
if(thisCategory == null)
{
TempData.Add("errorMessage", "Invalid category");
} else {
docs = thisCategory.Documents.ToList();
}
return View("Category", docs);
}
What's happening kind of makes sense - the PartialView on the Layout page needs to enumerate over a collection which isn't present in the ViewModel I'm using. I have no idea how to achieve this - the only way would seem to be to add a Categories property to every ViewModel in my site.
By default, using #Html.Partial() will pass the current model to the partial view, and because your Category.cshtml view uses #model List<DocumentViewModel>, then List<DocumentViewModel> is passed to a partial that expects HomeViewModel.
If you want to render a partial view for HomeViewModel on every page, then use #Html.Action() to call a ChildActionOnly method that returns the partial
[ChildActionOnly]
public ActionResult Categories
{
var model = new HomeViewModel()
{
.... // initialize properties
}
return PartialView("_CategoryViewModel", model)
}
and in the layout
#Html.Action("Categories", yourControllerName)
// or
#{ Html.RenderAction("Categories", yourControllerName); }
As I see it you have a few different alternatives.
1. Use Html.Action and create an Action that returns your view.
#Html.Action("Index", "Category") // Or your controller name.
I believe that there are some performance draw-backs with this approach because the whole MVC lifecycle will run again in order to render the result of the action. But then you can render the result of an action without having the correct model in the view that called it.
One may also argue that this breaks the MVC pattern, but it might be worth it.
2. Use a generic model (or an interface) in your _Layout.cshtml, and let your viewmodels inherit from that model.
In your _Layout.cshtml:
#model IBaseViewModel
And let all your viewmodels implement this interface.
public interface IBaseViewModel
{
ICollection<DocumentCategory> Categories { get; set; }
}
public interface IBaseViewModel<T> : IBaseViewModel
{
T ViewModel {get; set;}
}
Since you're placing #Html.Partial("_CategoryViewModel") in _Layout.cshtml I assume that it should be visible in all pages, so I think it's logical that all the controllers that are using _Layout.cshtml make sure that it gets the information it needs, and thus adding Categories to the model.
I use this approach all the time for stuff like breadcrumbs and menu-information (stuff that is used in all pages). Then I have a basecontroller that makes sure that Categories is populated with the correct info.

ASP.NET MVC passing several data instances from controller to view

I'm trying to build an ASP.NET MVC 2 application. I want to pass data to a view from a controller. I am able to pass it when it is only a single data structure. In the controller:
private ArticlesDBEntities _db = new ArticlesDBEntities();
public ActionResult Articles()
{
return View(_db.ArticleSet.ToList());
}
and in the view, I iterated over the list like so:
<div id="demo1">
<% foreach (var item in Model) { %>
<ul>
<li id="<%= Html.Encode(item.Id) %>">
<%= Html.Encode(item.Title) %>
<ul>
<li id="phtml_2">
Child node 1
</li>
<li id="phtml_3">
Child node 2
</li>
</ul>
</li>
</ul>
<% } %>
</div>
(the child nodes are for testing reasons right now, don't have a real role)
However, I now want to handle a scenario when a user tries to access Home/Articles/Id, and not only pass the article list (used for populating a jsTree), but also the Article itself, so I can show it as well. However, when I tried creating a ViewData object like so:
public ActionResult Articles()
{
ViewData["articlesList"] = _db.ArticleSet.ToList();
return View();
}
I was unable to find out how to iterate over it in the view.
as far as passing multiple data items is concerned u can do it using view models (preferred way) or by viewdata. if u want to pass it through View model u can do something like
public class ArticlVM
{
public Article Myarticle{get;set;}
public IEnumerable<ArticleSet> Artcileset{get; set;}
}
u can populate this view model and pass it to view
in view u can access it like
<%=Model.Article.articlName%>
<%=Model.Article.articlDescription%>
<%foreach(var m in Model.Articleset){%>
<label><%=m.Property1%></label>
<%}%>
to iterate over ViewData["key"] u have to cast it to corresponding object like
<%=foreach(var m in (ArticleSet)ViewData["Articles"]){%>
<label><%=m.Property1%></label>
<%}%>
In your View you should be able to do
<% foreach(var item in ViewData["articlesList"]) %>
An alternative approach would be to create a new view model class that would hold both the article and the list:
class ArticleViewModel {
public Article Article { get;set;}
public IEnumerable<Article> Articles { get;set;}
}
and pass that into your view. Then you can access it through the Model property and you will get strong typing.

Categories