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?
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);
}
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;
});
});
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