Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disabling OData V4 meta data and controllers at runtime

We have several modules in our software that ship as a single product. When a module is activated, those features become available. We would like our OData APIs to follow the same pattern. However I can't figure out how to make the $metadata ignore controllers for modules that have been disabled. Basically I want to determine what is available at any time instead of application start time.

We are using the following type of cod to register the routes:

    static public void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();
        var builder = new ODataConventionModelBuilder();
        builder.EntitySet<Module1Entity>("Module1Entities");
        builder.EntitySet<Module2Entity>("Module2Entities");
        config.MapODataServiceRoute("odata", "api", builder.GetEdmModel());
    }

    protected void Application_Start(object sender, EventArgs e)
    {
        GlobalConfiguration.Configure(Register);
    }

So we only want Module1Entity to show up in the metadata if the module has been activated. We already have code to disable the associated controller when the module is deactivated.

Any ideas?

like image 226
John Somsky Avatar asked Nov 08 '22 11:11

John Somsky


2 Answers

I ended up finding a solution:

static public void Register(HttpConfiguration config)
{
    config.MapHttpAttributeRoutes();
    var builder = new ODataConventionModelBuilder();
    if (IsModule1Enabled)
    {
        builder.EntitySet<Module1Entity>("Module1Entities");
    {
    if (IsModule2Enabled)
    {
       builder.EntitySet<Module2Entity>("Module2Entities");
    }
    var conventions = ODataRoutingConventions.CreateDefault();
    conventions.Insert(0, new MyAttributeRoutingConvention("odata", config));
    config.MapODataServiceRoute("odata", "api", builder.GetEdmModel(), new DefaultODataPathHandler(), conventions);

}

public class MyAttributeRoutingConvention : AttributeRoutingConvention
{
    public MyAttributeRoutingConvention(string routeName, HttpConfiguration configuration) : base(routeName, configuration)
    {
    }

    public override bool ShouldMapController(HttpControllerDescriptor controller)
    {
       if (controller.ControllerType == typeof(Module1EntitiesController))
       {
          return IsModule1Enabled;
       }
       if (controller.ControllerType == typeof(Module2EntitiesController))
       {
          return IsModule2Enabled;
       }
       return base.ShouldMapController(controller);
    }
 }


protected void Application_Start(object sender, EventArgs e)
{
    GlobalConfiguration.Configure(Register);
}
like image 145
John Somsky Avatar answered Nov 15 '22 06:11

John Somsky


Finally i found easier way.

This startup code ovveride OData $metadata path and return response forbidden.

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            endpoints.EnableDependencyInjection();
            endpoints.Select().Filter().OrderBy().Count().MaxTop(24);
            endpoints.MapODataRoute("ODataRoute", "odata", GetEdmModel());
            endpoints.MapGet("/odata/$metadata", async context =>
            {
                context.Response.StatusCode = 403;
                await context.Response.WriteAsync("Forbidden!");
            });
            endpoints.MapGet("/", context =>
            {
                context.Response.Redirect("/swagger");
                return Task.CompletedTask;
            });
        });
like image 21
Necip Sunmaz Avatar answered Nov 15 '22 06:11

Necip Sunmaz