How to use multiple Layout in MVC 3? - c#

I've four kinds of user (Customer, Admin, Manager, teacher) that can use my future ASP Web Site... And so for each of them I have to create different interfaces...
And so my questions:
Is this correct to use different Layout in MVC 3 ? If not what can I use for my problem ?
If it's correct how to use different layout in MVC 3 ? Can you give me one or more example please ?

I would create different _Layout.cshtml pages for each user category and put the _Layout selection logic in _ViewStart.cshtml page.
[Because the _ViewStart.cshtml allows us to write code, we can optionally make our Layout selection logic richer than just a basic property set.]
http://weblogs.asp.net/scottgu/archive/2010/10/22/asp-net-mvc-3-layouts.aspx

You can show the pages in different ways by testing what kind of user it is
In my _Layout.cshtml i have this:
#if (Request.IsAuthenticated && HttpContext.Current.User.IsInRole("Interviewer"))
{
<script type="text/javascript">
$("#logindisplay").show();
</script>
<li>#Html.ActionLink("Forside", "Index", "Home")</li>
<li>#Html.ActionLink("Spørgeskema", "Index", "Survey2")</li>
<li>#Html.ActionLink("Brugere", "Index", "UserAdministration")</li>
<li>#Html.ActionLink("Statistik", "Index", "Statistik")</li>
<li>#Html.ActionLink("Vagtplan", "Vagtplan", "Statistik")</li>
}
#if (HttpContext.Current.User.IsInRole("Respondent"))
{
<li>#Html.ActionLink("Gammelt spørgeskema", "Index")</li>
}
And so on.
You could create different DisplayTemplates for each kind of role and display these based upon which role the user has.
To manually assign Roles to different users, use ASP.NET Configuration
From there, you can create your roles and manage users.
You do not want to do this in the long run, if you get a lot of users on your site. Instead, when they create an account, you would want to assign their role automatically.
You can do this in your AccountController, for instance like this:
if (createStatus == MembershipCreateStatus.Success)
{
Roles.AddUserToRole(model.UserName, "Respondent");
} ....
Your model could have the Role property instead of hardcoding it.

I use 2 Layouts in my applications - Master (for all users) and Admin (for admin team). The only difference is in decorations - Admin has no banners, logos, etc...
So, it is up to you to use several. But I'd stay with one for Customer, Manager and Teacher. Use different CCS files for them to make appearance unique

I found this answer great. Adding to it, if you want use different layout based on the controller name then try editing method like below:
public static string LayoutHelper(RouteData data, string defaultLayout = "")
{
if (data.Values["controller"].ToString() == "client")
return "~/views/shared/_Layout2.cshtml";
return defaultLayout;
}
Client Controller index view
#{
Layout = HtmlHelper.LayoutHelper(Request.RequestContext.RouteData, "~/views/shared/_layout1.cshtml");
ViewBag.Title = "Clients";} <h2>This is my view</h2>
And at last new Layout2.cshtml
<!DOCTYPE html><html><head> <meta name="viewport" content="width=device-width" /><title>#ViewBag.Title</title></head><body> This is my Layout2 <div> RenderBody()</div></body></html>

Related

ASP.NET Core 6 MVC : how to implement layout logic?

