Skip to content
This repository was archived by the owner on Nov 17, 2023. It is now read-only.

Commit 72c8167

Browse files
committed
Attempt to migrate Mobile BFF to common services pattern
1 parent 8c9524c commit 72c8167

File tree

7 files changed

+212
-173
lines changed

7 files changed

+212
-173
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
internal static class Extensions
2+
{
3+
public static IServiceCollection AddReverseProxy(this IServiceCollection services, IConfiguration configuration)
4+
{
5+
services.AddReverseProxy().LoadFromConfig(configuration.GetRequiredSection("ReverseProxy"));
6+
return services;
7+
}
8+
9+
public static IServiceCollection AddHealthChecks(this IServiceCollection services, IConfiguration configuration)
10+
{
11+
services.AddHealthChecks()
12+
.AddUrlGroup(_ => new Uri(configuration.GetRequiredValue("CatalogUrlHC")), name: "catalogapi-check", tags: new string[] { "catalogapi" })
13+
.AddUrlGroup(_ => new Uri(configuration.GetRequiredValue("OrderingUrlHC")), name: "orderingapi-check", tags: new string[] { "orderingapi" })
14+
.AddUrlGroup(_ => new Uri(configuration.GetRequiredValue("BasketUrlHC")), name: "basketapi-check", tags: new string[] { "basketapi" })
15+
.AddUrlGroup(_ => new Uri(configuration.GetRequiredValue("IdentityUrlHC")), name: "identityapi-check", tags: new string[] { "identityapi" });
16+
17+
return services;
18+
}
19+
20+
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
21+
{
22+
// Register delegating handlers
23+
services.AddTransient<HttpClientAuthorizationDelegatingHandler>();
24+
25+
// Register http services
26+
services.AddHttpClient<IOrderApiClient, OrderApiClient>()
27+
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>();
28+
29+
return services;
30+
}
31+
32+
public static IServiceCollection AddGrpcServices(this IServiceCollection services)
33+
{
34+
services.AddTransient<GrpcExceptionInterceptor>();
35+
36+
services.AddScoped<IBasketService, BasketService>();
37+
38+
services.AddGrpcClient<Basket.BasketClient>((services, options) =>
39+
{
40+
var basketApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcBasket;
41+
options.Address = new Uri(basketApi);
42+
}).AddInterceptor<GrpcExceptionInterceptor>();
43+
44+
services.AddScoped<ICatalogService, CatalogService>();
45+
46+
services.AddGrpcClient<Catalog.CatalogClient>((services, options) =>
47+
{
48+
var catalogApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcCatalog;
49+
options.Address = new Uri(catalogApi);
50+
}).AddInterceptor<GrpcExceptionInterceptor>();
51+
52+
services.AddScoped<IOrderingService, OrderingService>();
53+
54+
services.AddGrpcClient<GrpcOrdering.OrderingGrpc.OrderingGrpcClient>((services, options) =>
55+
{
56+
var orderingApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcOrdering;
57+
options.Address = new Uri(orderingApi);
58+
}).AddInterceptor<GrpcExceptionInterceptor>();
59+
60+
return services;
61+
}
62+
}

src/ApiGateways/Mobile.Bff.Shopping/aggregator/Filters/AuthorizeCheckOperationFilter.cs

Lines changed: 0 additions & 33 deletions
This file was deleted.

src/ApiGateways/Mobile.Bff.Shopping/aggregator/GlobalUsings.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,18 @@
88
global using Microsoft.AspNetCore.Authorization;
99
global using Microsoft.AspNetCore.Builder;
1010
global using Microsoft.AspNetCore.Diagnostics.HealthChecks;
11-
global using Microsoft.AspNetCore.Hosting;
1211
global using Microsoft.AspNetCore.Http;
1312
global using Microsoft.AspNetCore.Mvc;
14-
global using Microsoft.AspNetCore;
1513
global using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
16-
global using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters;
1714
global using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure;
1815
global using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
1916
global using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services;
20-
global using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator;
2117
global using Microsoft.Extensions.Configuration;
2218
global using Microsoft.Extensions.DependencyInjection;
2319
global using Microsoft.Extensions.Diagnostics.HealthChecks;
24-
global using Microsoft.Extensions.Hosting;
2520
global using Microsoft.Extensions.Logging;
2621
global using Microsoft.Extensions.Options;
2722
global using Microsoft.OpenApi.Models;
28-
global using Swashbuckle.AspNetCore.SwaggerGen;
2923
global using System.Collections.Generic;
3024
global using System.IdentityModel.Tokens.Jwt;
3125
global using System.Linq;
@@ -37,3 +31,4 @@
3731
global using System.Threading;
3832
global using System;
3933
global using Microsoft.IdentityModel.Tokens;
34+
global using Services.Common;

