Skip to content

Automatically building OData APIs (Dynamic data context)

Maxim edited this page Feb 9, 2021 · 15 revisions

ASP.NET Core Middleware
For create server from only connection string, add reference to project \source\OdataToEntity.EfCore.DynamicDataContext

  • Sql Server
public void Configure(IApplicationBuilder app)
{
    var optionsBuilder = new DbContextOptionsBuilder<DynamicDbContext>();
    optionsBuilder = optionsBuilder.UseSqlServer("Server=.\\sqlexpress;Initial Catalog=OdataToEntity;Trusted_Connection=Yes;");
    using (ProviderSpecificSchema providerSchema = new SqlServerSchema(optionsBuilder.Options))
    {
        IEdmModel edmModel = DynamicMiddlewareHelper.CreateEdmModel(providerSchema, informationSchemaSettings: null);
        app.UseOdataToEntityMiddleware<OePageMiddleware>("/api", edmModel);
    }
}
  • PostgreSql
public void Configure(IApplicationBuilder app)
{
    var optionsBuilder = new DbContextOptionsBuilder<DynamicDbContext>();
    optionsBuilder = optionsBuilder.UseNpgsql("Host=localhost;Port=5432;Database=OdataToEntity;Pooling=true");
    using (ProviderSpecificSchema providerSchema = new PostgreSqlSchema(optionsBuilder.Options))
    {
        IEdmModel edmModel = DynamicMiddlewareHelper.CreateEdmModel(providerSchema, informationSchemaSettings: null);
        app.UseOdataToEntityMiddleware<OePageMiddleware>("/api", edmModel);
    }
}
  • MySql
public void Configure(IApplicationBuilder app)
{
    var optionsBuilder = new DbContextOptionsBuilder<DynamicDbContext>();
    optionsBuilder = optionsBuilder.UseMySql("server=localhost;database=dbo;user=root;password=123456");
    using (ProviderSpecificSchema providerSchema = new MySqlSchema(optionsBuilder.Options))
    {
        IEdmModel edmModel = DynamicMiddlewareHelper.CreateEdmModel(providerSchema, informationSchemaSettings: null);
        app.UseOdataToEntityMiddleware<OePageMiddleware>("/api", edmModel);
    }
}

HTTP server
Solution file - \sln\OdataToEntity.Test.DynamicDataContext.sln
Example implementation http server - \test\OdataToEntity.Test.DynamicDataContext.AspServer.
Http server configuration is done through the appsettings.json file.

  "OdataToEntity": {
    "BasePath" :  "api",
    "Provider": "sqlserver",
    "ConnectionString": "Server=.\\sqlexpress;Initial Catalog=OdataToEntity;Trusted_Connection=Yes;",
    "UseRelationalNulls": true,
    "DefaultSchema": "dbo",
    "IncludedSchemas": [ "dbo", "test" ],
    "ExcludedSchemas": null,
    "Filter": "all",
    "InformationSchemaMappingFileName": "InformationSchemaMapping.json"
  }

"BasePath" - base path in the server URL.
"Provider" - database type, possible values mysql, postgresql, sqlserver.
"ConnectionString" - connection string to the database.
"UseRelationalNulls" - indicates whether or not to use relational database semantics when comparing null values.
"DefaultSchema": - for tables containing this schema, the entity set name will be generated without the schema name prefix. "IncludedSchemas" - list of schemas to select, option applied only if is is not empty. Mutually exclusive with option ExcludedSchemas.
"ExcludedSchemas" - list of schemas to exclude from select, option applied only if is is not empty. Mutually exclusive with option IncludedSchemas.
"Filter" - all: use all database objects, mapping: only objects listed in InformationSchemaMapping.json.
"InformationSchemaMappingFileName" - custom mapping the database to the OData schema.

For additional customization of tables and foreign keys names, used InformationSchemaMapping.json file is a serialized class InformationSchemaMapping.

An example for use in your code

//Load our schema mappings (optional)
InformationSchemaMapping informationSchemaMapping = GetMappings();

//Configure context
var optionsBuilder = new DbContextOptionsBuilder<DynamicDbContext>();
optionsBuilder = optionsBuilder.UseSqlServer("Server=.\\sqlexpress;Initial Catalog=OdataToEntity;Trusted_Connection=Yes;");

IEdmModel dynamicEdmModel;
//Create database schema
using (ProviderSpecificSchema providerSchema = new SqlServerSchema(optionsBuilder.Options))
using (var metadataProvider = providerSchema.CreateMetadataProvider(informationSchemaMapping))
{
    //Create ef entity types manager
    DynamicTypeDefinitionManager typeDefinitionManager = DynamicTypeDefinitionManager.Create(metadataProvider);
    //Create adapter data access
    var dataAdapter = new DynamicDataAdapter(typeDefinitionManager);
    //Build OData edm model
    dynamicEdmModel = dataAdapter.BuildEdmModel(metadataProvider);
}

//Create query parser
var parser = new OeParser(new Uri("http://dummy"), dynamicEdmModel);
//Query
var uri = new Uri("http://dummy/Orders?$expand=Customer,Items&$orderby=Id");
//The result of the query
var stream = new MemoryStream();
//Execute query
await parser.ExecuteGetAsync(uri, OeRequestHeaders.JsonDefault, stream, CancellationToken.None);
stream.Position = 0;
//Get result as string
Console.WriteLine(new StreamReader(stream).ReadToEnd());