I'm using VS2022 and Net7 web App.
I have this page, to handle common stuff so I don't have to put it in every page
public class ApplicationPageModel : PageModel
{
public IActionResult? OnGet()
{
//cookie handling
//page set up
//security checking
//etc
return null;
}
}
Then all my other pages look like this
public class PermissionsModel : ApplicationPageModel
{
public override async void OnPageHandlerExecuted(PageHandlerExecutedContext context)
{
if (context.HandlerMethod!.MethodInfo.Name == nameof(OnGet))
{
string page = HttpContext.Request.Query["id"].ToString();
//page specific code goes here'
//do something awaitable here
}
base.OnPageHandlerExecuted(context);
}
}
I can't use OnGet
in the actual page because I get this error
An unhandled exception occurred while processing the request. InvalidOperationException: Multiple handlers matched. The following handlers matched route data and had all constraints satisfied:
The problem is using OnPageHandlerExecuted
I then have to use .GetAwaiter().GetResult() on my async method because the Razor page renders before my awaitable API call completes. So any model updates (null) aren't complete so I get null exceptions in the page. For exmaple if I use:-
@foreach(var stuff in Model.Stuff)
//Model.Stuff is always null because that method completes after the page.
Without the override using a normal OnGet
everything is fine, but then I have to put code in every page and I'm planning alot of pages in my app.
I have no issues with using .GetAwaiter().GetResult()
but I'm being told its either not safe or not a good idea. How else could I acheive the same in a safe way.
Any ideas anyone?
I'd argue your actual problem isn't about await
or GetAwaiter
, but about a pretty unfortunate class-design. Your base-class seems to be in no way related to a PageModel
, but happens to have this inheritance only to share some common functionality on all your pages. This is best done using composition instead of inheritance. So after all your ApplicationModel
-class is just a utility-class. This is also indicated by your OnGet
-method just returning null
instead of a valid response. So instead of deriving that utility-class, just use it:
class static ApplicationHelpers
{
public static async Task DoSomething() { await something }
}
public class MyPage : PageModel
{
// now you can easily implement OnGet here, no more naming-collisions
public Task<IActionResult> OnGetAsync()
{
// do the commmon stuff
await ApplicationHelpers.DoSomething();
// do the page-specific stuff here
}
}
As ApplicationHelpers.DoSomething
(or whatever you name it) now makes some request as well, you are free to make it async
and thus to avoid this annoying GetAwaiter
-thing in the first place. Of course you should consider to inject the dependency to this helper-class in your Program.cs
-file somehow, for brevity I omited that and made the class static
.
If you can't change the inheritance for whatever reason, you could at least just rename the OnGet
-function in your base-class, as the method is not really a request-handler. Instead it is just some common logic that should happen when a request is done. So just call that function withkin every request-handler like so:
class ApplicationPageModel : PageModel
{
public async Task DoSomething() { await something }
}
public class MyPage : PageModel
{
// now you can easily implement OnGet here, no more naming-collisions
public Task<IActionResult> OnGetAsync()
{
// do the commmon stuff
await base.DoSomething();
// do the page-specific stuff here
}
}