Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -360,4 +360,5 @@ MigrationBackup/
.ionide/

# Fody - auto-generated XML schema
FodyWeavers.xsd
FodyWeavers.xsd
/.vscode
7 changes: 2 additions & 5 deletions BlazorServerWebUI/Program.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
using BlazorServerWebUI.Data;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri("http://apigateway") });
// builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri("http://apigateway") });
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri("http://simpleapigateway") });

var app = builder.Build();

Expand Down
7 changes: 7 additions & 0 deletions DemoMicroserviceSolution.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UI", "UI", "{BF2E0098-3F2F-
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorServerWebUI", "BlazorServerWebUI\BlazorServerWebUI.csproj", "{BDDC7CB5-D948-42D3-92AD-CDC8B4DD65BB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleApiGateway", "Simple\SimpleApiGateway.csproj", "{122CC5B6-09E4-4F0C-8A32-2157142D3C45}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -51,6 +53,10 @@ Global
{BDDC7CB5-D948-42D3-92AD-CDC8B4DD65BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BDDC7CB5-D948-42D3-92AD-CDC8B4DD65BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BDDC7CB5-D948-42D3-92AD-CDC8B4DD65BB}.Release|Any CPU.Build.0 = Release|Any CPU
{122CC5B6-09E4-4F0C-8A32-2157142D3C45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{122CC5B6-09E4-4F0C-8A32-2157142D3C45}.Debug|Any CPU.Build.0 = Debug|Any CPU
{122CC5B6-09E4-4F0C-8A32-2157142D3C45}.Release|Any CPU.ActiveCfg = Release|Any CPU
{122CC5B6-09E4-4F0C-8A32-2157142D3C45}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -61,6 +67,7 @@ Global
{C73F9EA0-BD0D-4B4D-9F34-5BA91F055F75} = {2B947001-C3C6-47D2-BFC9-D68A7D72AAAC}
{3BD63280-F9EB-4978-AE5A-3324BFD7C143} = {EE2C0224-8662-49A2-9F66-ED47B9BFBB2D}
{BDDC7CB5-D948-42D3-92AD-CDC8B4DD65BB} = {BF2E0098-3F2F-43FD-80D4-108EE255EC68}
{122CC5B6-09E4-4F0C-8A32-2157142D3C45} = {EE2C0224-8662-49A2-9F66-ED47B9BFBB2D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5DE9B6CB-0BEA-4BFB-8CD6-9928D54BB4DA}
Expand Down
18 changes: 18 additions & 0 deletions Simple/ApiGateway/Extension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Simple.ApiGateway;

public static class Extension
{
public static void AddApiGateway(this WebApplicationBuilder builder)
{
var result = builder.Services.FirstOrDefault(a => a.ServiceType == typeof(IHttpClientFactory));
if (result is null) builder.Services.AddHttpClient();

builder.Services.Configure<List<Route>>(builder.Configuration.GetSection("SimpleApiGatewayRoute"));
builder.Services.AddSingleton<Middleware>();
}

public static void UseApiGateway(this WebApplication app)
{
app.UseMiddleware<Middleware>();
}
}
77 changes: 77 additions & 0 deletions Simple/ApiGateway/Middleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System.Text;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.Options;

namespace Simple.ApiGateway;

public class Middleware : IMiddleware
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly List<Route> _apiRoutes;

public Middleware(IHttpClientFactory httpClientFactory, IOptionsMonitor<List<Route>> options)
{
_httpClientFactory = httpClientFactory;
_apiRoutes = options.CurrentValue;
}

public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var urlSegments = context.Request.Path.ToString().Split('/');
var urlPath = string.Join('/', urlSegments[1..]);
if (urlPath == "/") urlPath = string.Empty;
var routeFound = _apiRoutes.FirstOrDefault(a => urlPath.ToLower().StartsWith(a.RouteName.ToLower()));
if (routeFound is not null)
{
context.Request.Scheme = routeFound.Scheme;
if (routeFound.Port == 80 || routeFound.Port == 143)
context.Request.Host = new HostString(routeFound.Host);
else
context.Request.Host = new HostString(routeFound.Host, routeFound.Port);
context.Request.Path = $"/{urlPath}";
await ExecuteAsync(context);
}
else
{
await context.Response.WriteAsync("Welcome to API Gateway!");
}
}

private async Task ExecuteAsync(HttpContext context)
{
try
{
var response = await SendRequest(context.Request);
if (response is not null)
{
context.Response.StatusCode = (int)response.StatusCode;
if (response.IsSuccessStatusCode)
await context.Response.WriteAsync(await response.Content.ReadAsStringAsync());
}
}
catch (Exception ex)
{
context.Response.StatusCode = 500;
Console.WriteLine(ex.Message);
}
}

private async Task<HttpResponseMessage> SendRequest(HttpRequest request)
{
using var client = _httpClientFactory.CreateClient();
string requestContent;
using (Stream receiveStream = request.Body)
using (StreamReader readStream = new(receiveStream, Encoding.UTF8))
requestContent = await readStream.ReadToEndAsync();

using var newRequest = new HttpRequestMessage(new HttpMethod(request.Method), request.GetDisplayUrl());

string mediaType = null!;

if (!string.IsNullOrEmpty(request.ContentType))
mediaType = request.ContentType.Replace("; charset=utf-8", "");

newRequest.Content = new StringContent(requestContent, Encoding.UTF8, mediaType);
return await client.SendAsync(newRequest);
}
}
9 changes: 9 additions & 0 deletions Simple/ApiGateway/Route.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Simple.ApiGateway;

public class Route
{
public string RouteName { get; set; } = null!;
public string Scheme { get; set; } = "https";
public string Host { get; set; } = "localhost";
public int Port { get; set; } = 5000;
}
21 changes: 21 additions & 0 deletions Simple/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["Simple/SimpleApiGateway.csproj", "Simple/"]
RUN dotnet restore "Simple/SimpleApiGateway.csproj"
COPY . .
WORKDIR "/src/Simple"
RUN dotnet build "SimpleApiGateway.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "SimpleApiGateway.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "SimpleApiGateway.dll"]
6 changes: 6 additions & 0 deletions Simple/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using Simple.ApiGateway;
var builder = WebApplication.CreateBuilder(args);
builder.AddApiGateway();
var app = builder.Build();
app.UseApiGateway();
app.Run();
31 changes: 31 additions & 0 deletions Simple/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:45044",
"sslPort": 44390
}
},
"profiles": {
"SimpleApiGateway": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7084;http://localhost:5219",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
9 changes: 9 additions & 0 deletions Simple/SimpleApiGateway.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

</Project>
8 changes: 8 additions & 0 deletions Simple/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
30 changes: 30 additions & 0 deletions Simple/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"SimpleApiGatewayRoute": [
{
"routeName": "api/Customer",
"scheme": "http",
"host": "customerwebapi",
"port": 80
},
{
"routeName": "api/Product",
"scheme": "http",
"host": "productwebapi",
"port": 80
}
,
{
"routeName": "api/Order",
"scheme": "http",
"host": "orderwebapi",
"port": 80
}
]
}
9 changes: 7 additions & 2 deletions docker-compose.override.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,18 @@ services:
- "80"


