Could someone tell me which is the front controller in MVC 4 c# visual studio please?
I mean, i have to do a big application and i want add security to restrict the access to the controllers and actions. I used to do this in the Logistic of the Front Controller in CodeIgniter, adding a token to the session, so if someone wanted to write the route manually on the browser he couldnt access.
I've been reading about [Authorize(Roles="Admin")] and i have to admit that is a solution, but that means i have to write in every method of the all controllers, and i want to have that centralized in the front-controller with IF/ELSE.
PD: If you don't know how to do this, at least try to tell me where can i find the front controller in MVC c# visual studio please.
Thanks for all.
There is no front controller in MVC. You need to create a base controller , And your every controller will inherit Base controller.
public class BaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
var getControllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
var getActionName = filterContext.ActionDescriptor.ActionName;
//Write your code here
}
}
Now Inherit your controller with Base controller.
public class AccountController : BaseController
{
//Your action goes here.
}
There is no such thing as a front controller in ASP MVC. I think the thing you're looking for is some sort of base controller where all of the other controllers inherit from.
You can add this Authorize attribute to methods or classes (whole controllers). If every action needs this attribute I suggest to create a master controller and let every controller inherit from this controller.
Consider using action filters.
http://www.asp.net/mvc/overview/older-versions-1/controllers-and-routing/understanding-action-filters-cs
Related
I have the following controller which I wanted to use as an Web API Controller for ajax posts to retrieve data from my user table.
namespace MyProjectName.Controllers.API
{
[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
private readonly myContext _context;
public UsersController(myContext context)
{
_context = context;
}
[HttpGet]
public List<string> GetInstitutionNamesById(int id)
{
// returns desired list
}
}
}
Now I'd expect the routing of this Function to be like this: /api/users/getinstitutionnamesbyid but apparently it seems to be just /api/users which I find really confusing (what if I add additional HttpGet Functions?).
Can anyone explain me what I am doing wrong? Am I using Web Api Controllers not the Intended way? Is my routing wrong?
Thanks in Advance.
[Route("api/[controller]")]
With this template, you're explicitly stating that you only care about the name of the controller. In your example, GetInstitutionNamesById is the name of the action, which isn't being considered by the template.
There are a few options for achieving what you're asking for here:
Change your [Route] template to include the action name:
[Route("api/[controller]/[action]")]
This option applies to all actions within your controller.
Change the HttpGet constraint attribute to specify the action implicitly:
[HttpGet("[action]")]
This option ensures that the name of your action method will always be used as the route
segment.
Change the HttpGet constraint attribute to specify the action explicitly:
[HttpGet("GetInstitutionNamesById")]
This option allows you to use a route segment that differs from the name of the action method itself.
In terms of whether you're using routing in the correct way here - that's somewhat opinion-based. Generally, you'll see that APIs are attempting to be RESTful, using route templates that match resources, etc. With this approach, you might have something more like the following:
/api/Users/{userId}/InstitutionNames
In this case, you might have a separate InstitutionNames controller or you might bundle it up into the Users controller. There really are many ways to do this, but I won't go into any more on that here as it's a little off-topic and opinion-based.
You just need to name it this way
[HttpGet("[action]/{id}")]
public List<string> GetInstitutionNamesById(int id)
{
// returns desired list
}
and from ajax call /api/users/GetInstitutionNamesById/1
I'm looking for a good place in the ASP.NET Web API lifecycle To update a property in my User entity that is purposed to store the date and time the User last made a request. Obviously, I could just add the code to each of my Controller methods but I would prefer doing this in one place outside of my controllers.
Ideally I would have access to the User principal and could use its Identity property to get the user's ID so that I could retrieve and update my User entity using Entity Framework.
I am currently looking at using a DelegatingHandler implementation.
Can anyone suggest the place in the lifecycle where I should carry this out? A code example would be appreciated.
Create an ActionFilter:
public class LogActionFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
// Do your work
}
}
Yes, but wouldn't I have to add the ActionFilter to each and every controller method?
No, you can apply it to the controller or to actions.
Alternatively, you can do the following and you will not have to apply it to every controller (sort of like a global filter):
[LogActionFilter ]
public class LogableApiController : ApiController
{
...
}
Then inherit that wherever you want.
And lastly, another option is to add to global filters by finding the App_Start/FilterConfig.cs and add:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new LogActionFilter());
}
So I have shown you how to apply it to action level, controller level, one or more controllers but not all controllers and then how to apply it to all controllers (global).
I would create an Attribute for your Controller to execute the update on your User Entity with an ActionFilter.
This example explain how to create an attribute for a controller method, it is the same way to do it: Custom Attribute above a controller function
b.e, your controller would be like this:
[SaveUserRequest]
public class HomeController : ApiController
I have a Solution structure like this:
MyApp.Core
--Properties
--References
--bin
--Events
|EventHandlers.cs
--Directory
--Controllers
|DirectoryController.cs
--Helpers
|ContextHelpers.cs
--Models
|DirectoryModel.cs
--AnotherSite
--Controllers
--Helpers
--Models
--Services
--Shared
--Controllers
|HomePageController.cs
--Helpers
|Extensions.cs
|app.config
|packages.config
MyApp.Umbraco
--Properties
--References
--bin
etc........
--Views
--Directory
--Partials
|DirectoryFilters.cshtml
|DirectoryBase.cshtml
|DirectoryHome.cshtml
|FDirectory.cshtml
|SDirectory.cshtml
--Partials
--Shared
|Base.cshtml
|Web.config
etc........
My Umbraco instance uses the models and controllers from my "Core" project. There is nested directory structure, because of multiple websites in one installation, in the "Core", and also in the "Views" directory in the Umbraco instance.
I am still fairly noob to .NET MVC, and I understand route hijacking, but the documentation for Umbraco's routing is slim. I have the following:
EventHandlers.cs
namespace MyApp.Core.Events
{
/// <summary>
/// Registers site specific Umbraco application event handlers
/// </summary>
public class MyAppStartupHandler : IApplicationEventHandler
{
public void OnApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
}
public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
RegisterCustomRoutes();
}
public void OnApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
}
private static void RegisterCustomRoutes()
{
// Custom Routes
RouteTable.Routes.MapUmbracoRoute(
"FDirectory",
"fdirectory/{id}",
new
{
controller = "Directory",
action = "FDirectory",
id = UrlParameter.Optional
},
new PublishedPageRouteHandler(1000));
RouteTable.Routes.MapUmbracoRoute(
"SDirectory",
"sdirectory/{id}",
new
{
controller = "Directory",
action = "SDirectory",
id = UrlParameter.Optional
},
new PublishedPageRouteHandler(1001));
RouteTable.Routes.MapUmbracoRoute(
"HomePage",
"",
new
{
controller = "HomePage",
action = "Index",
id = UrlParameter.Optional
},
new PublishedPageRouteHandler(1002));
}
}
public class PublishedPageRouteHandler : UmbracoVirtualNodeRouteHandler
{
private readonly int _pageId;
public PublishedPageRouteHandler(int pageId)
{
_pageId = pageId;
}
protected override IPublishedContent FindContent(RequestContext requestContext, UmbracoContext umbracoContext)
{
if (umbracoContext != null)
{
umbracoContext = ContextHelpers.EnsureUmbracoContext();
}
var helper = new UmbracoHelper(UmbracoContext.Current);
return helper.TypedContent(_pageId);
}
}
}
DirectoryController.cs
namespace MyApp.Core.Directory.Controllers
{
public class DirectoryController : RenderMvcController
{
public DirectoryController() : this(UmbracoContext.Current) { }
public DirectoryController(UmbracoContext umbracoContext) : base(umbracoContext) { }
public ActionResult FDirectory(RenderModel model)
{
return CurrentTemplate(new DirectoryModel(model.Content));
}
public ActionResult SDirectory(RenderModel model)
{
return CurrentTemplate(new DirectoryModel(model.Content));
}
}
}
So Umbraco does not install with an App_Start folder. I would like to know what the best approach is for a multi-site installation of Umbraco for registering the routes to the controllers. My implementation works, but it seems like I shouldn't have to create actions for every single page I am going to have in a site, in every controller. I know Umbraco has its own routing, so using Umbraco concepts, ASP.NET MVC concepts, and whatever else is available, what is the best way to implement this type of solution structure? Should I even worry about using a RouteConfig.cs and create a App_Start directory? Or is what I am doing the best approach? Should I use IApplicationEventHandler or ApplicationEventHandler?
Also, I have to hard code the node ID's. I've read that there is a way to Dynamically? And example of this would be great.
Examples of the best way to implement a structured multi-site Umbraco MVC solution is what I am asking for I guess, in regards to routing the controllers, with some detail, or links to strong examples. I have searched and researched, and there are bits and pieces out there, but not really a good example like what I am working with. I am going to have to create a RouteMap for every single page I create at this point, and I don't know if this is the most efficient way of doing this. I even tried implementing a DefaultController, but didn't see the point of that when your solution is going to have multiple controllers.
I'm not entirely sure what you are trying to achieve with this, but I'll try to explain how it works and maybe you can clarify afterwards.
I assume you have the basics of Umbraco figured out (creating document types + documents based on the document types). This is how Umbraco is normally used and it will automatically do routing for you for each of these "content nodes" (documents) you create in a site.
So create a document named document1 and it will be automatically routed in your site at URL: http://localhost/document1. By default this document will be served through a default MVC controller and it will all take place behind the scenes without you having to do anything.
Route hijacking allows you to override this default behavior and "shove in" a controller that lets you interfere with how the request is handled. To use hijacking you create a RenderMvcController with the alias of your document type. That could be HomePageController : RenderMvcController.
This controller should have an action with the following signature:
public override ActionResult Index(RenderModel model)
In this action you are able to modify the model being sent to the view in any way you like. That could be - getting some external data to add on to the model or triggering some logic or whatever you need to do.
This is all automatically hooked up by naming convention and you will not have to register any routes manually for this to work.
The other type of Umbraco MVC controller you can create is a SurfaceController. This one is usually used for handling rendering of child actions and form submissions (HttpPost). The SurfaceController is also automatically routed by Umbraco and will be located on a "not so pretty" URL. However since it is usually really not used for anything but rendering child actions and taking form submits, it doesn't really matter what URL it is located at.
Besides these auto-routed controllers you are of course able to register your own MVC controllers like in any standard MVC website. The one difference though is that unlike a normal ASP.NET MVC website, an Umbraco site does not have the automagical default registration of controllers allowing the routing to "just work" when creating a new controller.
So if you want to have a plain old MVC controller render in an Umbraco site without it being related to a document/node in Umbraco, you would have to register a route for it like you would do in any other MVC site. The best way of doing that is to hook in and add it to the Routes using an ApplicationEventHandler class. That will automatically be triggered during application startup - essentially allowing you to do what you would normally do in App_Start.
Just to be clear though - if you plan on using data from Umbraco, you should not be using normal MVC controllers and should not require any manual route registration to be done. You usually want to render a template/view in context of a document/node created in Umbraco (where you can modify data/properties of the document) and then the route hijacking is the way to go.
From what it looks like, it could seem that the correct way to do what you are trying to do is to simply create two document types:
FDirectory and SDirectory
You click to allow both of these to be created in root and then you create documents called FDirectory and SDirectory and they will be automatically routed on these URLs. Creating a RenderMvcController's called FDirectoryController : RenderMvcController will then make sure it is used to hijack the routing whenever that page is requested.
If you're simply trying to set up a multi-site solution I would suggest you create a Website document type and create a node for each site you want, in the root of your Umbraco content tree. Right click each of these nodes and edit the hostname to be whatever you need it to be. This can also be some "child url" like /fdirectory or /sdirectory in case you need to test this on localhost without using multiple hostnames.
Hope this gives you the pointers needed, otherwise try to explain what you are trying to do and I'll see if I can refine my answer a bit!
This is a question about best-practices in ASP.NET MVC
I've created a website in MVC. Because every page has a menu, I thought I'd create a base controller class which all MVC Controllers in the project inherit from. In The Initialize() function of the base controller class I would then load my Menu.
In that way, I could keep my logic for loading the menu in one place and have it executed automatically.
Code (C#):
public abstract class BaseController : System.Web.Mvc.Controller
{
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
//Load the menu:
ViewBag.HeaderModel = LoadMenu();
}
}
public class HomeController : BaseController
{
public ActionResult Index()
{
//the menu is loaded by the base controller, so we can just return the view here
return View();
}
}
That works like a charm. Now here's the problem.
In my View, I present a list of the five latest Articles on the website. Since the Articles have their own logic and their own section on the website, I've created an ArticleController, which inherits from BaseController as well, with an action that displays a PartialResult with my five latest Articles.
public class ArticlesController : BaseController
{
public ActionResult DisplayLatestArticles()
{
var model = ... //abbreviated, this loads the latest articles
return PartialView("LatestArticles", model);
}
}
And the method is called like this in the View:
#Html.Action("Index", new { controller = "Articles" })
But this has one drawback: namely the Initialize() function on my Base Controller is executed twice, which loads the menu two times, which is undesirable (for performance reasons). So far I haven't been able to find a way to avoid this behavior.
What do you suggest in so far as refactoring this code? I want to make sure my logic to load my menu stays somewhere so it gets called automatically, without me or any other developers on the project having to worry about it. I prefer keeping my logic to display the latest Articles in the ArticlesController so everything to do with Articles is kept in its own Controller.
So, how best to proceed?
What you're trying to do is more suited to calling your header menu from a _Layout.cshtml page.
_Layout.cshtml:
<html>
...
<body>
...
#Html.Action("Header", "SharedStuff")
...
SharedStuffController.cs
public ActionResult Header()
{
// logic to create header, also create a view
return this.View();
}
Base controllers, I feel, are normally the wrong way to go. The above means that you keep all logic for the header nicely contained in something that describes it.
I am not expert on the MVC and landed on this page while searching for my own answer. I completely agree that Base contoller should not be used for generating menu items. However, for what so ever reason, if you wanted to continue using base controller, I would suggest the controller that returns partial views (i.e ArticlesController) should not inherit from base controller and it should inherit from Controller class.
I would like to add a check for Request.IsAuthenticated into my MasterPage (COntroller? Is there such a thing??). Is this possible? I want to redirect to a NoAccess.aspx page if the check fails.
The concept on MVC is different to web forms where you would do common logic on the master.
In ASP.NET MVC master page must only contain UI related setup.
In MVC you use Action filters: decorate your actions with [Authorize].
Did you create a project using the default MVC project template? It has everything you're looking for already in there. If you didn't go ahead and create one now.
Once you're in there you'll notice the [Authorize] attributes as #Aliostad mentioned. These are custom attributes that do the validation on the controller level.
Check out the MVC tutorial on web form security for a more detailed run-down on how it all meshes together: http://www.asp.net/mvc/tutorials/authenticating-users-with-forms-authentication-cs
You can achieve this by creating your own custom authentication attribute.
Create a new filter folder within your project and add the following class
public class NoAccessDirectAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
filterContext.Result = new RedirectResult("noaccess.aspx");
}
}
then decorate your home controller and other required controllers with the Authorization Attribute
[NoAccessDirectAuthorizeAttribute]
public class HomeController : Controller
This will redirect an unathenticated user to your noaccess.aspx page