🎉 Welcome back, Netcode-Hub community!
We are diving into the exciting world of Docker and MongoDB! If you've been following our series, you know we've already covered how to run .NET Web API with SQLite, SQL Server, and PostgreSQL. Today, we're taking it a step further by showing you how to connect your .NET Web API to MongoDB, all within a Docker container! 🌐💻
Scenario
Imagine you’re working on a project that involves handling a large amount of unstructured data—like logs, real-time analytics, or IoT data. MongoDB, a NoSQL database, is perfect for this scenario due to its flexible schema design. By running your .NET Web API connected to MongoDB in a Docker container, you ensure a consistent environment across all stages of development, testing, and production. This setup allows you to quickly spin up instances, making your development workflow much more efficient and scalable.
Summary
In this tutorial, we'll walk you through:
- Setting Up MongoDB in Docker: We’ll start by pulling the official MongoDB image from Docker Hub and setting up a container.
- Configuring .NET Web API: Next, we'll modify our .NET Web API project to connect to the MongoDB instance.
- Running Everything Together: Finally, we'll use Docker Compose to orchestrate both the MongoDB and .NET Web API containers, ensuring seamless communication between them.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "mongodb://mongo:27017"
},
"MongoDB": {
"DatabaseName": "MyMongoDatabase",
"CollectionName": "MyMongoCollection"
}
}
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="x.x.x" />
<PackageReference Include="MongoDB.Driver" Version="x.x.x" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="x.x.x" />
public class Product
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string? Id { get; set; }
[BsonElement("Name")]
public string? Name { get; set; }
[BsonElement("Description")]
public string? Description { get; set; }
[BsonElement("Quantity")]
public int Quantity { get; set; }
}
public class ProductDbContext
{
private readonly IMongoDatabase _database;
private readonly IConfiguration Configuration;
public ProductDbContext(IConfiguration configuration)
{
Configuration = configuration;
string connectionString = Configuration.GetConnectionString("DefaultConnection")!;
string databaseName = Configuration.GetSection("MongoDB:DatabaseName").Value!;
var client = new MongoClient(connectionString);
_database = client.GetDatabase(databaseName);
}
public IMongoCollection<Product> Products =>
_database.GetCollection<Product>(Configuration.GetSection("MongoDB:CollectionName").Value!);
}
public static class ProductEndpoints
{
public static void MapProductEndpoints(this IEndpointRouteBuilder routes)
{
var group = routes.MapGroup("/api/Product").WithTags(nameof(Product));
group.MapGet("/", async (ProductDbContext db) =>
{
return await db.Products.FindAsync(_ => true).Result.ToListAsync();
})
.WithName("GetAllProducts")
.WithOpenApi();
group.MapGet("/{id}", async Task<Results<Ok<Product>, NotFound>> (string id, ProductDbContext db) =>
{
var filter = Builders<Product>.Filter.Eq(p => p.Id, id);
var data = await db.Products.Find(filter).FirstOrDefaultAsync();
return TypedResults.Ok(data);
})
.WithName("GetProductById")
.WithOpenApi();
group.MapPut("/{id}", async Task<Results<Ok, NotFound>> (string id, Product product, ProductDbContext db) =>
{
var affected = await db.Products.ReplaceOneAsync(m => m.Id == id, product);
if (affected.MatchedCount > 0)
return TypedResults.Ok();
else return TypedResults.NotFound();
})
.WithName("UpdateProduct")
.WithOpenApi();
group.MapPost("/", async (Product product, ProductDbContext db) =>
{
await db.Products.InsertOneAsync(product);
return TypedResults.Created($"/api/Product/{product.Id}", product);
})
.WithName("CreateProduct")
.WithOpenApi();
group.MapDelete("/{id}", async Task<Results<Ok, NotFound>> (string id, ProductDbContext db) =>
{
var result = await db.Products.DeleteOneAsync(model => model.Id == id);
if (result.DeletedCount > 0)
return TypedResults.Ok();
else return TypedResults.NotFound();
})
.WithName("DeleteProduct")
.WithOpenApi();
}
}
# See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
# This stage is used when running from VS in fast mode (Default for Debug configuration)
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 80
# This stage is used to build the service project
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["DemoWebAPIWithMongoDbInDocker/DemoWebAPIWithMongoDbInDocker.csproj", "DemoWebAPIWithMongoDbInDocker/"]
RUN dotnet restore "./DemoWebAPIWithMongoDbInDocker/DemoWebAPIWithMongoDbInDocker.csproj"
COPY . .
WORKDIR "/src/DemoWebAPIWithMongoDbInDocker"
RUN dotnet build "./DemoWebAPIWithMongoDbInDocker.csproj" -c $BUILD_CONFIGURATION -o /app/build
# This stage is used to publish the service project to be copied to the final stage
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./DemoWebAPIWithMongoDbInDocker.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "DemoWebAPIWithMongoDbInDocker.dll"]
services:
webapi:
build:
context: .
dockerfile: Dockerfile
image: "myapi_mongo:latest"
ports:
- "5003:80"
environment:
- ASPNETCORE_URLS=http://+:80;
- ASPNETCORE_ENVIRONMENT=Development
- ConnectionStrings__DefaultConnection=mongodb://mongo:27017
- MongoDB__DatabaseName=MyMongoDatabase
- MongoDB__CollectionName=MyMongoCollection
depends_on:
- mongo
networks:
- my_custom_network
mongo:
image: mongo:latest
ports:
- "27017:27017"
volumes:
- mongo-data:/data/db
networks:
- my_custom_network
networks:
my_custom_network:
external: false
volumes:
mongo-data:
builder.Services.AddSingleton<ProductDbContext>();
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowAllOrigins",
builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseSwagger();
app.UseSwaggerUI();
app.UseCors("AllowAllOrigins");
//app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.MapProductEndpoints();
app.Run();
Comments
Post a Comment