-
Notifications
You must be signed in to change notification settings - Fork 14
Tutorial 02 05 Entity Collection Endpoints
Entity collection endpoints enable you to expose collections of entities, such as "all customers", "all orders", etc.
Here is an example of an entity collection endpoint URL for all customers:
https://localhost:8086/odata/v1/Customers
Your first reaction might be, "Why would I want to do that? I don't have a use case for exposing everything at once." But remember, you're building an OData service, and with OData, the developers writing applications to interact with your service will use OData query URLs to specify the data they need. So exposing all entities in a collection is completely normal. In fact, it is the most common thing that OData services do.
To generate endpoints that expose entity collections, you must set the Enable collection endpoints
option.
-
At a Windows prompt, move to the directory with your Harmony Core solution and type
harmonycore gui
. When the GUI for the Harmony Core CLI tool opens, go to the OData screen, scroll down to theEnable collection endpoints
option, and double-click it. -
In the "Enter new value" screen, click the diamond icon to the right of
Enable collection endpoints
. (The diamond will change to a checkmark.) Then click OK.
-
Save the setting you made by selecting
File > Save
from the menu. -
Regenerate generated code for your solution by selecting
Codegen > Regen
from the menu.
When code generation is finished, a message will list the files that were generated.
Enabling this feature causes a GET method to be generated in each of your controller classes. Let's see what this method looks like in Services.Controllers\CustomersController.dbl
.
- In Visual Studio Solution Explorer, double-click
Services.Controllers\CustomersController.dbl
to open the file in the editor, and then scroll down to theGetCustomers
method declaration. The method accepts no parameters and returns a collection of all customers. You will find similar code in the other controllers.
If you examine the GetCustomers
method declaration, you will notice it is decorated with attributes that specify the way operations exposed by the controller are accessed. For example, the {HttpGet("Customers")}
attribute specifies that this endpoint will be accessed by adding “Customers” to the base address of the service:
https://localhost:8086/odata/v1/Customers
The other attributes for this method define the type of returned data (application/json), HTTP status codes to be returned, and the maximum depth for the $expand
query option (4 levels).
{HttpGet("Customers")}
{Produces("application/json")}
{ProducesResponseType(^typeof(IEnumerable<Customer>),StatusCodes.Status200OK)}
{EnableQuery(MaxExpansionDepth=4)}
;;; <summary>
;;; Get all Customers
;;; </summary>
;;; <returns>Returns an IActionResult indicating the status of the operation and containing any data that was returned.</returns>
public method GetCustomers, @IActionResult
proc
mreturn Ok(_DbContext.Customers.AsNoTracking())
endmethod
Above this method, you will see a constructor method that accepts instances of various objects and saves references to them in these class variables:
;;Services provided via dependency injection
private _DbContext, @Services.Models.DBContext
private _ServiceProvider, @IServiceProvider
private _AppSettings, @IOptions<AppSettings>
;;; <summary>
;;; Constructs a new instance of CustomersController
;;; </summary>
;;; <param name="aDbContext">Database context instance (DI)</param>
;;; <param name="aServiceProvider">Service provider instance (DI)</param>
;;; <param name="aAppSettings">Application settings</param>
public method CustomersController
aDbContext, @Services.Models.DBContext
aServiceProvider, @IServiceProvider
aAppSettings, @IOptions<AppSettings>
proc
this._DbContext = aDbContext
this._ServiceProvider = aServiceProvider
this._AppSettings = aAppSettings
endmethod
What you see here in this constructor method is the dependency injection pattern. The service's startup code registers several useful services and makes them available throughout the environment via dependency injection. Classes in the web service can receive instances of those services, as needed, by declaring specifically-typed parameters on their constructor methods.
In this case, the constructor method doesn't need to use these services directly, so it saves references to the service objects in local class variables. This way they will be accessible to other code in the class that may need to use them later.
This code (constructor, method, etc.) is not new. It was present prior to enabling the entity collection endpoints. But it is useful to have an overall understanding of what the code is doing.
-
Select
Build > Rebuild Solution
from the Visual Studio menu. -
Check the Output window, you should see something like this:
1>------ Rebuild All started: Project: Repository, Configuration: Debug Any CPU ------ 2>------ Rebuild All started: Project: Services.Models, Configuration: Debug Any CPU ------ 3>------ Rebuild All started: Project: Services.Controllers, Configuration: Debug Any CPU ------ 4>------ Rebuild All started: Project: Services.Isolated, Configuration: Debug Any CPU ------ 5>------ Rebuild All started: Project: Services, Configuration: Debug Any CPU ------ 6>------ Rebuild All started: Project: Services.Host, Configuration: Debug Any CPU ------ ========== Rebuild All: 6 succeeded, 0 failed, 0 skipped ==========
- In Visual Studio, press F5 (
Start Debugging
) to start the self-hosting application.
Once again you should see the console window appear, with a message confirming that your service is running.
- With your web browser, go to the "all customers" endpoint:
You should see a JSON response that includes the full record for all 38 customers in the sample customer data file.
You should also be able to do the same with the "all entities" endpoints for the other four entity types:
* https://localhost:8086/odata/v1/Items
* https://localhost:8086/odata/v1/Orders
* https://localhost:8086/odata/v1/OrderItems
* https://localhost:8086/odata/v1/Vendors
The data returned by the Orders and OrderItems endpoints is relatively large and might take a few seconds to render in your browser. REST assured (pun intended), the Harmony Core service returned the data very quickly, but it takes your web browser a few seconds to deal with all that incoming data!
- When you are finished testing the endpoints, stop the self-hosting application.
Enabling collection endpoints adds endpoints to all your code-generated OData controllers, but it is possible to prevent the generation of these endpoints for certain structures. This capability is documented in Structure-Specific Endpoint Control.
Next topic: API Documentation
-
Tutorial 2: Building a Service from Scratch
- Creating a Basic Solution
- Enabling OData Support
- Configuring Self Hosting
- Entity Collection Endpoints
- API Documentation
- Single Entity Endpoints
- OData Query Support
- Alternate Key Endpoints
- Expanding Relations
- Postman Tests
- Supporting CRUD Operations
- Adding a Primary Key Factory
- Adding Create Endpoints
- Adding Upsert Endpoints
- Adding Patch Endpoints
- Adding Delete Endpoints
-
Harmony Core Code Generator
-
OData Aware Tools
-
Advanced Topics
- CLI Tool Customization
- Adapters
- API Versioning
- Authentication
- Authorization
- Collection Counts
- Customization File
- Custom Field Types
- Custom File Specs
- Custom Properties
- Customizing Generated Code
- Deploying to Linux
- Dynamic Call Protocol
- Environment Variables
- Field Security
- File I/O
- Improving AppSettings Processing
- Logging
- Optimistic Concurrency
- Multi-Tenancy
- Publishing in IIS
- Repeatable Unit Tests
- Stored Procedure Routing
- Suppressing OData Metadata
- Traditional Bridge
- Unit Testing
- EF Core Optimization
- Updating a Harmony Core Solution
- Updating to 3.1.90
- Creating a new Release
-
Background Information