apigateway:
# apigateway:
# environment:
# - ASPNETCORE_ENVIRONMENT=Development
# ports:
# - "80"

simpleapigateway:
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- "80"


blazorserverwebui:
environment:
- ASPNETCORE_ENVIRONMENT=Development
Expand Down
28 changes: 20 additions & 8 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ services:

customerwebapi:
container_name: customer-api
image: ${DOCKER_REGISTRY-}customerwebapi
image: customerwebapi
build:
context: .
dockerfile: CustomerWebApi/Dockerfile
Expand All @@ -41,7 +41,7 @@ services:

productwebapi:
container_name: product-api
image: ${DOCKER_REGISTRY-}productwebapi
image: productwebapi
build:
context: .
dockerfile: ProductWebApi/Dockerfile
Expand All @@ -62,7 +62,7 @@ services:

orderwebapi:
container_name: order-api
image: ${DOCKER_REGISTRY-}orderwebapi
image: orderwebapi
build:
context: .
dockerfile: OrderWebApi/Dockerfile
Expand All @@ -72,12 +72,24 @@ services:
- DB_HOST=orderdb
- DB_NAME=dms_order

apigateway:
container_name: api-gateway
image: ${DOCKER_REGISTRY-}apigateway
# apigateway:
# container_name: api-gateway
# image: apigateway
# build:
# context: .
# dockerfile: ApiGateway/Dockerfile
# ports:
# - 8001:80
# networks:
# - backend
# - frontend

simpleapigateway:
container_name: simple-api-gateway
image: simpleapigateway
build:
context: .
dockerfile: ApiGateway/Dockerfile
dockerfile: Simple/Dockerfile
ports:
- 8001:80
networks:
Expand All @@ -86,7 +98,7 @@ services:

blazorserverwebui:
container_name: blazor-web-ui
image: ${DOCKER_REGISTRY-}blazorserverwebui
image: blazorserverwebui
build:
context: .
dockerfile: BlazorServerWebUI/Dockerfile
Expand Down