I have an extension for ActionResult that adds a toast to TempData when returning a page:
public static IActionResult WithMessage(this ActionResult result, InformMessage msg)
{
return new InformMessageResult(result, msg);
}
and this is InformMessageResult:
public class InformMessageResult : ActionResult
{
public ActionResult InnerResult { get; set; }
public InformMessage InformMessage { get; set; }
public InformMessageResult (ActionResult innerResult, InformMessage informMsg)
{
InnerResult = innerResult;
InformMessage = informMsg;
}
public override async Task ExecuteResultAsync(ActionContext context)
{
ITempDataDictionaryFactory factory = context.HttpContext.RequestServices.GetService(typeof(ITempDataDictionaryFactory)) as ITempDataDictionaryFactory;
ITempDataDictionary tempData = factory.GetTempData(context.HttpContext);
tempData.Put("InformMessage", InformMessage);
await InnerResult.ExecuteResultAsync(context);
}
}
This works well with
return RedirectToPage(etc).WithMessage(etc)
and the like, but fails with
return Page().WithMessage(etc)
and the debugger highlights
await InnerResult.ExecuteResultAsync(context);
saying InnerResult not set to an instance of an object.
Is there a way I can make this work with Return Page()?
Edit for additional info:
I tested what was being sent in as the "InnerResult" and it looks like with Return Page(), everything is null (by design, I'd say, as I do nothing to it before that point):
with RedirectToPage():
With Page():
This is an older question, but I needed functionality like this myself, and dug deep to find the reason.
As you can see from your debugging, the Page
method generates a completely blank PageResult
. Being as every property is null, calling ExecuteResultAsync
on it fails as it obviously can't do anything with all-null values.
The reason Page()
otherwise works the rest of the time is due to behind-the-scenes magic in PageActionInvoker, specifically in its InvokeResultAsync method. It will detect that your ViewData and Page are blank and populate them before it, itself, calls the pageResult.ExecuteResultAsync
method.
Hence, you can still get your InformMessageResult
to work if you do the same work as PageActionInvoker does. Here's how:
public override async Task ExecuteResultAsync(ActionContext context)
{
/* temp data work goes here */
if (InnerResult is PageResult pageResult)
{
var pageContext = context as PageContext
?? throw new ArgumentException("context must be a PageContext if your InnerResult is a PageResult.", "context");
var pageFactoryProvider = pageContext.HttpContext.RequestServices.GetRequiredService<IPageFactoryProvider>();
var pageFactory = pageFactoryProvider.CreatePageFactory(pageContext.ActionDescriptor);
var viewContext = new ViewContext(
pageContext,
NullView.Instance,
pageContext.ViewData,
tempData,
TextWriter.Null,
new Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelperOptions()
);
viewContext.ExecutingFilePath = pageContext.ActionDescriptor.RelativePath;
pageResult.ViewData = viewContext.ViewData;
pageResult.Page = (PageBase)pageFactory(pageContext, viewContext);
}
await InnerResult.ExecuteResultAsync(context);
}
private class NullView : IView
{
public static readonly NullView Instance = new NullView();
public string Path => string.Empty;
public Task RenderAsync(ViewContext context)
{
if (context == null) throw new ArgumentNullException("context");
return Task.CompletedTask;
}
}
The problem I suspect is that Page() and RedirectToPage() inherit from different base classes.
RedirectToPage() as per this documentation. It has the following Inheritance:
Object -> ActionResult -> RedirectToPageResult
This is exposed by some inheritance of the controller. So you're extension of ActionResult
is available to be used.
However the Page() method is part of a RazorPages class as per this documentation. So it's inheritance is as follows:1
Object -> RazorPageBase -> PageBase -> Page
Now the Page() method of that class does return a PageResult
which looks to inherit from ActionResult
as defined here.
So with that in mind I'd suggest casting it to the base ActionResult
first, and then using your extension method. Something like this perhaps:
var baseClass = (Page() as ActionResult);
return baseClass.WithMessage(etc);
1 You can see the base type in the second image the OP supplied.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With