I need to implement some logic to all views globally. I have a _layout view. How can I run logic (via a controller) for the shared layout?
I'm looking to implement the following logic:
Check if the user can perform an action of controller (if not, return to the previous page)
Check if the user account is active (after login, a user account can be disabled) (if not, log out and return to the login page)
Update the user log (update a table to save the IP and the time of the last user request to the server)
Hide controls for the user (prevent the user from seeing a control or changing any data)
In ASP.NET Web Forms 4, I created a class called Users, and this class was called inside of the master page's .cs code behind.
How can I accomplish something similar in ASP.NET Core MVC?
Welcome to MVC! The transition from ASP.NET Web Forms can be a bit frustrating as the programming models are so different. But once you get past the conceptual hurdles, you'll find a lot of tasks are much cleaner and easier to maintain.
I struggled with a similar challenge myself when migrating from ASP.NET Web Forms to, first, the ASP.NET MVC Framework and, later, ASP.NET Core MVC. There are a few common strategies for addressing problems like this, which I'll summarize below.
Custom Filter
For most of what you're talking about, the textbook solution is to create an custom filter, which is a piece of code that can be applied to multiple actions or controllers, and will be called at various stages of execution (e.g., before or after an action). You can also wrap filters in attributes, which makes it easy to apply them as an annotation to any action or controller. You can also register filters globally so they apply to all actions on all controllers. Filters are especially useful when you want to validate a request based on the current request—including potentially the current user.
View Component
Another approach, introduced with ASP.NET Core, is a View Component, which is a bit like a partial view, except that it has code behind it that operates a lot like a controller. This is useful if you need reusable components that share their own model on every page of your site, as it allows that to be constructed independently of any one action, while being shared across multiple views.
The textbook example of a view component is a login control, which receives a view model with information about the currently authenticated user, and uses that to conditionally display e.g., a sign-in or sign-out link.
Aside: I often use view components for centralizing my navigation, so I don't need to relay the data for the navigation down to every single view model. That's beyond what you're asking about here, but may help further conceptualize when a view component is useful.
Business Object
From a code organization perspective, you can still maintain much of the logic inside a custom User class, or even as extension methods off of e.g. the ASP.NET Core ClaimsPrincipal class (which is returned from the HttpContext.User property). Determining what the current state of the user is for the purposes of e.g. authorization makes sense in a separate class; handling the ASP.NET Core response to that (such as redirection to a previous page) belongs in the filter or view component.
And, of course, you can also relay (properties from) this class to your view via your action's or view component's view model if you need to rely upon them to customize the user interface.
Conclusion
There are obviously a number of approaches here—as well as some I haven't mentioned, such as implementing a base controller—but this should help get you started in thinking about how to centralize site-wide business logic without needing to repeat it in every action of every controller, or polluting your _Layout.cshtml with logic that would normally reside in a controller.
First I wouldn't recommend a Controller for the _layout page as this is not how the MVC architecture works.
You could create a view using the layout page, like UserView.cshtml.
Then you can create a UserController.cs and your actions in it.
I hope I could help.
Check if the user can perform an action of controller (if not, return
to the previous page) Check if the user account is active (after
login, a user account can be disabled) (if not, log out and return to
the login page) Hide controls for the user (prevent the user from
seeing a control or changing any data)
You can use #if(User.IsInRole("Admin")) to determine the identity of the user in the layout, and then if the user can't perform an action of controller, use class="disabled" to disable the action.
If is the user you want to show a control , you can contains this control after it is judged to be true. So hide controls for the user.
For example, if it is admin, you can add a role or view the current role.
Demo as below:
_layout:
#inject SignInManager<AppUser> SignInManager
#inject UserManager<AppUser> UserManager
#using Microsoft.AspNetCore.Identity
#using Identity.Models
<!DOCTYPE html>
<style>
.disabled {
pointer-events: none;
color: grey;
text-decoration: none;
}
</style>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>#ViewBag.Title</title>
<link href="~/twitter-bootstrap/css/bootstrap.css" rel="stylesheet" />
<p>Login</p>
#if(User.IsInRole("Admin"))
{
<p>Admin</p>
<p>Role</p>
<p>Claims</p>
<li >
<a asp-area="" asp-controller="Role" asp-action="Create" >Hello #UserManager.GetUserName(User)! Create a Role</a>
</li>
}
else
{
<p><a class="disabled"href="/Admin" target="_blank" >Admin</a></p>
<p><a class="disabled" href="/Role" target="_blank" >Role</a></p>
<li >
<a asp-area="" asp-controller="Role" class="disabled"asp-action="Create" >Hello #UserManager.GetUserName(User)! Create a Role</a>
</li>
}
</head>
<body class="m-1 p-1">
#RenderBody()
</body>
</html>
result:
Update the user log (update a table to save the IP and the time of the
last user request to the server)
Use javascript to get the URL of the current request and the time of the current request, and then use ajax to call the action of the back-end controller, and record the time of the obtained request into the database.

Several Shared layouts for several sidebars

So I'm new to MVC 4 and I'm currently contemplating on what should I do.
CURRENT CODE
I made several SHARED layouts for each type of user. So I now have, _AdminLayout.cshtml for the Admin's sidebar, _FacultyLayout.cshtml for Faculty, and _StudentLayout.cshtml
PROBLEM
I have several types of users: Admin, Student, and Faculty. The content of the sidebar changes depending on which type of user is logged in.
Are there any other solutions for this?
I was planning to put all the sidebars in one SHARED LAYOUT but MVC 4 doesn't have Controllers for Shared Layouts unlike in Web Forms Master Pages, there is a Codebehind file. I'm just trying to shorten my code and lessen the redundancy between the 3 SHARED LAYOUTS that I currently have.
You can have one single layout and use #Html.Action() to render the sidebar as a partial view depending on the role of the user. This could go in a BaseController from which all other controlles inherit, or in a separate controller (say) LayoutController
[ChildActionOnly]
public ActionResult SideBar()
{
var role = ... // your code for getting the users role
if (role == "Admin")
{
return PartialView("_AdminSideBar");
}
else if (role == "Faculty")
{
return PartialView("_FacultySideBar");
}
else if ..........
}
and then create a associated partial views _AdminSideBar.cshtml, _FacultySideBar.cshtml etc.
Then in the Layout Page
......
<div id="sidebar">
#{ Html.RenderAction("", ""); }
</div>

