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
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 have a user search request object which looks like this:
UserSearchRequest
{
FirstName:"John",
LastName:"Smith",
Expand:["groups","devices"]
}
Expand is an optional parameter. I have validation which checks that the provided Expand parameters are within thin expected set of parameters. The problem is that if a client submits a request like this:
{
FirstName:"John",
LastName:"Smith",
Expand:1
}
By default Web API 2 will pass this request to the controller method with an Expand value of null. So the user won't know that he submitted a bad request and the controller won't be able to identify it as a bad request b/c null is a valid value for this property. Is there a way to override this default behavior?
Action filters are triggered before controller executes its logic. I will give a general idea of what you need to do to get you on the right track.
First requirement for ActionFilter is to create your own filter class by extending ActionFilterAttribute class.
The following is a sample for this
public class ValidateCustomModel : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
//Write your logic to check that all attributes are not null
}
}
Now onto the second step. This step will register your filter in WebApiConfig class so that the application will know that it has to pass requests to this filter wherever the attribute is used
config.Filters.Add(new ValidateModelAttribute());
Now the third step is to call the custom class as an attribute on the controller method that is being executed when user makes a request.
[ValidateModel]
Hope this helps you to customise it for your own logic. Happy coding.
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
I'm just getting started with Asp.Net Core (and asp.net in general) and I'm trying to build nice controller classes for my rest api.
I'm trying to inherit from a base controller to avoid redefining routes and logic such as validation for resources like so (non working example):
[Route("/api/v1/users/{id}")]
public class UserController: Controller
{
protected int userId;
public override void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context);
// Validate userId..
userId = (int) RouteData.Values["id"];
}
[HttpGet]
public IActionResult Info()
{
// Use this.userId here
return this.Json("User info..");
}
}
[Route("/friends")]
public class UserFriendsController: UserController
{
[HttpGet]
public IActionResult Info()
{
// Use this.userId here
return this.Json("List of user's friends..");
}
}
I realize I can put this into a single class with multiple actions, but my real scenario involves more controllers that all may want to inherit from UserController.
Route attributes cannot be inherited.
You can play with Routing Middleware. See documentation and the examples on Routing github repo.
Also I can recommend this ASP.NET Core 1.0 - Routing - Under the hood article, as it has good explanation about how routing works:
I'm trying to inherit from a base controller to avoid redefining
routes and logic such as validation for resources
If you want to check whether current user has access right on the resource or not, you should use Resource Based Authorization. For other cross cutting concerns, you can use Filters or Middlewares.
I want to implement a CMS and I would like to make some settings available to views.
These settings may be the web site's name, the company name and maybe some more complex items.
I would like these to be available on every view without using strongly typed Models, something like ViewData-ViewBag but without having to set it in every action.
I think that I have to create a ControllerFactory that will set the ViewBag on every CreateController.
What do you think that it's the best solution for this problem?
Possible duplication at Execute Code on Every Request
Create your own application controller and override OnActionExecuting. There you can initialize your own properties in Viewbag:
public abstract class ApplicationController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
// set your ViewBag.Settings here
}
}
Create all of your controller classes derived from ApplicationController:
public class HomeController : ApplicationController { ... }
Now you can access ViewBag.Settings from all of your views without setting this property explicitly in each action.