In my MVC project has 2 Areas which is Admin and Client and I need to dynamic config Layout for Client side, In _ViewStart (in client) file will set layout for all of client page.
Layout = "~/Views/Shared/_Layout.cshtml";
So if we need to change client layout we can change Layout path of cshtml file in _ViewStart file right? I cant find how to change inside ViewStart file or Is there another solution in this case.
Thanks for your Help :)
Remember that anything within the #{ ... } is treated as code. So, it should be a simple matter of placing a condition in there to change how it's inherited:
#{
Layout = "~/Views/Shared/_Layout.cshtml";
if (User.Current.IsAuthenticated) {
Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
}
Though you're probaby better off looking at Themes (and have an admin/user theme). Alternatively, you can make your _Layout.cshtml smarter and have it handle the different views based on conditions as well.
See Also: MVC3 Razor - Is there a way to change the Layout depending on browser request?
Your question has not enough information to give you a complete code sample.
But basicly you can do this
if (InsertIsAdminLogicHere) {
Layout = "~/Views/Shared/_AdminLayout.cshtml";
} else {
Layout = "~/Views/Shared/_Layout.cshtml";
}
If you show us how you determine admin or not, we can provide more help.
hope this helps
You can take advantage of Nested Layouts. Create a base controller and drive all controllers from this one.
public class ControllerBase : Controller
{
public ControllerBase()
{
ViewBag.Theme = "~/Views/Shared/Default/Views/_Layout.cshtml";
}
}
public class HomeController : ControllerBase
{
public ActionResult Index()
{
return View();
}
}
_ViewStart.cshtml (don't make any changes in this file)
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
Views/Shared/_Layout.cshtml
This is default Layout file of Asp.NET Mvc. Empty this and replace these lines.
#{
Layout = ViewBag.Theme;
}
#RenderBody()
You can Modify this way for Areas. You can fetch active template info in BaseController from database or wherever you want.
Btw, if you want to put your views outside of ~/Views folder search for ThemeableRazorViewEngine
in Views/_ViewStart.cshtml
#{
object multiTenant;
if (!Request.GetOwinContext().Environment.TryGetValue("MultiTenant", out multiTenant))
{
throw new ApplicationException("Could not find tenant");
}
Layout = "~/Views/"+ ((Tenant)multiTenant).Name + "/Shared/_Layout.cshtml";
}
Related
I'm trying to set a master layout.cshtml page that works consistently for all page except for one or two (typically login and logout). In my layout I'd like to display some elements that I want to not display for these special pages.
I've seen partial views and sections and they all seem to work "backwards" to the way I want - in this case I want the default to be 'display all the elements', but for special pages I want to be able to turn an element off.
I've seen previous code that uses PageData to pass a variable to the layout (which seemed very useful as I could slap a bool in the relevant pages and check it in the layout) but this seems to have been removed. Are there any other ways that work without involving the controller or updating every page to display the bits I want hidden on just 1 page?
There's a number of different ways you can achieve this. If you want to simply "turn off" an area of the page, the simplest approach is probably with ViewData. Something like:
_Layout.cshtml
#if (ViewData["ShowThis"] as bool? ?? true)
{
<!-- HTML here -->
}
This will cause it to default to true (show the HTML) if the ViewData key is not defined, so then in your views where you want to disable it, you'd just need to define it as false:
SomeView.cshtml
#{
ViewData["ShowThis"] = false;
}
Alternatively, you can use sections. This would give you the ability to optionally replace the HTML with something else.
_Layout.cshtml
#if (!IsSectionDefined("Foo"))
{
<!-- HTML here -->
}
else
{
#RenderSection("Foo", required: false)
}
Then, in your view, you simply define the section. If you want to display nothing, you can just define it empty:
SomeView.cshtml
#section Foo {}
Or you can can actually put something in there to replace the area with:
#section Foo
{
<!-- alternate HTML here -->
}
You can try this to pass ViewData in _Layout page in asp.net mvc
public class DynamicMenuAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
var result = filterContext.Result as ViewResult;
result.ViewData["key"] = "Hello Bangladesh";
}
}
Add Dependency Injection into Startup.cs file
services.AddMvc(
config =>
{
config.Filters.Add(new DynamicMenuAttribute());
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
Now you can you ViewData["key"] in _Layout.cshtml
I am using code like this to detect the browser and apply a condition to display or not display <label>:
#{
var settings = Model.PartFieldDefinition.Settings.GetModel();
System.Web.HttpBrowserCapabilitiesBase theBrow = Request.Browser;
}
<fieldset>
#{
if ((theBrow.Browser == "IE") && (theBrow.MajorVersion < 10))
{
#:<label>#Model.DisplayName</label>
#://Some Code for inputs
}
else
{
#://Some Code for inputs
}
}
</fieldset>
I have been trying to figure out if I can (and if so, how) I could utilize this logic to detect what path in the website the user is in to display or not display <label>
For example, on any other path I want the label displayed. However, for the pages under ~/Services (the path), I want to be able to hide the label.
It's a little bit more complicated than that. The code is in an editor template that gets used all over the site. If I use CSS in the editor template to "hide" the label I will affect all the pages. I was hoping with the above logic I can avoid that and only apply my logic on certain pages under a path.
Thanks.
Update
I have tried the following:
#{
string CurrentURL = Request.ApplicationPath;
}
<fieldset>
#{
if ((CurrentURL == "Services")) // also tried "/Services"
// rest of code left out for brevity
}
but the labels are hidden on all pages, even outside the path "~/Services". Am stuck on the syntax.
Found answer
I did the following:
#{
string CurrentURL = Request.Url.AbsoluteUri;
}
<fieldset>
#{
if (CurrentURL.Contains("Services"))
}
and it worked. I don't know if anyone can comment, but which would be better to use: Request.Url.AbsoluteUri or Request.Url.ToString() (both of which work)?
I'm moving my WebForms project to MVC and having a hard time designing things.
The basic display of my app is in _Layout. The page is divided into 4 parts(say Part A,B,C and D), with 3(A,B,C) just containing html and one(D) is dynamic. I had used #RenderBody to bring in the content of Part D. However, now the other parts are changing and I need separate controllers for these parts. What is the best way to get their contents to be displayed into _Layout?
#Html.RenderPartial / #Html.Partial / #Html.RenderAction / #Html.Action ?
I'm currently trying to replace Part C by using -
#Html.Action("Index", "CController")
However, this is not working.
In Index.cshtml for CController, I've the Layout = null, initially it was set to point to _Layout.cshtml, but I read here that this created issues.
After putting the C Part in CControllers view, it does not event display the basic _Layout page that it displayed earlier.
Here's the Index.cshtml of CController -
<div id="noteContainerDiv">
Here goes all the data to display
</div>
And Here's the code for CController.cs -
public class CController : Controller
{
public ActionResult Index()
{
return PartialView();
}
}
Can anyone suggest the right way to design this?
What you could do is have a view model for your subview (the one you call D) and pass in this view model from your layout view.
I.e. by doing something like this in your _Layout:
#Html.Partial("_SubviewD", Model.SubviewDModel)
Then obviously in your controllers you need to initialize this subview model and include it in your model (or alternatively, in the ViewBag--apologies for suggested being evil!) You could even find ways to do this without changing all your controllers (for example through a base Controller class and overriding OnActionExecuted).
There are many ways you could do this. But I would stick to your initial approach.
Have your CController Index action return a PartialViewResult instead of a full result.
You don't set the layout for partial views. So in your CController index action you'll have something like this:
var model = ....
return this.PartialView("NameOfYourPartialView", yourModel);
And when you call
#Html.Action("Index", "CController")
Everything should be OK, cool?
In my Views root folder I have _ViewStart.cshtml, which has:
#{
Layout = "~/Views/Shared/_Layout.cshtml";
Page.Title = "Using Root ViewStart!";
}
Then in a nested Views\ProjectCharter folder, I have another _ViewStart.cshtml, which looks like this:
#{
Layout = "~/Views/Shared/_ProjectLayout.cshtml";
Page.Title = "Using Nested ViewStart!";
}
(note that both the _Layout.cshtml and the _ProjectLayout.cshtml file are in the same folder, called Views\Shared).
The problem I'm having is that the views in my Views\ProjectCharter folder are NOT using the _ProjectLayout.cshtml Layout...instead they are still using the root _Layout.cshtml (even though they are correctly picking up the "Using Nested ViewStart" title).
What's interesting is that if I change my ActionMethod to return the View using
return View("Create","~/Views/Shared/_ProjectLayout.cshtml",newProjectCharter);
instead of just
return View(newProjectCharter);
then the view does indeed use the _ProjectCharterLayout.cshtml layout. Any idea what I am missing? I don't want to have to change all my ActionMethods to use this more verbose overload.
As I can see from your post you are referring to _ProjectLayout.cshtml being in "
Views\ 'PROJECTCHARTER'
but in the code you are saying that it is in the shared folder:
Layout = "~/Views/ 'SHARED' /_ProjectLayout.cshtml";
Hope that will sort it out
In the application I am working on, I have an Html page inside views folder and I have mentioned the action as follows.
<form name="form" onsubmit="return validateForm();" method="post" action="//Controllers/RegistrationController.cs">
The registration controller returns a view.
public ActionResult Detail(string name)
{
return View();
}
When I run the program, I get server not found error.
I also tried changing the action string to action="//Controllers/RegistrationController.cs/Detail"
but got the same error.
Does the action string have to be written in some other way?
Thank you very much in advance for your help.
Assuming you are using the default routes ({controller}/{action}/{id}) you need:
action="/Registration/Detail"
Actually I would recommend you using HTML helpers to generate forms and never hardcode them as you did:
#using (Html.BeginForm("Details", "Registration", FormMethod.Post, new { name = "form", onsubmit = "return validateForm();" }))
{
...
}
Description
You don't have to set the path like in your solution. You don't need to set Controllers because the framework knows that you mean the controller.
Assuming that you dont change the routing in global.asax, your RegistrationController.cs has an ActionMethod called Detail (decorated with [HttpPost]) and the following folder structure within your project.
Controllers/RegistrationController.cs
Views/Registration/Detail.cshtml
#using (Html.BeginForm("Detail", "Registration", FormMethod.Post, new { #onSubmit = "return validateForm();" }))
{
// Your Form's content
}
/registration/detail - you don't need to reference the path to the actual file. The framework finds the controller class and invokes the requested action for you. It uses the routes as defined in global.asax.cs to determine the controller and action from the url. The default route is {controller}/{action}/{id} where the first two have defaults of "Home" and "Index", respectively, and the third is optional. You can change this if you want by adding/modifying the route set up.