ActionExecutingContext ActionParameters gets an object - asp.net-mvc

I have a controller like this
public ActionResult ChangePassword(LG_CRD_PASSWORD_MODIFY_MAP pLG_CRD_PASSWORD_MODIFY_MAP)
{
....
}
And an OnActionExecuting Method
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
var param = filterContext.ActionParameters;
}
I'm not being able to extract values from the object parameter

Retrieve object from dictionary:
LG_CRD_PASSWORD_MODIFY_MAP extractedObj = param.Single(x => x.Key == "pLG_CRD_PASSWORD_MODIFY_MAP").value;
For example:
var prop = extractedObj.CURRENT_PASSWORD;

Related

Can I no longer pass ViewData to _Layout.cshtml in MVC Core 1.0?

I'm trying to pass a URL for a background image to my _Layout.cshtml,
public HomeController()
{
this.ViewData["BackgroundImage"] = "1920w/Stipula_fountain_pen.jpg";
}
and
<body style="background-image: url(#(string.Format("assets/images/{0}", ViewData["BackgroundImage"])))">
...
</body>
but ViewData is always empty inside _Layout.cshtml. Is that working as intended? I'd rather not go down the BaseViewModel/BaseController route as that feels like overkill.
EDIT: It seems as if ViewData set in the constructor isn't actually used, because once an action is executing the collection is empty. If I set ViewData inside the action then that data is passed on to _Layout.cshtml - feels like a bug to me.
You can use an action filter to set ViewData for all controller actions:
public class SetBackgroundUrlAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
var result = filterContext.Result as ViewResult;
if (result != null)
{
result.ViewData["BackgroundImage"] = "1920w/Stipula_fountain_pen.jpg";
}
}
}
[SetBackgroundUrl]
public HomeController()
{
}
Or just override OnActionExecuted method of the controller:
public override void OnActionExecuted(ActionExecutedContext context)
{
base.OnActionExecuted(context);
var result = context.Result as ViewResult;
if (result != null)
{
result.ViewData["BackgroundImage"] = "1920w/Stipula_fountain_pen.jpg";
}
}
Expanding on adem caglin's answer I went with this filter attribute, which can take an arbitrary URL:
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method, AllowMultiple = false)]
public class SetBackgroundUrlAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
if (!string.IsNullOrWhiteSpace(this.Url))
{
var result = filterContext.Result as ViewResult;
if (result != null)
result.ViewData["BackgroundImage"] = this.Url;
}
}
public string Url { get; set; }
}
and is used like so:
[SetBackgroundUrl(Url = "1920w/Stipula_fountain_pen.jpg")]
public class HomeController : Controller
{
...
}

How to set values to ViewBag in ActionFilterAttribute ASP MVC 5?

Hello I would like to create my custom ActionFilterAttribute for each controller in my application, this attribute should set some ViewBag values. Is ActionFilterAttribute would be fine for it and how to get access to viewbag in ActionFilterAttribute ?
You can do like this
public class SomeMsgAttribute : FilterAttribute, IResultFilter
{
public void OnResultExecuted(ResultExecutedContext filterContext)
{
}
public void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.Controller.ViewBag.Msg= "Hello";
}
}
Using:
[SomeMsg]
public ActionResult Index()
{
return View();
}
try this
public class CustomFilterAttribute : ActionFilterAttribute
{
public override void
OnActionExecuting(ActionExecutingContext filterContext)
{
// get the view bag
var viewBag = filterContext.Controller.ViewBag;
// set the viewbag values
viewBag.CustomValue = "CustomValue";
}
}
For ASP.NET Core you can do the following
public class SomeFilterAttribute : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
Controller controller = context.Controller as Controller;
controller.ViewBag.CustomValue = customVal;
controller.ViewData["CustomValue "] = customVal;
controller.TempData["CustomValue "] = customVal;
}
}
Then from the controller
[TypeFilter(typeof(ValidateAppFeatureEnabled))]
public IActionResult Index()
{
var foo = ViewBag.CustomValue;
var bar = (type)ViewData["CustomValue"];
var buzz = (type)TempData["CustomValue"];
// Whatever else you need to do
return View();
}
To transfer data from a different controller action
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
EmployeeTrackingSystemAndMISEntities db = new EmployeeTrackingSystemAndMISEntities();
var UserCookie = filterContext.HttpContext.Request.Cookies["UserUniqueID"];
RouteValueDictionary redirectTargetDictionary = new RouteValueDictionary();
redirectTargetDictionary.Add("action", "UserLogIn");
redirectTargetDictionary.Add("controller", "Login");
var TempData = filterContext.Controller.TempData;
TempData["Status"] = "Please log in as Admin";
filterContext.Result = new RedirectToRouteResult(redirectTargetDictionary);
}

How to pass ControllerContext to Attribute

I would like to use information from the ControllerContext or ActionContext from inside the Attribute\Filter constructor. How can i do so? Tried to pass the ControllerContext as a parameter to the attribute from the action but with no success.
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var controllerContext = filterContext.Controller.ControllerContext;
on action executing. You cannot have the context on construction
[HttpGet]
public ActionResult VideoStream(int id = 0)
{
}
public override void ExecuteResult(ControllerContext context)
{
string routedata = context.RequestContext.RouteData.Values["id"].ToString();
//The File Path
var videoFilePath = HostingEnvironment.MapPath("~/CombineFile/Tanvir.mp4");
//The header information
}

How to disable a global filter in ASP.Net MVC selectively

I have set up a global filter for all my controller actions in which I open and close NHibernate sessions. 95% of these action need some database access, but 5% don't. Is there any easy way to disable this global filter for those 5%. I could go the other way round and decorate only the actions that need the database, but that would be far more work.
You could write a marker attribute:
public class SkipMyGlobalActionFilterAttribute : Attribute
{
}
and then in your global action filter test for the presence of this marker on the action:
public class MyGlobalActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.ActionDescriptor.GetCustomAttributes(typeof(SkipMyGlobalActionFilterAttribute), false).Any())
{
return;
}
// here do whatever you were intending to do
}
}
and then if you want to exclude some action from the global filter simply decorate it with the marker attribute:
[SkipMyGlobalActionFilter]
public ActionResult Index()
{
return View();
}
Though, the accepted answer by Darin Dimitrov is fine and working well but, for me, the simplest and most efficient answer found here.
You just need to add a boolean property to your attribute and check against it, just before your logic begins:
public class DataAccessAttribute: ActionFilterAttribute
{
public bool Disable { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (Disable) return;
// Your original logic for your 95% actions goes here.
}
}
Then at your 5% actions just use it like this:
[DataAccessAttribute(Disable=true)]
public ActionResult Index()
{
return View();
}
In AspNetCore, the accepted answer by #darin-dimitrov can be adapted to work as follows:
First, implement IFilterMetadata on the marker attribute:
public class SkipMyGlobalActionFilterAttribute : Attribute, IFilterMetadata
{
}
Then search the Filters property for this attribute on the ActionExecutingContext:
public class MyGlobalActionFilter : IActionFilter
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (context.Filters.OfType<SkipMyGlobalActionFilterAttribute>().Any())
{
return;
}
// etc
}
}
At least nowadays, this is quite easy: to exclude all action filters from an action, just add the OverrideActionFiltersAttribute.
There are similar attributes for other filters: OverrideAuthenticationAttribute, OverrideAuthorizationAttribute and OverrideExceptionAttribute.
See also https://www.strathweb.com/2013/06/overriding-filters-in-asp-net-web-api-vnext/
Create a custom Filter Provider. Write a class which will implement IFilterProvider. This IFilterProvider interface has a method GetFilters which returns Filters which needs to be executed.
public class MyFilterProvider : IFilterProvider
{
private readonly List<Func<ControllerContext, object>> filterconditions = new List<Func<ControllerContext, object>>();
public void Add(Func<ControllerContext, object> mycondition)
{
filterconditions.Add(mycondition);
}
public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
return from filtercondition in filterconditions
select filtercondition(controllerContext) into ctrlContext
where ctrlContext!= null
select new Filter(ctrlContext, FilterScope.Global);
}
}
=============================================================================
In Global.asax.cs
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
MyFilterProvider provider = new MyFilterProvider();
provider.Add(d => d.RouteData.Values["action"].ToString() != "SkipFilterAction1 " ? new NHibernateActionFilter() : null);
FilterProviders.Providers.Add(provider);
}
protected void Application_Start()
{
RegisterGlobalFilters(GlobalFilters.Filters);
}
Well, I think I got it working for ASP.NET Core.
Here's the code:
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// Prepare the audit
_parameters = context.ActionArguments;
await next();
if (IsExcluded(context))
{
return;
}
var routeData = context.RouteData;
var controllerName = (string)routeData.Values["controller"];
var actionName = (string)routeData.Values["action"];
// Log action data
var auditEntry = new AuditEntry
{
ActionName = actionName,
EntityType = controllerName,
EntityID = GetEntityId(),
PerformedAt = DateTime.Now,
PersonID = context.HttpContext.Session.GetCurrentUser()?.PersonId.ToString()
};
_auditHandler.DbContext.Audits.Add(auditEntry);
await _auditHandler.DbContext.SaveChangesAsync();
}
private bool IsExcluded(ActionContext context)
{
var controllerActionDescriptor = (Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor;
return controllerActionDescriptor.ControllerTypeInfo.IsDefined(typeof(ExcludeFromAuditing), false) ||
controllerActionDescriptor.MethodInfo.IsDefined(typeof(ExcludeFromAuditing), false);
}
The relevant code is in the 'IsExcluded' method.
You can change your filter code like this:
public class NHibernateActionFilter : ActionFilterAttribute
{
public IEnumerable<string> ActionsToSkip { get; set; }
public NHibernateActionFilter(params string[] actionsToSkip)
{
ActionsToSkip = actionsToSkip;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (null != ActionsToSkip && ActionsToSkip.Any(a =>
String.Compare(a, filterContext.ActionDescriptor.ActionName, true) == 0))
{
return;
}
//here you code
}
}
And use it:
[NHibernateActionFilter(new[] { "SkipFilterAction1 ", "Action2"})]

How to get parameter in OnActionExecuting?

I modify the default route rule a little bit as below:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id= (string)null } // Parameter defaults
);
Then I can set url as:
/Controller/Action/myParam
/Home/Index/MyParam
The default Action Index would be:
public ActionResult Index(string id)
{
//....
}
I can get the param in action. But I want to get the param in OnActionExecuting. How can I do it?
You should be able to access it with :
public override void OnActionExecuting(ActionExecutingContext filterContext) {
string id = filterContext.RouteData.Values["id"];
//...
}
It can be accessible from ActionArguments inside OnActionExecuting.
public override void OnActionExecuting(ActionExecutingContext context) {
string id = context.ActionArguments["id"].ToString();
//...
}
if you want to get controller, action, and all parameters, you can do this
var valuesStr = new StringBuilder();
if (ctx.RouteData != null && ctx.RouteData.Values != null)
foreach (var v in ctx.RouteData.Values)
valuesStr.AppendFormat("/{0}", v.Value);
_logger.Info("executing {0}", valuesStr.ToString());
which results in the whole path
results with:
"/Get/Customer/215840"
it should work on multiple parameters just as well.
I use the following code to retrieve and compare the parameters passed to an action (.net core 3.1).
var vals = filterContext.ActionArguments.Values;
var fistobj = vals.FirstOrDefault();
var val = fistobj.GetType().GetProperties().FirstOrDefault(x => string.Equals(x.Name, "nameParameter", StringComparison.OrdinalIgnoreCase)).GetValue(fistobj);
if (val == null || val.ToString() != "value parameter")
{
filterContext.Result = new JsonResult(ExecuteResult.Fail(JanException.Parameter.API00001));
//base.OnActionExecuting(filterContext);
return;
}
More details for OnActionExecuting and a custom Attribute InitializingActionAttribute
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
ControllerActionDescriptor controlActionDescriptor = (ControllerActionDescriptor)filterContext.ActionDescriptor;
var attributes = controlActionDescriptor.MethodInfo.CustomAttributes;
if (attributes.Any(a => a.AttributeType == typeof(InitializingActionAttribute)))
{
var vals = filterContext.ActionArguments.Values;
var fistobj = vals.FirstOrDefault();
var val = fistobj.GetType().GetProperties().FirstOrDefault(x => string.Equals(x.Name, "nameParameter", StringComparison.OrdinalIgnoreCase)).GetValue(fistobj);
if (val == null || val.ToString() != "value parameter")
{
filterContext.Result = new JsonResult(ExecuteResult.Fail(JanException.Parameter.API00001));
//base.OnActionExecuting(filterContext);
return;
}
}
base.OnActionExecuting(filterContext);
}
From your filterContext you should be able to get whatever you need.
public class MyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Do your stuff here
}
}
[MyAttribute]
public ActionResult Index(string id)
{
//....
}

Resources