mvc razor allow users to select there own theme css

I am using MVC/Razor/.Net/C# and i would like to allow users to change the theme of the site just like you can change the theme in microsoft windows.
Does anyone know how to, or, can point me in the direction of some good tutorials/examples.
Cheers
This is a very, very broad question with any number of correct approaches.
You could create a base controller that loads the user's selected CSS theme name from a database during each request. Then you can put that value into the ViewBag (or ViewData) and reference it in your view:
<head>
#{
var themeName = ViewBag.ThemeName;
}
#if (String.IsNullOrWhiteSpace(themeName)) {
themeName = "default";
}
<link href="#Url.Content(String.Format("~/themes/{0}.css", themeName))" type="text/stylesheet" />
</head>
Usually this functionality is achieved with multiple CSS files and has little (or nothing to do with .NET).
You should design your HTML in a semantic way so that by changing the CSS files the entire output is different with each CSS applied.
This link gives a more explanatory intro into the subject -> http://www.thesitewizard.com/css/switch-alternate-css-styles.shtml
After you do that, what you need to do in your application is to store the user preference (of what skin) in a session or something like that and change the CSS file accordingly.
Asp.Net WebForms use to have the Skin/Theme feature, but I think that it was deprecated (it is not very good) and I also saw an implementation where instead of HTML the developer used XML and XSLT files to render the views (which is also too complicated for my taste).

Checking permissions in controller and in view

I want to create permissions on some actions like creating or updating information (but not for displaying).
For this I'm adding attributes before all the necessary methods e.g.
[Permissions(Permissions.Admin)]
public ActionResult Create()
{
//...
}
Besides I wouldn't like to leave the links active on the index page. So I have to add some checks inside the views.
#if (checking...)
{
#Html.ActionLink("Create New", "Create")
}
The more checks I add, the more boring, and the more things I have to keep in my mind.
How to do it right?
Your could create a HtmlHelper for this.
Something like #Html.ActionLinkUsingPermissions("Create New", "Create",Permissions.Admin)
The HtmlHelper would decide whether or not to display the link depending on the current users permissions.
You can create a read-only version of views and letting the controller decides which version it should return (based on your permission).
Shared UI can be then externalized in partial views.
It's recommended to keep your view free from business logic as much as possible.
You could also create two different view models. One for read/write and one for just read. Then using the View Templates feature you can have one view automatically pick the right template to show using this line:
#Html.DisplayForModel()

Asp.net MVC - Render a partial View From an Area

I've created an area that will handle our some generic things across all our development products, just as log ins, HTML helpers, etc. Inside the area, I have a partial view that I'm attempting to reference outside of the area. I've registered the area with
public class Routes : AreaRegistration
{
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Common_default",
"Common/{controller}/{action}/{id}",
new {
controller = "Account",
action = "Index",
id = UrlParameter.Optional
});
}
public override string AreaName
{
get { return "MvcCommons"; }
}
}
And now in the regular project, I'm trying to reference a view in the MvcCommons area...
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>TestGrid</h2>
<% Html.RenderPartial("jQGridTable", ViewData.Model); %>
But I keep getting that the view isn't found. Before, while creating the MVC Commons project, I was getting view errors, but the errors told me that it looked in both the area folders and the default view folders. This time, I'm only getting the default folders. Is there any way to accomplish this?
Thanks everyone!
I haven't actually had to do this, but at a guess I would assume you should use Html.RenderAction() instead, something like Html.RenderAction("action", "controller", new { area = "Area", model = ViewData.Model }).
model will have to be replaced with the name of the action's parameters, but that should work.
edit this will require a controller and view setup for each action though.
An important thing to remember is that when using RenderPartial you use it in the context of the current action.
As your action isn't in an area it will only look in the View/ folder for the controller the action belongs to then the shared folder.
Any views you wish to share between areas and controllers and have available at the route should be the root View/Shared folder. Really if the view is callable as a partial like that there is probably little reason for it to belong to an area.
You can call into area when you want to render actions rather than partials - which then changes the context of the current action to the action you call into thereby allowing you to then return views within that area.
The Default ViewEngine looks for the Views inside the same area (or root) folders where the user control is referenced. If you want to create a custom way to use or store views, I suggest you to create a custom ViewEngine. Please take a look at this example: Implement Theme Folders using a Custom ViewEngine

Categories