Creating A Simple Data-Driven CRUD Microservice - Microsoft Docs
Creating A Simple Data-Driven CRUD Microservice - Microsoft Docs
microservice
01/13/2021 • 16 minutes to read • +3
In this article
Designing a simple CRUD microservice
Implementing a simple CRUD microservice with ASP.NET Core
The DB connection string and environment variables used by Docker containers
Generating Swagger description metadata from your ASP.NET Core Web API
This section outlines how to create a simple microservice that performs create, read,
update, and delete (CRUD) operations on a data source.
Figure 6-6. Creating an ASP.NET Core Web API project in Visual Studio 2019
To create an ASP.NET Core Web API Project, first select an ASP.NET Core Web
Application and then select the API type. After creating the project, you can implement
your MVC controllers as you would in any other Web API project, using the Entity
Framework API or other API. In a new Web API project, you can see that the only
dependency you have in that microservice is on ASP.NET Core itself. Internally, within
the Microsoft.AspNetCore.All dependency, it is referencing Entity Framework and many
other .NET NuGet packages, as shown in Figure 6-7.
Figure 6-7. Dependencies in a simple CRUD Web API microservice
The API project includes references to Microsoft.AspNetCore.App NuGet package, that
includes references to all essential packages. It could include some other packages as
well.
C# = Copy
You also need a DbContext that represents a session with the database. For the catalog
microservice, the CatalogContext class derives from the DbContext base class, as shown
in the following example:
C# = Copy
You can have additional DbContext implementations. For example, in the sample
Catalog.API microservice, there's a second DbContext named CatalogContextSeed
where it automatically populates the sample data the first time it tries to access the
database. This method is useful for demo data and for automated testing scenarios, as
well.
Within the DbContext , you use the OnModelCreating method to customize
object/database entity mappings and other EF extensibility points .
C# = Copy
[Route("api/v1/[controller]")]
public class CatalogController : ControllerBase
{
private readonly CatalogContext _catalogContext;
private readonly CatalogSettings _settings;
private readonly ICatalogIntegrationEventService _catalogIntegra‐
tionEventService;
public CatalogController(
CatalogContext context,
IOptionsSnapshot<CatalogSettings> settings,
ICatalogIntegrationEventService
catalogIntegrationEventService)
{
_catalogContext = context ?? throw new
ArgumentNullException(nameof(context));
_catalogIntegrationEventService = catalogIntegrationEventSer‐
vice
?? throw new ArgumentNullException(nameof(catalogIntegra‐
tionEventService));
_settings = settings.Value;
context.ChangeTracker.QueryTrackingBehavior = QueryTracking‐
Behavior.NoTracking;
}
// GET api/v1/[controller]/items[?pageSize=3&pageIndex=10]
[HttpGet]
[Route("items")]
[ProducesResponseType(typeof(PaginatedItemsViewModel<CatalogItem>),
(int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(IEnumerable<CatalogItem>),
(int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> ItemsAsync(
[FromQuery]int pageSize = 10,
[FromQuery]int pageIndex = 0,
string ids = null)
{
if (!string.IsNullOrEmpty(ids))
{
var items = await GetItemsByIdsAsync(ids);
if (!items.Any())
{
return BadRequest("ids value invalid. Must be comma-
separated list of numbers");
}
return Ok(items);
}
itemsOnPage = ChangeUriPlaceholder(itemsOnPage);
return Ok(model);
}
//...
}
Saving data
Data is created, deleted, and modified in the database using instances of your entity
classes. You could add code like the following hard-coded example (mock data, in this
case) to your Web API controllers.
C# = Copy
var catalogItem = new CatalogItem() {CatalogTypeId=2,
CatalogBrandId=2,
Name="Roslyn T-Shirt", Price =
12};
_context.Catalog.Add(catalogItem);
_context.SaveChanges();
An important configuration to set up in the Web API project is the DbContext class
registration into the service's IoC container. You typically do so in the Startup class by
calling the services.AddDbContext<CatalogContext>() method inside the
ConfigureServices() method, as shown in the following simplified example:
C# = Copy
typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
});
//...
}
Additional resources
Querying Data
https://docs.microsoft.com/ef/core/querying/index
Saving Data
https://docs.microsoft.com/ef/core/saving/index
JSON = Copy
{
"ConnectionString": "Server=tcp:127.0.0.1,5433;Initial
Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User
Id=sa;Password=[PLACEHOLDER]",
"ExternalCatalogBaseUrl": "http://localhost:5101",
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
The settings.json file can have default values for the ConnectionString property or for
any other property. However, those properties will be overridden by the values of
environment variables that you specify in the docker-compose.override.yml file, when
using Docker.
From your docker-compose.yml or docker-compose.override.yml files, you can initialize
those environment variables so that Docker will set them up as OS environment
variables for you, as shown in the following docker-compose.override.yml file (the
connection string and other lines wrap in this example, but it would not wrap in your
own file).
yml = Copy
# docker-compose.override.yml
#
catalog-api:
environment:
- ConnectionString=Server=sqldata;Database=Microsoft.eShopOnCon‐
tainers.Services.CatalogDb;User Id=sa;Password=[PLACEHOLDER]
# Additional environment variables for this service
ports:
- "5101:80"
The docker-compose.yml files at the solution level are not only more flexible than
configuration files at the project or microservice level, but also more secure if you
override the environment variables declared at the docker-compose files with values set
from your deployment tools, like from Azure DevOps Services Docker deployment tasks.
Finally, you can get that value from your code by using
Configuration["ConnectionString"], as shown in the ConfigureServices method in an
earlier code example.
However, for production environments, you might want to explore additional ways on
how to store secrets like the connection strings. An excellent way to manage application
secrets is using Azure Key Vault .
Azure Key Vault helps to store and safeguard cryptographic keys and secrets used by
your cloud applications and services. A secret is anything you want to keep strict control
of, like API keys, connection strings, passwords, etc. and strict control includes usage
logging, setting expiration, managing access, among others.
Azure Key Vault allows a detailed control level of the application secrets usage without
the need to let anyone know them. The secrets can even be rotated for enhanced
security without disrupting development or operations.
Applications have to be registered in the organization's Active Directory, so they can use
the Key Vault.
You can check the Key Vault Concepts documentation for more details.
Implementing versioning in ASP.NET Web APIs
As business requirements change, new collections of resources may be added, the
relationships between resources might change, and the structure of the data in
resources might be amended. Updating a Web API to handle new requirements is a
relatively straightforward process, but you must consider the effects that such changes
will have on client applications consuming the Web API. Although the developer
designing and implementing a Web API has full control over that API, the developer
does not have the same degree of control over client applications that might be built by
third-party organizations operating remotely.
Versioning enables a Web API to indicate the features and resources that it exposes. A
client application can then submit requests to a specific version of a feature or resource.
There are several approaches to implement versioning:
URI versioning
Query string versioning
Header versioning
Query string and URI versioning are the simplest to implement. Header versioning is a
good approach. However, header versioning is not as explicit and straightforward as URI
versioning. Because URL versioning is the simplest and most explicit, the
eShopOnContainers sample application uses URI versioning.
With URI versioning, as in the eShopOnContainers sample application, each time you
modify the Web API or change the schema of resources, you add a version number to
the URI for each resource. Existing URIs should continue to operate as before, returning
resources that conform to the schema that matches the requested version.
As shown in the following code example, the version can be set by using the Route
attribute in the Web API controller, which makes the version explicit in the URI (v1 in this
case).
C# = Copy
[Route("api/v1/[controller]")]
public class CatalogController : ControllerBase
{
// Implementation ...
This versioning mechanism is simple and depends on the server routing the request to
the appropriate endpoint. However, for a more sophisticated versioning and the best
method when using REST, you should use hypermedia and implement HATEOAS
(Hypertext as the Engine of Application State).
Additional resources
Scott Hanselman. ASP.NET Core RESTful Web API versioning made easy
https://www.hanselman.com/blog/ASPNETCoreRESTfulWebAPIVersioningMadeEas
y.aspx
Versioning a RESTful web API
/azure/architecture/best-practices/api-design#versioning-a-restful-web-api
Roy Fielding. Versioning, Hypermedia, and REST
https://www.infoq.com/articles/roy-fielding-on-versioning
C# = Copy
Once this is done, you can start your application and browse the following Swagger
JSON and UI endpoints using URLs like these:
Console = Copy
http://<your-root-url>/swagger/v1/swagger.json
http://<your-root-url>/swagger/
You previously saw the generated UI created by Swashbuckle for a URL like
http://<your-root-url>/swagger . In Figure 6-9, you can also see how you can test
any API method.
Additional resources
ASP.NET Web API Help Pages using Swagger
https://docs.microsoft.com/aspnet/core/tutorials/web-api-help-pages-using-
swagger
Get started with Swashbuckle and ASP.NET Core
https://docs.microsoft.com/aspnet/core/tutorials/getting-started-with-
swashbuckle
Get started with NSwag and ASP.NET Core
https://docs.microsoft.com/aspnet/core/tutorials/getting-started-with-nswag
Previous Next