I'm just reading about OutputCache, and I see how you can apply VaryByParam to change the cache based on parameters sent to the view, but I would like to change the cache based on both the parameters and the currently logged in user (using Asp.Nets default membership). I've been looking around, but I don't seem to be able to find a way to get this working.
Any suggestions on what I should try?
Use VaryByCustom. I implemented something like this:
[OutputCache(VaryByCustom="user")]
public ActionResult SomeAction()
{
return View();
}
and in Global.asax.cs
public override string GetVaryByCustomString(HttpContext context, string arg)
{
if (arg == "user")
{
return context.Request.User.Identity.IsAuthenticated ? context.Request.User.Identity.Name : string.Empty;
}
return base.GetVaryByCustomString(context, arg);
}
Related
I want to run some custom logic for all APIs (asp.net core) that we have in our service before model validation but after model binding. Is this possible? I tried an ActionFilter but it gets called after validation. Resource filter also does not work for us. Appreciate your help.
Web API controllers don't have to check ModelState.IsValid if they have the [ApiController] attribute. In that case, an automatic HTTP 400 response containing issue details is returned when model state is invalid.
One way to achieve what you want is to suppress this behavior.
Add the following code to ConfigureServices:
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
Then you can add your code to the filter - eg:
public class SampleActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// do something before the action executes
if(context.ActionArguments != null && context.ActionArguments.Count > 0)
{
//WARNING - you should add "safe" code to access the dictionary
//I have hardcoded the parameter name (data) here for sample only.
var model = context.ActionArguments["data"];
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
// do something after the action executes
}
}
of course you need to apply the filter as well - in the example case below, I have applied it globally. You can be more specific if you want.
services.AddMvc(
options => options.Filters.Add(new SampleActionFilter())
).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
In your controller code, you can also further use the TryValidateModel method if you want, like so:
[Route("api/[controller]")]
[ApiController]
public class ProcessController : ControllerBase
{
[HttpPost]
public IActionResult Contact(FormDataModel data)
{
bool validated = TryValidateModel(data);
if (!ModelState.IsValid)
{
ModelState.AddModelError("", "Id cannot be empty..");
return Ok();
}
return Ok();
}
}
Hope this helps to solve your problem.
Given the following two urls:
/employee/list/active
/employee/list/inactive
How do I map the active/inactive part of the url to a boolean action method parameter, active being true, inactive being false?
[Route("employee/list")]
public ActionResult List(bool? active = null)
The enum is a correct approach as it allows you to easily add new statuses in the future :
[Route("employee/list/{status}")]
public ActionResult List(status status)
{
...
}
public enum status { active, inactive }
Even though, based on the single responsibility principle, I would prefer a simpler solution like this:
[Route("employee/list/active")]
public ActionResult ListActive()
{
return List(true);
}
[Route("employee/list/inactive")]
public ActionResult ListInactive()
{
return List(false);
}
public ActionResult List(status status)
{
...
}
I reworked it to use a string so it worked like this:
[Route("employee/list")]
[Route("employee/list/{active}")]
public ActionResult List(string active ="both")
{
///Stuff happens here
}
It's important to add the first, parameterless route if you need the parameter to be optional.
Update: This route works too
[Route("employee/list/{active='both'}")]
I'm use to custom authorize attribute like
public class AdminAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return (base.AuthorizeCore(httpContext) && User.IsCurrentUserAdmin());
}
}
how to check is action call current user or not
as an example:
[OnlyYouself]
public ActionResult ViewUser(int userId)
{
...
}
means userId = current user
else redirect to previous view
You might want to build a custom attribute that looks like this:
public class AllowCurrentUserAttribute: AuthorizeAttribute
{
public string Field { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
return (base.AuthorizeCore(httpContext) && filterContext.HttpContext.User.Identity.Name == filterContext.HttpContext.Request.QueryString[Field];
}
And then use it like this:
[AllowCurrentUser(Field = "userId")]
public ActionResult ViewUser(int userId)
{
...
}
There are probably better ways to check the request properties, though. Also, you may want to have a default value of "id" for the field, assuming you use the default MVC routing. If your id field is called something else, you'll want to change it.
actionContext.RequestContext.Principal.Identity
I am having the following code:
public ActionResult EditTrain(EditTraing editrain)
{
....
....
return RedirectToAction("Details", new { id = "200241"});
}
Once I am in the Details Action, I like to check who the referrer was. In this case, I would be the EditTrain. Is there anyway I can figure out what Action the Redirection came from?
You can probably send some keys in the querystring
public ActionResult EditTrain(EditTraing editrain)
{
return RedirectToAction("Details", new { id = "200241" ,from="edittrain"});
}
public ActionResult Details(int id,string from)
{
//do stuff
}
From memory you should be able to access HttpContext.Request.UrlReferrer from within your action.
Either use TempData or pass the information in the redirect itself.
i have some controlers that provide access only to users that are in Admin role:
[Authorize(Roles = "Administrators")]
controler im talking about displays company details for customers and i want to provide access to that controler by some url for example:
www.mysite.com/Company/123?code=0932840329809u0932840
generating code will not be a problem, problem is what is the best solution to provide access to controler via that secret url AND access without secret url only for administrators?
thnx!
You could create a custom attribute filter by extending the AuthorizeAttribute.
Something like:
public class CustomAuthorizeAttribute : AuthorizeAttribute {
public string Code { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext) {
if (base.AuthorizeCore(httpContext)) {
return true;
}
string code = Code ?? GetCode() //parse you code as a parameter or get it from another method
if (httpContext.Request["code"] == code) {
return true;
}
return false;
}
}
//I wouldn't recommend parsing the code like this, I would get it in your action filter
[CustomAuthorizeAttribute(Code="0932840329809u0932840")]
public ActionResult Index() {
return View();
}
Have a look at http://schotime.net/blog/index.php/2009/02/17/custom-authorization-with-aspnet-mvc/