I have a masterpage called _Layout.cshtml and placed in the folder Views/Shared/_Layout.cshtml.
I created a controller: SharedController.cs to pass data to _Layout.cshtml
but does not enter into the controller.
How can I pass data to each load masterpage _Layout.cshtml?
This is the controller for example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace HAnnoZero.Controllers
{
public class SharedController : Controller
{
public ActionResult _Layout()
{
ViewBag.help = "ciao";
return View();
}
}
}
First, don't call it a master page. That's from Web Forms. In MVC, _Layout.cshtml is a "layout". That may seem like semantics, but it's important to differentiate because in Web Forms, the master page is a true page in it's own right, with it's own code behind. In MVC, a layout is only an HTML template with some placeholders. The controller, and specifically the action of the controller that was requested, is solely responsible for the page context. That also means you can't have a _Layout action that adds context to the layout because that action is not being called, and even if you did (by going to a URL like /Shared/_Layout in your browser, it would fail when loading _Layout.cshtml as a view, because it needs a superficial view to fill in the call to #RenderBody().
If you want to render something with its own context in your layout, then you must use child actions:
Controller
[ChildActionOnly]
public ActionResult Something()
{
// retrieve a model, either by instantiating a class, querying a database, etc.
return PartialView(model);
}
Something.cshtml
#model Namespace.To.ModelClass
<!-- HTML that utilizes data from the model -->
_Layout.cshtml
#Html.Action("Something", "ControllerSomethingActionIsIn")
Another way is creating a common base controller that other controllers inherit from:
public abstract class BaseController : Controller
{
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
filterContext.Controller.ViewBag.Title = "Hello world";
}
}
public class SharedController : BaseController
{
...
}
Then in _layout you just use:
<title>#ViewBag.Title</title>
Layout pages do not work this way. The view returned by your action is rendered within a _Layout page when using a default MVC project.
See here for more of an introduction to _Layout pages.
One way to display information in a _Layout page is to use a child action method which is called from the _Layout page.
For example, the _Layout.cshtml may contain a call similar to:
#Html.Action("GetNews", "Home", new { category = "Sports"})
And then you would have a controller action similar to:
[ChildActionOnly]
public ActionResult GetNews(string category)
{
....
}
Related
I am using ASP.Net MVC 5 for web development. I have added many Views and they are working. But if I try to add a new View, it cannot be navigated by browser i.e. 404 error occurred. But the rest of the Views are working correctly.
I tried to add new Views in distinct controllers but they have the same problem.
Please help me to solve this issue.
Created a new view in MVC 5, opening the new view results in HTTP 404
You should be accessing the view through an action method. So If you
created your new view in ~/Views/Home/AboutMe.cshtml, You should add
an action method like this in your HomeController.
public class HomeController : Controller
{
public ActionResult AboutMe()
{
return View();
}
}
Now you can access this like
http://yourServerName/yourAppName/Home/AboutMe
If you want to have your action method in a different controller, You
can specify the full view path. Ex : IF you want to add the action
method to your Account controller,
public class AccountController : Controller
{
public ActionResult AboutMe()
{
return View("~/Views/Home/aboutme.cshtml");
}
}
I have this controller:
public class BaseController : Controller
{
public ActionResult Index(string controller)
{
TemplateMasterModel model = new TemplateMasterModel()
return View(model);
}
}
I created a view for baseController Index Action
It is located in Views/Base/Index.cshtlm
code:
#model Reports.Models.TemplateMasterModel
#{
ViewBag.Title = #Model.Title;
Layout = "~/Views/Shared/_Layout.cshtml";
}
#Html.Partial("TemplateRptMaster",Model)
#section scripts{
#Scripts.Render("~/bundles/rptFormSubmit")
}
I want to know if there is a way to use this Index view for others Controller that inherits BaseController, it is returning the following error:
The view 'Index' or its master was not found or no view engine
supports the searched locations. The following locations were
searched:
You can just put the index.cshtml view into the Shared folder as well. If you dont want to clutter up your shared folder, and want some other scheme, you will have to write your own view engine, which sounds more complicated than it is... here's a link to do that: http://www.dotnet-tricks.com/Tutorial/mvc/NcJP200113-Custom-Razor-View-Engine-for-C
I am developing a website that has a View called _MainPage in View\Shared folder that other views use that for basic layout of my website, so I have a section in this view that populates data from database in fact this section is latest news of the site and I should show latest news in this section ,in simple way I should make section for example called latestNews :
<ul class="news-list">
#RenderSection("latestNews",required:false)
</ul>
and in each views I should fill this section by razor that data came from relevant controller :
#foreach (var item in Model.News)
{
<div>
<p>#Html.Raw(item.Body)<br />ادامه مطلب</p>
</div>
}
in fact I have latest news in every views in footer of my pages.
now my question is : How can define a custom controller for my View (_MainPage) that haven't do these routine in each view. Is there any generic way to accomplish that?
Any public method in a controller class is an action method. Every action method in a controller class can be invoked via an URL from web browser or a view page in application.
Your scenario is some dynamic information (data) need to displayed on couple pages in your application. Generally we end up in adding that data to model passed to views by action methods. We duplicate same data in multiple models where we brake DRY (Don’t Repeat Yourself) principle.
To handle this scenario ASP.NET MVC provides child action methods. Any action method can be child an action method but child actions are action methods invoked from within a view, you can not invoke child action method via user request (URL).
We can annotate an action method with [ChildActionOnly] attribute for creating a child action. Normally we use child action methods with partial views, but not every time.
[ChildActionOnly] represents an attribute that is used to indicate that an action method should be called only as a child action.
[ChildActionOnly]
public ActionResult GetNews(string category)
{
var newsProvider = new NewsProvider();
var news = newsProvider.GetNews(category);
return View(news);
}
Above child action method can be invoked inside any view in the application using Html.RenderAction() or Html.Action() method.
#Html.Action("GetNews", "Home", new { category = "Sports"})
(or)
#{ Html.RenderAction("GetNews", "Home", new { category = "finance"}); }
Instead of a section, you can use Html.RenderAction to specify a controller and an action. The action should return a partial view which is then integrated within the calling site.
I have opened a sample ASP.NET MVC project.
In HomeController I have created a method (action) named MethodA
public ActionResult MethodA()
{
return View();
}
I have right clicked on MethodA and created a new view called MethodA1
Re-did it and created a new view called MethodA2.
How is this magical relationship done? I looked for the config to tell the compiler that views MethodAX are related to action MethodA, but found none.
What view will the controller return when MethodA is called?
The convention is that if you don't specify a view name, the corresponding view will be the name of the action. So:
public ActionResult MethodA()
{
return View();
}
will render ~/Views/ControllerName/MethodA.cshtml.
But you could also specify a view name:
public ActionResult MethodA()
{
return View("FooBar");
}
and now the ~/Views/ControllerName/FooBar.cshtml view will be rendered.
Or you could even specify a fully qualified view name which is not inside the views folder of the current controller:
public ActionResult MethodA()
{
return View("~/Views/Foo/Baz.cshtml");
}
Now obviously all this assumes Razor as view engine. If you are using WebForms, replace .cshtml with .aspx or .ascx (if you are working with partials).
For example if there is no view it will even tell you where and in what order is looking for views:
Remember: ASP.NET MVC is all about convention over configuration.
The MVC framework use convention over configuration. The framework calls the ExecuteResult on the ViewResult object (created by the return View();). The framework by convention then looks in a number of locations to find a view
If you are using areas the framework will look in the following locations for a view.
/Areas//Views/ControllerName/ViewName.aspx
/Areas//Views/ControllerName/ViewName.ascx
/Areas//Views/Shared/ViewName.aspx
/Areas//Views/Shared/ViewName.ascx
/Areas//Views/ControllerName/ViewName.cshtml
/Areas//Views/ControllerName/ViewName.vbhtml
/Areas//Views/Shared/ViewName.cshtml
/Areas//Views/Shared/ViewName.vbhtml
Without areas (or if you are using areas and no view has been found) the framework will look at the following locations
/Views/ControllerName/ViewName.aspx
/Views/ControllerName/ViewName.ascx
/Views/Shared/ViewName.aspx
/Views/Shared/ViewName.ascx
/Views/ControllerName/ViewName.cshtml
/Views/ControllerName/ViewName.vbhtml
/Views/Shared/ViewName.cshtml
/Views/Shared/ViewName.vbhtml
As soon as the Framework tests a location and finds a file, then the search stops,
and the view that has been found is used to render the response to the client.
There are a number of overriden versions of the View method. The most common one is to render a specific view, outside of the framework convention, by calling it by name. For example
return View("~/Views/AnotherIndex.cshtml");
As an interesting footnote, the framework looks for legacy ASP, C# and VB Razor views (aspx, ascx, cshtml and vbhtml) even though you have a specific view engine.
In MVC controller action is not bound to view.
It uses delegate mechanism to pickup the view.
Model Binding(Mapping)
I was looking for the same and I just made a couple of tests and figured out.
It doesn't save anywhere.
To understand how it works; just do these steps:
In your controller, right click, Add View
Then enter a different View Name
and Ctrl F5
you will get Server error in application.
For example if you right click , Add View in following Index action method and type "Index2" in View name, you will get the error.
public class TestController : Controller
{
// GET: Test
public ActionResult Index()
{
return View();
}
}
So basically there is a 1-1 matching between action name and View name. And you cannot add view for the same method so there is no need to save in a config file.
Now change the view file name in Visual Studio from Index2.cshtml to Index.cshtml then Ctrl+F5. You should see it is working.
I am learning about Progressive Enhancement and I have a question about AJAXifying views. In my MVC 3 project I have a layout page, a viewstart page, and two plain views.
The viewstart page is in the root of the Views folder and thus applies to all views. It specifies that all views should use _Layout.cshtml for their layout page. The layout page contains two navigation links, one for each view. The links use #Html.ActionLink() to render themselves to the page.
Now I have added jQuery and want to hijack these links and use Ajax to load their content on the page dynamically.
<script type="text/javascript">
$(function () {
$('#theLink').click(function () {
$.ajax({
url: $(this).attr('href'),
type: "GET",
success: function (response) {
$('#mainContent').html(response);
}
});
return false;
});
});
</script>
There are two ways I can think of to do this, but I don't particularly like either one:
1) I can take the entire View's contents and place them in a partial view, then have the main view call the partial view when it is rendered. That way, using Request.IsAjaxRequest() in the controller, I can return View() or return PartialView() based on whether or not the request is an Ajax request. I can't return the regular view to the Ajax request because then it would use the layout page and I'd get a second copy of the layout page injected. However, I don't like this because it forces me to create empty views with just a #{Html.RenderPartial();} in them for the standard GET requests.
public ActionResult Index()
{
if (Request.IsAjaxRequest())
return PartialView("partialView");
else
return View();
}
Then in Index.cshtml do this:
#{Html.RenderPartial("partialView");}
2) I can remove the layout designation from _viewstart and specify it manually when the request is NOT Ajax:
public ActionResult Index()
{
if (Request.IsAjaxRequest())
return View(); // Return view with no master.
else
return View("Index", "_Layout"); // Return view with master.
}
Does anyone have a better suggestion? Is there a way to return a view without its layout page? It would be much easier to explicitly say "don't include your layout" if it is an ajax request, than it would be to explicitly include the layout if it's not an ajax.
In ~/Views/ViewStart.cshtml:
#{
Layout = Request.IsAjaxRequest() ? null : "~/Views/Shared/_Layout.cshtml";
}
and in the controller:
public ActionResult Index()
{
return View();
}
Just put the following code on the top of the page
#{
Layout = "";
}
I prefer, and use, your #1 option. I don't like #2 because to me View() implies you are returning an entire page. It should be a fully fleshed out and valid HTML page once the view engine is done with it. PartialView() was created to return arbitrary chunks of HTML.
I don't think it's a big deal to have a view that just calls a partial. It's still DRY, and allows you to use the logic of the partial in two scenarios.
Many people dislike fragmenting their action's call paths with Request.IsAjaxRequest(), and I can appreciate that. But IMO, if all you are doing is deciding whether to call View() or PartialView() then the branch is not a big deal and is easy to maintain (and test). If you find yourself using IsAjaxRequest() to determine large portions of how your action plays out, then making a separate AJAX action is probably better.
All you need is to create two layouts:
an empty layout
main layout
Then write the code below in _viewStart file:
#{
if (Request.IsAjaxRequest())
{
Layout = "~/Areas/Dashboard/Views/Shared/_emptyLayout.cshtml";
}
else
{
Layout = "~/Areas/Dashboard/Views/Shared/_Layout.cshtml";
}
}
of course, maybe it is not the best solution
You don't have to create an empty view for this.
In the controller:
if (Request.IsAjaxRequest())
return PartialView();
else
return View();
returning a PartialViewResult will override the layout definition when rendering the respons.
With ASP.NET 5 there is no Request variable available anymore. You can access it now with Context.Request
Also there is no IsAjaxRequest() Method anymore, you have to write it by yourself, for example in Extensions\HttpRequestExtensions.cs
using System;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Mvc
{
public static class HttpRequestExtensions
{
public static bool IsAjaxRequest(this HttpRequest request)
{
if (request == null)
{
throw new ArgumentNullException(nameof(request));
}
return (request.Headers != null) && (request.Headers["X-Requested-With"] == "XMLHttpRequest");
}
}
}
I searched for a while now on this and hope that will help some others too ;)
Resource: https://github.com/aspnet/AspNetCore/issues/2729
For a Ruby on Rails application, I was able to prevent a layout from loading by specifying
render layout: false in the controller action that I wanted to respond with ajax html.