src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
</ItemGroup>
1818

1919
<ItemGroup>
20+
<PackageReference Include="Yarp.ReverseProxy" />
2021
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" />
2122
<PackageReference Include="AspNetCore.HealthChecks.Uris" />
2223
<PackageReference Include="Google.Protobuf" />
@@ -31,6 +32,10 @@
3132
<PackageReference Include="Swashbuckle.AspNetCore" />
3233
</ItemGroup>
3334

35+
<ItemGroup>
36+
<ProjectReference Include="..\..\..\Services\Services.Common\Services.Common.csproj" />
37+
</ItemGroup>
38+
3439
<ItemGroup>
3540
<Protobuf Include="..\..\..\Services\Basket\Basket.API\Proto\basket.proto" GrpcServices="Client" />
3641
<Protobuf Include="..\..\..\Services\Catalog\Catalog.API\Proto\catalog.proto" GrpcServices="Client" />
Lines changed: 13 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,145 +1,38 @@
11
var builder = WebApplication.CreateBuilder(args);
22

3-
builder.Services.AddHealthChecks()
4-
.AddCheck("self", () => HealthCheckResult.Healthy())
5-
.AddUrlGroup(new Uri(builder.Configuration["CatalogUrlHC"]), name: "catalogapi-check", tags: new string[] { "catalogapi" })
6-
.AddUrlGroup(new Uri(builder.Configuration["OrderingUrlHC"]), name: "orderingapi-check", tags: new string[] { "orderingapi" })
7-
.AddUrlGroup(new Uri(builder.Configuration["BasketUrlHC"]), name: "basketapi-check", tags: new string[] { "basketapi" })
8-
.AddUrlGroup(new Uri(builder.Configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" })
9-
.AddUrlGroup(new Uri(builder.Configuration["PaymentUrlHC"]), name: "paymentapi-check", tags: new string[] { "paymentapi" });
3+
builder.AddServiceDefaults();
104

11-
builder.Services.Configure<UrlsConfig>(builder.Configuration.GetSection("urls"));
12-
13-
builder.Services.AddControllers()
14-
.AddJsonOptions(options => options.JsonSerializerOptions.WriteIndented = true);
15-
16-
builder.Services.AddSwaggerGen(options =>
17-
{
18-
options.SwaggerDoc("v1", new OpenApiInfo
19-
{
20-
Title = "Shopping Aggregator for Mobile Clients",
21-
Version = "v1",
22-
Description = "Shopping Aggregator for Mobile Clients"
23-
});
24-
var identityUrl = builder.Configuration.GetSection("Identity").GetValue<string>("ExternalUrl");
25-
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
26-
{
27-
Type = SecuritySchemeType.OAuth2,
28-
Flows = new OpenApiOAuthFlows()
29-
{
30-
Implicit = new OpenApiOAuthFlow()
31-
{
32-
AuthorizationUrl = new Uri($"{identityUrl}/connect/authorize"),
33-
TokenUrl = new Uri($"{identityUrl}/connect/token"),
34-
35-
Scopes = new Dictionary<string, string>()
36-
{
37-
{ "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" }
38-
}
39-
}
40-
}
41-
});
42-
43-
options.OperationFilter<AuthorizeCheckOperationFilter>();
44-
});
5+
builder.Services.AddReverseProxy(builder.Configuration);
6+
builder.Services.AddControllers();
457

8+
builder.Services.AddHealthChecks(builder.Configuration);
469
builder.Services.AddCors(options =>
4710
{
11+
// TODO: Read allowed origins from configuration
4812
options.AddPolicy("CorsPolicy",
4913
builder => builder
14+
.SetIsOriginAllowed((host) => true)
5015
.AllowAnyMethod()
5116
.AllowAnyHeader()
52-
.SetIsOriginAllowed((host) => true)
5317
.AllowCredentials());
5418
});
5519

56-
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
20+
builder.Services.AddApplicationServices();
21+
builder.Services.AddGrpcServices();
5722

58-
var identityUrl = builder.Configuration.GetValue<string>("urls:identity");
59-
60-
builder.Services.AddAuthentication(options =>
61-
{
62-
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
63-
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
64-
65-
})
66-
.AddJwtBearer(options =>
67-
{
68-
options.Authority = identityUrl;
69-
options.RequireHttpsMetadata = false;
70-
options.Audience = "mobileshoppingagg";
71-
options.TokenValidationParameters = new TokenValidationParameters
72-
{
73-
ValidateAudience = false
74-
};
75-
});
76-
77-
builder.Services.AddAuthorization(options =>
78-
{
79-
options.AddPolicy("ApiScope", policy =>
80-
{
81-
policy.RequireAuthenticatedUser();
82-
policy.RequireClaim("scope", "mobileshoppingagg");
83-
});
84-
});
85-
86-
builder.Services.AddTransient<HttpClientAuthorizationDelegatingHandler>();
87-
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
88-
builder.Services.AddHttpClient<IOrderApiClient, OrderApiClient>();
89-
90-
builder.Services.AddTransient<GrpcExceptionInterceptor>();
91-
builder.Services.AddScoped<IBasketService, BasketService>();
92-
builder.Services.AddGrpcClient<Basket.BasketClient>((services, options) =>
93-
{
94-
var basketApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcBasket;
95-
options.Address = new Uri(basketApi);
96-
}).AddInterceptor<GrpcExceptionInterceptor>();
97-
builder.Services.AddScoped<ICatalogService, CatalogService>();
98-
builder.Services.AddGrpcClient<Catalog.CatalogClient>((services, options) =>
99-
{
100-
var catalogApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcCatalog;
101-
options.Address = new Uri(catalogApi);
102-
}).AddInterceptor<GrpcExceptionInterceptor>();
103-
builder.Services.AddScoped<IOrderingService, OrderingService>();
104-
builder.Services.AddGrpcClient<GrpcOrdering.OrderingGrpc.OrderingGrpcClient>((services, options) =>
105-
{
106-
var orderingApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcOrdering;
107-
options.Address = new Uri(orderingApi);
108-
}).AddInterceptor<GrpcExceptionInterceptor>();
23+
builder.Services.Configure<UrlsConfig>(builder.Configuration.GetSection("urls"));
10924

11025
var app = builder.Build();
11126

112-
var pathBase = app.Configuration["PATH_BASE"];
113-
114-
if (!string.IsNullOrEmpty(pathBase))
115-
{
116-
app.UsePathBase(pathBase);
117-
}
118-
119-
app.UseSwagger().UseSwaggerUI(c =>
120-
{
121-
c.SwaggerEndpoint($"{(!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty)}/swagger/v1/swagger.json", "Purchase BFF V1");
27+
app.UseServiceDefaults();
12228

123-
c.OAuthClientId("mobileshoppingaggswaggerui");
124-
c.OAuthClientSecret(string.Empty);
125-
c.OAuthRealm(string.Empty);
126-
c.OAuthAppName("Purchase BFF Swagger UI");
127-
});
29+
app.UseHttpsRedirection();
12830

129-
app.UseRouting();
13031
app.UseCors("CorsPolicy");
13132
app.UseAuthentication();
13233
app.UseAuthorization();
133-
app.MapDefaultControllerRoute();
34+
13435
app.MapControllers();
135-
app.MapHealthChecks("/hc", new HealthCheckOptions()
136-
{
137-
Predicate = _ => true,
138-
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
139-
});
140-
app.MapHealthChecks("/liveness", new HealthCheckOptions
141-
{
142-
Predicate = r => r.Name.Contains("self")
143-
});
36+
app.MapReverseProxy();
14437

14538
await app.RunAsync();

0 commit comments

Comments
 (0)