in the asp.net when i used masterpages i can use masterpage code behind to run share codes .
in the MVC how can i do it . all pages use layout.cshtml but there isn't any share controller .
in my layout i have some datas that must load from database but there isn't anywhere to write these code and fill viewbag to send data to layout.cshtml
<div class="page">
<header >
<div id="title">
<h1>Management</h1>
</div>
<div id="logindisplay">
#Html.Partial("_LogOnPartial")
</div>
<br />
<br />
<nav>
<ul id="menu">
// these data must load from db
</ul>
</nav>
</header>
<section id="main">
#RenderBody()
</section>
<footer>
</footer>
</div>
In the shared directory you put all your files (like master pages and partial views) that will be used across your web application, hopefully in a situation where they are used more than once (for partial views). There is not a shared controller, but you could create a CommonController that can handle stuff like your menu.
I don't know what other data you need to display in your view, but looking at your example it seems like you want to display menu items in a ul tag.
I would have a class that would represent a menu item like:
public class MenuItem
{
public int MenuId { get; set; }
public string MenuName { get; set; }
}
I always create a view model for each view. This is better because then you have only the fields that are required on the view. Never send your domain objects to the view directly.
A view model would look something like this, it can contain many other properties, but for this demo I will only include the meu items.
public class MyViewModel
{
// This will contain the menu items that you want displayd in your view
public IEnumerable<MenuItem> MenuItems { get; set; }
}
You action method (in a controller called something like CommonController):
public ActionResult MyActionMethod
{
MyViewModel viewModel = new MyViewModel
{
// Here you do a database call to populate your menu items
// This GetAllMenuItems method returns a list of MenuItem objects
MenuItems = menuItemService.GetAllMenuItems()
};
return View(viewModel);
}
Create a partial view that will get its data from CommonController (you need to create this with the action method above). Loop through each MenuItem in MenuItems and display the name in a li tag.
<ul>
#foreach (var item in Model.MenuItems)
{
<li>item.MenuName</li>
}
</ul>
I hope this helps. The rest I leave up to you do the rest and read up on more articles. There is many info on the internet that describes what you want to do. You just need to invest in time to read these articles.
There are a couple of options. You can either use a partial view (with it's own controller and view model) or you can use a base controller. With a base controller, each controller would use it as an ancestor and you can use the base controller to load common data elements.
I know this post is old but I was having the same problem suddenly I got that we can easily access VB in Layout form using Razor I am working with vb. You can modify this code for c#. I am using #Imports System.Data.SqlClient. This code is working perfectly for me and I want exactly what you describe
<li class="treeview">
<a href="#">
<i class="fa fa-indent"></i>
<span>Transaction</span> <i class="fa fa-angle-left pull-right"></i>
<span class="label label-primary pull-right"></span>
</a>
<ul class="treeview-menu scrollbar">
#Code
Using conn As New SqlConnection(connectionString)
Dim sSql = "SELECT * FROM SM_OBJECT_INFO WHERE menu_name = 'Transaction' Order By group_index, index_no"
Dim formname As String
Dim formtitle As String
Dim cmd As SqlCommand = New SqlCommand(sSql, conn)
conn.Open()
Dim rst As SqlDataReader = cmd.ExecuteReader
Do While rst.Read()
formname = rst!form_name
formtitle = rst!object_name
#<li><a href=#formname>#formtitle</a></li>
Loop
End Using
end code
</ul>
</li>
This article worked for me-- below i am writing in details-
In the shared directory you put all your files (like master pages and partial views) that will be used across your web application, hopefully in a situation where they are used more than once (for partial views). There is not a shared controller, but you could create a CommonController that can handle stuff like your menu.
I don't know what other data you need to display in your view, but looking at your example it seems like you want to display menu items in a ul tag.
I would have a class that would represent a menu item like:
public class MenuItem
{
public int MenuId { get; set; }
public string MenuName { get; set; }
}
I always create a view model for each view. This is better because then you have only the fields that are required on the view. Never send your domain objects to the view directly.
A view model would look something like this, it can contain many other properties, but for this demo I will only include the meu items.
public class MyViewModel
{
// This will contain the menu items that you want displayd in your view
public IEnumerable<MenuItem> MenuItems { get; set; }
}
You action method (in a controller called something like CommonController):
public ActionResult MyActionMethod
{
MyViewModel viewModel = new MyViewModel
{
// Here you do a database call to populate your menu items
// This GetAllMenuItems method returns a list of MenuItem objects
MenuItems = menuItemService.GetAllMenuItems()
};
return View(viewModel);
}
Create a partial view that will get its data from CommonController (you need to create this with the action method above). Loop through each MenuItem in MenuItems and display the name in a li tag.
<ul>
#foreach (var item in Model.MenuItems)
{
<li>item.MenuName</li>
}
</ul>
I hope this helps. The rest I leave up to you do the rest and read up on more articles. There is many info on the internet that describes what you want to do. You just need to invest in time to read these articles.
This is very useful article to achieve asp.net master page functionality in MVC. i.e. if we want a functionality which is common for every page[ every controller/view in MVC] need to follow this article steps.
I faced once problem which is not mentioned in this article going to share below-
When we will create partial view which will be called on _layout page for being share in every view.. we hare to write -
#{Html.RenderAction("BindMenu", "Common");}
on _Layout page.
Since I was newbie and i wast trying to call partial view like-
#Html.Partial("~/Views/Shared/_HeaderMenuPartial.cshtml", Model.MenuItemsList)
which was not working.
Related
I have a 2-level menu item: I have a list of department and each department has a list of stores.
I have a Menu, PartialView which iterates through the Model (departments) and builds the menu:
#model IEnumerable<Department>
<ul>
#foreach (var department in Model)
{
<li>
#Model.DepartmentName
<ul>
#foreach (var store in department.Stores)
{
<li>#store.StoreName</li>
}
</ul>
</li>
}
</ul>
And this is how I call the Menu PartialView in my _layout.cshtml:
#Html.Partial("Shared/_Menu", MyApplicationCache.departments)
As you can see I am passing the same model (from the cache) to the PartialView on all the requests.
Does Razor ViewEngine have an internal caching system to recognize that this view has already been built (complied to HTML string) for this model? Or does it re-render (recompile) the PartialView on every single request?
The PartialView gets re-rendered at every single request, assuming you don't have any OutputCacheAttribute applied on the Controller or its action method involved.
If you need output caching, you need to set this up explicitly via OutputCacheAttribute, see the documentation.
You can easily check this by outputting a DateTime, eg. via a menu-item as shown here below.
At every request, it will show a new value, proving it got re-rendered.
<li>#DateTime.Now</li>
Full menu:
#model IEnumerable<Department>
<ul>
#foreach (var department in Model)
{
<li>
#Model.DepartmentName
<ul>
<li>#DateTime.Now</li>
#foreach (var store in department.Stores)
{
<li>#store.StoreName</li>
}
</ul>
</li>
}
</ul>
Re-Rendering and Re-Compiling are very very different in ASP.Net MVC. While most of the answers here are correct, the View is only compiled once (except in debug mode, where it's compiled each time so you can change the view, hit refresh and see the change, or if the timestamp changes on the file in production). It is compiled into a runtime class that derives from WebViewpage(no ViewModel) or WebViewPage<T>(has ViewModel of type T).
The class is instantiated for each view needed (so if you used the same partial multiple times, you have to instantiate the each time), the model is populated, and the execute() method is called to create/stream the HTML to the client. The view could never be cached per model as it is to complicated to do that and instead the MVC team chose to allow configuring caching per controller method, not per WebViewPage.
#ErikPhilips, thanks a lot for this - So the View is only compiled once (no matter if we use or not use OutputCache)? It's the execute method which renders the runtime class into HtmlString, and it is the rendering which would benefit from caching?
Sorta of, but it's much more advanced, easier and complicated then that.
Advanced - The output cache is based on the controller method. So if the output cache configuration determines that the call can use a cached version, the controller method is never called. That's where the huge performance gain is. Imagine no call to the DB / external API call, there isn't a need. You could configure the cache so if it sees id=1 cache it for 30 minutes. Now anyone who calls that method with authorization and id=1 gets the cached string/html.
Easier - You put your OuputCacheAttribute on a method, configure it and you're done. Pretty darn easy to configure.
Complicated - Caching can be more complicated because you can render other controller methods using Html.Action() (Html.Partial() if you don't need a layout for your partial) or the preferred Html.RenderAction(); (Html.RenderPartial() if you don't need a layout). There use to be a Donut Hole Caching Issue (recommended reading) but that's been fixed for a long time.
This question has a great answer, which proves PartialViews are not cached, and this link which is suggested in the comments explains how to use [OutputCache] for a partialView - this could be used with Html.Action() / Html.RenderAction() and renders PartialViews as a [ChildAction].
Caching PartialView as a child action makes sense, but I did not want to render my menu as a [ChildAction], because I did not want to make a separate call for displaying the menu, so this is what I ended up doing:
I used RazorEngine to render my PartialView into HtmlString on application Startup, and will keep the HtmlString in a static variable (cache).
public static class MenuCache
{
private static readonly MvcHtmlString _menuMvcHtmlString;
static MenuCache()
{
using (var context = ApplicationDbContext.Create())
using (var razorEngine = RazorEngineService.Create(new TemplateServiceConfiguration()))
{
var repository = new MyRepository(context);
var departments = repository.GetDepartments();
// use razorEngine to render menu partial view into html string
// keep the htmlString in cache: _menuMvcHtmlString
string menuPartialView = File.ReadAllText(HostingEnvironment.MapPath("~/Views/Shared/_Menu.cshtml"));
string menuHtmlString = razorEngine.RunCompile(menuPartialView, "menuKey", null, departments);
_menuMvcHtmlString = new MvcHtmlString(menuHtmlString);
}
}
public static MvcHtmlString GetMenuHtmlString()
{
return _menuMvcHtmlString;
}
}
I also created a Customized HtmlHelper method which would return the HtmlString for the menu:
public static class HtmlHelperExtensions
{
public static MvcHtmlString MyMenu(this HtmlHelper html)
{
return MenuCache.GetMenuHtmlString();
}
}
Now in my _Layout page, I can use the customized HtmlHelper to display the menu:
#Html.MyMenu()
I have navbar elements in my _Layout.cshtml which depend on the controller being called. On a search page there will be no navigation but in order to keep the style of the site consistent the navbar itself will remain. I'm not sure what is the most accepted and idiomatic way of performing this work.
_Layout.cshtml
(etc)
<nav>
<div class="container">
<ul>
#if (TempData.ContainsKey(KeyChain.ItemKeyTempDataKey))**
{
var itemKey = TempData[KeyChain.ItemKeyTempDataKey] as ItemKey;
<li>#Html.ActionLink("Overview", "Index", "Overview", itemKey, new { })</li>
<li>#Html.ActionLink("Purchasing", "Index", "InvoiceMovementHistory", itemKey, new { })</li>
<li>#Html.ActionLink("Profit Trends", "Index", "SalesMovement", itemKey, new { })</li>
<li>#Html.ActionLink("Coupons", "Index", "Coupon", itemKey, new { })</li>
<li>#Html.ActionLink("Deals", "Index", "WebDeal", itemKey, new { })</li>
<li>#Html.ActionLink("Update Log", "Index", "UpdateLog", itemKey, new { })</li>
}
</ul>
</div>
</nav>
(etc)
ItemKey.cs
public class ItemKey
{
public string Upc { get; set; }
public string VendorItemCode { get; set; }
public int Vendor { get; set; }
}
UpdateLogViewModel.cs
public class UpdateLogViewModel
{
public IEnumerable<UpdateLogEntryViewModel> UpdateLogEntries { get; set; }
}
UpdateLogController.cs
public ActionResult Index(ItemKey itemKey)
{
TempData[KeyChain.ItemKeyTempDataKey] = itemKey;
//etc uses itemkey to get data in order to generate updateLogViewModel
return updateLogViewModel();
}
Things I thought of
Using TempData (as above) to display the navbar elements if the itemkey is populated. TempData, however, is kind of on its way out and feels hacky.
Add a rendersection to the navbar, put the navbar elements in a renderaction and populating them in the section on every view that uses it (which is essentially every view EXCEPT the search view). This just violates DRY on overdrive, but seems to me to be the idiomatic thing.
Derive a secondary sublayout that is an "itemlayout", which would be typed to itemkey and drops the tempdata check. At least provides compile-time checking as long as developers use the itemlayout for item subscreens. But, call me crazy, that's worse because now all of my derived view's viewmodels have to depend on the type from the itemlayout viewmodel. However, this has the advantage of making the dependency clear: if you're going to use this layout, you must derive from this viewmodel that contains an itemkey property. This seems like the most idiomatic way, but I hate the idea of a typed layout.
Move the navbar on to every view page. I will almost certainly not do this, but it should be mentioned that the possibility exists.
So, is there another way I could perform this action idiomatically in MVC, or is one of the options I've listed above the preferred method?
TempData is a bad way to send data around in an ASP.NET MVC application. It's a holdover from the Viewstate days. It's a bad idea.
Instead of TempData, you can make your Navbar a RenderAction, and pass it information from each page it appears on (from the view). You can also use an HtmlHelper (outlined below) to render the links. There's no sense in having all this cooped up in the Layout.cshtml, since it'll have code that doesn't apply to it.
Effectively what you're trying to do is show the active page in a different style.
There are quite a few ways of doing that.
Highlighting current page ASP.NET MVC
Highlighting current page in navigation ASP.NET MVC
And K. Scott Allen has a blog post about the various methods he uses.
All of this tricks have one thing in common: They all suggest using an HTMLHelper that simply looks at the current page.
The most natural and canonical way to do this in MVC is by overriding partials. Create a specific controller called SearchController.
Then, create a partial called _Navigation.cshtml in your "Views\Shared" folder, like this:
<nav>
<div class="container">
<ul>
<li>...</li>
<li>...</li>
<li>...</li>
</ul>
</div>
</nav>
And then, in "Views\Search" create another partial called _Navigation.cshtml like this:
<nav>
<div class="container">
<p>Nothing to see here.</p>
</div>
</nav>
Then, in your layout, when you do this:
#Html.Partial("_Navigation")
The precedence of the view resolver will pick up the latter on the search page and the former everywhere else.
Edit: Based on what I can gather from your comments and updates, you have a controller action that receives some values in the query string and you want to persist those in your action links. The answer is easy.
Assuming the URL /UpdateLog?Upc=xyz&VendorItemCode=abc&Vendor=1 hits your UpdateLog.Index action, then in your view, your links just need to be, e.g.:
#Html.ActionLink("Purchasing", "Index", "InvoiceMovementHistory")
If InvoiceMovementHistory.Index also accepts those parameters, the MVC framework will automatically map the current route parameters to the target route when it is generating the link. No need for you to manage the values at all.
If they're not query string parameters but URL segments, the same applies.
This stateless passing of context from request to request via GET parameters is the ultimate "idiomatic" way of doing this sort of thing in MVC and on the web in general.
Use this in conjunction with the view overriding I described above and you have a very easy way of doing this and switching the nav off for specific pages. That said, given the emerging clarity I would forego the partials and just check a ViewBag.DisableNav property in your layout:
#if (!ViewBag.DisableNav)
{
<nav>
<div class="container">
<ul>
<li>#Html.ActionLink("Purchasing", "Index",
"InvoiceMovementHistory")</li>
<li>...</li>
<li>...</li>
</ul>
</div>
</nav>
}
I am creating a voting mechanism for my MVC application. user will be able to vote only after loged in. I have totally 3 tables tblQuestions(to populate the questions), tblAnswers(to populate the answers), tblQuestionAnswerUserResponses (to populate the user response.)tblAnswers have relation with tblQuestions. I have used the following code in the container in the HttpGet. This is my controller code.
[HttpGet]
[ActionName("VotingResult")]
public ActionResult VotingResult(int personid)
{
List<Voting_Questions> QuesList = EpDObj.PopulateQuestions(); //Populate the list of questions
CountofQuestionsDisplayed = QuesList.Count;
ViewBag.Questions = QuesList; // Storing the list of questions in the viewbag
List<Voting_Answers> Answers = EmcObj.Voting_Answers.ToList(); //Populate the list of answers
return View(Answers);
}
I am using the Voting_Answers as model in my view My view is
#model IEnumerable<EmployeeManagementDAL.Voting_Answers>
<h2>VotingResult</h2>
#using (Html.BeginForm())
{
<div>
#foreach (var a in ViewBag.Questions)
{
<h4>#a.Questions</h4>
<div>
#foreach (var b in Model)
{
if (b.QuestionsID == a.id)
{
#Html.RadioButton(b.AnswersOptions, new {Answerid= b.id, Questionid=a.id }) #b.AnswersOptions
}
}
</div>
}
</div>
<br/>
<div >
<input type="submit" value="Vote Now!!" onclick="return confirm('Are you sure you want to submit your choices?');"/>
</div>
}
When the user go to this page for the very first time there will be no options selected. after selecting the options the values an clicking Save button will save the details to the third table and then he comes out of that page. Now if for the second time he reaches that page for editing, I want my page to render with those values in my tblQuestionAnswerResponses i.e I guess my model class of tblQuestionAnswerResponses to be used. In that case can i use the same page for both cases i.e when the user vists the page for first time and also when second time the page is visited. Can I use multiple Model in MVC based on conditions in my View.
Your ActionName attribute is unnecessary, as you have specified the same name that your action already has.
It would be cleaner to use a ViewModel instead of using the ViewBag. For starters, you'll get strong typing in your view, and it will also lend itself to easier testing.
If you make a ViewModel that represents what you want your view to display, then you can map back and forth between it and your domain models in your controller actions, and let them do the heavy lifing.
I have a model with various properties but the one of interest is a List of another type of Model.
For example:
public class User
{
public string Name { get; set; }
public string Description { get; set; }
public IEnumerable<UserInterest> Interests { get; set; }
}
I then use an Editor Template within my view to render out a view for each item of the model items.
#Html.EditorFor(x => x.Interests)
The EditorFor template looks something like:
#model Interest
<div>
#Html.HiddenFor(x => x.Id)
#Html.TextBoxFor(x => x.InterestText)
#Html.CheckBoxFor(x => x.Delete)
....
</div>
Something very similar to the accepted answer here: Model Containing List of Models (MVC-3, Razor)
My question is - how would you from the client-side (jQuery) create a new item within the property without going back to the server. I currently have a rough way of doing it whereby I post the data back to my controller which returns the model back with a new blank item within the Interests property.
This seems to be overkill making a HTTP request and not very elegent. I was thinking of using jQuery .Clone() but not entirely sure on what I'd need to do in terms of naming the elements and clearing existing values.
So does anybody have any suggestions. I'm hoping to get more opinions and different approaches.
You can simply create the Textbox and checkbox on the fly and add that to the DOM. When saving it, Use jQuery ajax to post that data ( new record data) to an action method and save it there. Return a status back (Succcess /Falied) from your action method to your client side code ( your callback function of jQuery ajax/post) and check it there. If it is success, Show a success message to the user and append the new item to the existing list.
Sample jSFiddle : http://jsfiddle.net/carwB/2/
If you want to return some complex data ( ex : All new records with its id etc..) along with the status, you may return JSON from your action method.
EDIT : To keep your Model binding works with the newly added dynamic elements, you need to follow the naming convention of the elements.
The trick is to keep the id property value of the html element in this format.
CollectionName_ItemIndex__PropertyName
and name property value in this format
CollectionName[ItemIndex].PropertyName
I created a sample working program and explained it how it works Here based on your requirements.
In such situations I prefer to use client templating. You send data to server with ajax and then receive JsonResult. Look at JsRender this is javascript lib without jQuery dependency.
1.Create two partial view one is for list item and second one is creation
2.First partail view should be inside the div which has id 'divMdeolList'
3.and Creation view will have the code like that
#using (Ajax.BeginForm("SubmitData", new AjaxOptions { UpdateTargetId = "divMdeolList" }))
{
#Html.TextBoxFor(x => x.InterestText)
<p>
<input type="submit" value="Create" />
</p>
}
4. And then create a ActionResult type action on controller that will render the partialview
public ActionResult SubmitData(YourModel model)
{
//Do : save the record
return PartialView("FirstPartailView", model);
}
This will update the View without postback
I build my web site using asp.net mvc3, layout is 2 columns, main content with sidebar.
I create a section for sidebar. this sidebar will show top 10 articles. what I did right now is to query the top 10 articles on every controller.
is there a way to do it in one place and using it on all controllers?
You can do this using Html.RenderAction([methodname], [controllername]). So in your _Layout.cshtml, you might end up with something like:
<div id="content">
#RenderBody()
</div>
#{ Html.RenderAction("ShowTopArticles", "Article"); }
Then in your ArticleController:
private readonly int MaxArticles = 10;
[ChildActionOnly]
public PartialViewResult ShowTopArticles()
{
var model = articleRepository.GetTopArticles(MaxArticles);
return PartialView(model);
}
Marking the action with the attribute ChildActionOnly means it can only be invoked by a call to Html.Action() or Html.RenderAction().