The Wayback Machine - https://web.archive.org/web/20220216055739/https://github.com/dotnet/aspnetcore/issues/40257
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blazor Server-Side sorta-kinda-breaks EF Core used in AuthorizationRequirementHandlers #40257

Open
1 task done
wasabii opened this issue Feb 15, 2022 · 0 comments
Open
1 task done

Comments

@wasabii
Copy link

@wasabii wasabii commented Feb 15, 2022

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

EF Core, if two independent execution contexts invoke any method, notices and throws an exception like 'A second operation started on this context before a previous asynchronous operation completed.'. This has been covered in a number of Blazor related issues: #17004, #16745, etc. Because of the way Blazor server-side works, with a single scope for the duration of the circuit, and multiple Components being able to enter InitializeAsync (etc) at the same time, EF Core's standard scoped model DbContext cannot work.

The recommended solution is to use either OwnedComponentBase, or resolve your DbContext's differently.

Okay. Fine.

A problem I haven't seen mentioned is how this causes issues when adding a Blazor-server application into an existing ASP.Net Core API service, while using Authorization Policies.

It is pretty normal practice, in a ASP.NET Core API, to implement custom AuthorizationRequirement and AuthorizationRequirementHandler classes, to check that certain users have access to certain policies, or resources. It is also fairly normal practice to make use of EF Core from within these Handler classes. Existing sites do this. Custom Handler classes, that evaluate the success or failure of the policy based on queries to a database.

Under normal circumstances, this works fine. AuthorizationRequirementHandler instances are scoped. And thus created for the Request. And called by DefaultAuthorizationService within the request, once.

However, simply adding a Blazor server-side application to the Web project can easily break this. Blazor has components such as AuthorizeRouteView and AuthorizeView, that as part of their component logic, resolve the AuthorizationService, and attempt to authorize the user. When running in server-side Blazor, these invocations happen during the Render (or potentially prerender) phase. And since Blazor has a habit of allowing components, each in the same Scope, to independently internal logic (InitializeAsync, etc, can be called for multiple components at the same time), it is quite easy for two independent async calls to enter into the same AuthorizationService instance at the same time. Thus, traversing down into the custom AuthorizationRequirementHandler instances, and thus down into EF Core.

This issue cannot be solved with OwnedComponentBase, since AuthorizeView and AuthorizeRouteView are the potential components that will cause this issue, and these cannot be overridden to inherit from a new base class.

This leaves one remaining option I can see: to edit your AuthorizationRequirementHandler to create nested container scopes, simply to use EF Core. This can solve the problem.

However, AuthorizationRequirementHandlers are shared between Blazor server-side and traditional MVC and Controller code. This has the unfortunate effect of forcing you to edit your AuthorizationRequirementHandler code to create nested scopes, for Blazor, but have those nested scopes created even during MVC or API Controller requests. And, worse, since it's pretty difficult to determine whether you are inside a Blazor render call or not, you can't conditionally do this within the Handlers.

Essentially, you have to write your AuthorizationRequirementHandlers in a special way, for both MVC and API controllers, simply in order to add a Blazor server-side application into the project. Blazor ends up forcing your to pollute code that otherwise wouldn't need it.

There might be other ASP.Net internal classes that are subject to this same issue. But, as it's very typical to use EF Core within AuthorizationRequirementHandlers, this is the only one I noticed.

Expected Behavior

I would expect Blazor to not introduce additional unexpected coding requirements against existing classes that conform to the basic requirements of ASP.Net Core. If Blazor intends to request AuthorizationService, and make use of it, it should expect that traditionally that class was registered scoped, and may need to take special care in the case of reentrant async executions.

Steps To Reproduce

Extend AuthorizationRequirementHandler. Conduct a EF Core operation within AuthorizeAsync. Register with ASP.Net Core. See that it works.

Add a Blazor server side application to the same project. Add an AuthorizeView. See that Blazor begins failing in the EF Core calls.

Exceptions (if any)

No response

.NET Version

No response

Anything else?

No response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants