Skip to content

Question: Construct EdmModels on a per request basis? #1134

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

Open
aniliht opened this issue May 14, 2025 · 2 comments
Open

Question: Construct EdmModels on a per request basis? #1134

aniliht opened this issue May 14, 2025 · 2 comments

Comments

@aniliht
Copy link

aniliht commented May 14, 2025

Hello,
Thank you for the support and maintaining this library. I'm in the process of updating my code from
.NET6 and OData v7

    <PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.0.0" />
    <PackageReference Include="Microsoft.AspNetCore.OData" Version="7.7.1" />
    <PackageReference Include="Microsoft.AspNetCore.OData.Versioning" Version="4.1.1" />

to .NET8 and OData v8 and updated versioning:

    <PackageReference Include="Asp.Versioning.Mvc" Version="8.1.0" />
    <PackageReference Include="Asp.Versioning.OData" Version="8.1.0" />
    <PackageReference Include="Microsoft.AspNetCore.OData" Version="8.2.7" />

In my old code, I was able to construct the OData EDM Models on a per request basis (depending on the user's claims). So the structure of the EDMs would vary based on the user's claims. I do this to hide certain entitySets that certain users shouldn't have access to OR not expose certain properties on a specific entitys. I'm wondering if there's a way to do it similarly in the newer library?

How I did it in my old code:

            app.UseMvc(routeBuilder =>
            {
                routeBuilder.Count();
                routeBuilder.SetTimeZoneInfo(TimeZoneInfo.Utc);
                routeBuilder.MapVersionedODataRoute(routeNameV1, string.Empty, new ApiVersion(1, 0), GetODataContainerBuilder(routeNameV1, routeBuilder));
            });


        private Action<IContainerBuilder> GetODataContainerBuilder(string routeName, IRouteBuilder routeBuilder)
        {
            return containerBuilder =>
            {
                containerBuilder.AddService(Microsoft.OData.ServiceLifetime.Scoped, sp =>
                {
                    var httpRequestScope = sp.GetRequiredService<HttpRequestScope>();
                    var claims = httpRequestScope?.HttpRequest?.HttpContext?.User?.Claims;
                    if (httpRequestScope?.HttpRequest?.HttpContext?.User?.Identity?.IsAuthenticated == true)
                    {
                        return EdmModelFactory.GetEdmModel(claims);
                    }
                    else
                    {
                        return EdmModelFactory.Empty;
                    }
                });

                containerBuilder.AddService<IEnumerable<IODataRoutingConvention>>(Microsoft.OData.ServiceLifetime.Singleton, sp =>
                    ODataRoutingConventions.CreateDefaultWithAttributeRouting(routeName, routeBuilder));
            };

        }

For now, I'm using pretty much the pattern shown in the provided examples and am planning to workaround not being able to dynamically generate EDM's based on the User's claims.

Thank you!

@commonsensesoftware
Copy link
Collaborator

OData 8+ fundamentally changed how things work under the hood. The EDM and routes are built ahead of time. The only way I know of that you can get in front of the EDM is via IOptions<ODataOptions>. This is what API Versioning itself does. It's very yucky and comes with all kinds of sharp edges. You can have a look at:

public void OnProvidersExecuted( ApplicationModelProviderContext context )

and

For this type of scenario, I think you'd be better off adding annotations to your model and changing the ODataInputFormatter and ODataOutputFormatter to control/limit what goes over the wire. There might even other alternatives, but that's what immediately comes to mind. If you do come up with some way to copy or generate a new EDM, don't for forget to add or copy the ApiVersionAnnotation. I expect API Versioning with OData will break without that.

Hopefully that points you in the right direction.

@aniliht
Copy link
Author

aniliht commented May 14, 2025

Thank you very much for your quick and detailed response. I'll give some of those ideas a try. Cheers.

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

No branches or pull requests

2 participants