Reputation: 34632
The site I am creating custom colors that can be set by the user (only on certain pages). I want to grab that data within an ActionFilterAttribute and set it in the ViewBag so I can then get the data in my _Layout.cshtml.
Here is my ActionFilterAttribute...
public class PopulateColorOptionsAttribute : ActionFilterAttribute
{
private readonly OptionsDataHelper optionsDataHelper;
public PopulateOptionsAttribute(OptionsDataHelper optionsDataHelper)
{
this.optionsDataHelper = optionsDataHelper;
}
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
await base.OnActionExecutionAsync(context, next);
// Get the cemetery data and set it on the view bag.
var personId = Convert.ToInt32(context.RouteData.Values["personId"]);
context.Controller.ViewBag.OptionsData = await optionsDataHelper.GetValueAsync(personId, CancellationToken.None);
}
}
Unfortunately, I receive an error on ViewBag that states:
'object' does not contain a definition for 'ViewBag' and no extension method 'ViewBag' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) [dnx451]
I'm pretty sure I'm not understanding something correctly about Filters and I would appreciate guidance on how to achieve what I am looking to do.
Upvotes: 8
Views: 7450
Reputation: 31
Cast the context.Controller as Controller
Try to change the following line
context.Controller.ViewBag.OptionsData = await optionsDataHelper.GetValueAsync(personId, CancellationToken.None);
to
((Controller)(context.Controller)).ViewBag.OptionsData = await optionsDataHelper.GetValueAsync(personId, CancellationToken.None);
Upvotes: 1
Reputation: 34992
ActionExecutingContext.Controller
is declared of type Object
since the framework doesn't impose any restriction on which classes can be controllers.
If you are always creating your controllers inheriting from the base Controller
class, then you can use that assumption in your filter and cast context.Controller
as Controller
:
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
await base.OnActionExecutionAsync(context, next);
var controller = context.Controller as Controller;
if (controller == null) return;
controller.ViewBag.Message = "Foo message";
}
If you cannot make that assumption, then you can use a similar approach inspecting the result in the context:
public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
var viewResult = context.Result as ViewResult; //Check also for PartialViewResult and ViewComponentResult
if (viewResult == null) return;
dynamic viewBag = new DynamicViewData(() => viewResult.ViewData);
viewBag.Message = "Foo message";
await base.OnResultExecutionAsync(context, next);
}
Upvotes: 22