Skip to content

Commit

Permalink
feat(templates): improve project templates request pipeline + other s…
Browse files Browse the repository at this point in the history
…tuff #5994 (#5998)
  • Loading branch information
ysmoradi authored Nov 12, 2023
1 parent e945b0c commit fa8c229
Show file tree
Hide file tree
Showing 62 changed files with 947 additions and 242 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//-:cnd:noEmit

using System.Reflection;
using AdminPanel.Client.Core.Services.HttpMessageHandlers;
using Microsoft.Extensions.FileProviders;

namespace AdminPanel.Client.App;
Expand All @@ -27,13 +28,15 @@ public static MauiApp CreateMauiApp()
services.AddBlazorWebViewDeveloperTools();
#endif

Uri.TryCreate(builder.Configuration.GetApiServerAddress(), UriKind.Absolute, out var apiServerAddress);

services.AddScoped(sp =>
{
HttpClient httpClient = new(sp.GetRequiredService<AppHttpClientHandler>())
var handler = sp.GetRequiredService<LocalizationDelegatingHandler>();
HttpClient httpClient = new(handler)
{
BaseAddress = new Uri(sp.GetRequiredService<IConfiguration>().GetApiServerAddress())
BaseAddress = apiServerAddress
};

return httpClient;
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.0-rc.2.23480.2" />
<PackageReference Condition=" '$(BlazorMode)' == 'BlazorWebAssembly' " Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.0-rc.2.23480.2" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.0-rc.2.23480.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0-rc.2.23479.6" />

<Using Include="System.Net.Http.Json" />
<Using Include="System.Collections.Concurrent" />
Expand Down
46 changes: 24 additions & 22 deletions src/Templates/AdminPanel/Bit.AdminPanel/src/Client/Core/App.razor
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
<LayoutView Layout="@typeof(MainLayout)">
<Router AppAssembly="@GetType().Assembly"
AdditionalAssemblies="@([Assembly.Load(BlazorModeDetector.Current.IsBlazorHybrid() ? "AdminPanel.Client.App" : "AdminPanel.Client.Web")])"
OnNavigateAsync="@OnNavigateAsync">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData">
<NotAuthorized>
<NotAuthorizedComponent />
</NotAuthorized>
<Authorizing>
<LoadingComponent Color="#002A66" />
</Authorizing>
</AuthorizeRouteView>
</Found>
<NotFound>
<PageNotFound />
</NotFound>
<Navigating>
<LoadingComponent Color="#002A66" />
</Navigating>
</Router>
</LayoutView>
<CascadingAuthenticationState>
<LayoutView Layout="@typeof(MainLayout)">
<Router AppAssembly="@GetType().Assembly"
AdditionalAssemblies="@([Assembly.Load(BlazorModeDetector.Current.IsBlazorHybrid() ? "AdminPanel.Client.App" : "AdminPanel.Client.Web")])"
OnNavigateAsync="@OnNavigateAsync">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData">
<NotAuthorized>
<NotAuthorizedComponent />
</NotAuthorized>
<Authorizing>
<LoadingComponent Color="#002A66" />
</Authorizing>
</AuthorizeRouteView>
</Found>
<NotFound>
<PageNotFound />
</NotFound>
<Navigating>
<LoadingComponent Color="#002A66" />
</Navigating>
</Router>
</LayoutView>
</CascadingAuthenticationState>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Reflection;

namespace Microsoft.Extensions.Configuration;

public static class IConfigurationBuilderExtensions
{
public static void AddClientConfigurations(this IConfigurationBuilder builder)
{
var assembly = Assembly.Load("AdminPanel.Client.Core");
builder.AddJsonStream(assembly.GetManifestResourceStream("AdminPanel.Client.Core.appsettings.json")!);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ public static class IConfigurationExtensions
{
public static string GetApiServerAddress(this IConfiguration configuration)
{
#if BlazorWebAssembly
return "api/";
#else
return configuration.GetValue<string?>("ApiServerAddress") ?? throw new InvalidOperationException("Could not find ApiServerAddress config");
#endif
var apiServerAddress = configuration.GetValue("ApiServerAddress", defaultValue: "api/")!;

return Uri.TryCreate(apiServerAddress, UriKind.RelativeOrAbsolute, out _) ? apiServerAddress : throw new InvalidOperationException($"Api server address {apiServerAddress} is invalid");
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//-:cnd:noEmit

using AdminPanel.Client.Core.Services.HttpMessageHandlers;

namespace Microsoft.Extensions.DependencyInjection;

public static class IServiceCollectionExtensions
Expand All @@ -13,7 +15,11 @@ public static IServiceCollection AddClientSharedServices(this IServiceCollection
services.AddScoped<IPubSubService, PubSubService>();
services.AddBitBlazorUIServices();

services.AddTransient<AppHttpClientHandler>();
services.AddTransient<LocalizationDelegatingHandler>();
services.AddTransient<AuthDelegatingHandler>();
services.AddTransient<RetryDelegatingHandler>();
services.AddTransient<ExceptionDelegatingHandler>();
services.AddTransient<HttpClientHandler>();

services.AddScoped<AuthenticationStateProvider, AppAuthenticationStateProvider>();
services.AddScoped<IAuthenticationService, AuthenticationService>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System.Net.Http.Headers;

namespace AdminPanel.Client.Core.Services.HttpMessageHandlers;

public class AuthDelegatingHandler
: DelegatingHandler
{
private IAuthTokenProvider _tokenProvider = default!;
private IJSRuntime _jsRuntime = default!;

public AuthDelegatingHandler(IAuthTokenProvider tokenProvider, IJSRuntime jsRuntime, RetryDelegatingHandler handler)
: base(handler)
{
_tokenProvider = tokenProvider;
_jsRuntime = jsRuntime;
}

public AuthDelegatingHandler(IAuthTokenProvider tokenProvider, IJSRuntime jsRuntime)
: base()
{
_tokenProvider = tokenProvider;
_jsRuntime = jsRuntime;
}

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Headers.Authorization is null)
{
var access_token = await _tokenProvider.GetAccessTokenAsync();
if (access_token is not null)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", access_token);
}
}

try
{
return await base.SendAsync(request, cancellationToken);
}
catch (UnauthorizedException)
{
// try to get refresh token, store access token and refresh token,
// then use the new access token to request's authorization header and call base.SendAsync again.
throw;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
//-:cnd:noEmit
using System.Net;
using System.Net.Http.Headers;
using System.Net;

namespace BlazorWeb.Client.Services;
namespace AdminPanel.Client.Core.Services.HttpMessageHandlers;

public partial class AppHttpClientHandler : HttpClientHandler
public class ExceptionDelegatingHandler
: DelegatingHandler
{
[AutoInject] private IAuthTokenProvider _tokenProvider = default!;
public ExceptionDelegatingHandler(HttpClientHandler httpClientHandler)
: base(httpClientHandler)
{

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
}

public ExceptionDelegatingHandler()
{
if (request.Headers.Authorization is null)
{
var access_token = await _tokenProvider.GetAccessTokenAsync();
if (access_token is not null)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", access_token);
}
}

#if MultilingualEnabled
request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(CultureInfo.CurrentCulture.Name));
#endif
}

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
bool serverCommunicationSuccess = false;

try
Expand Down Expand Up @@ -51,7 +46,7 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
args.Add(restError.Payload);
}

Exception exp = (Exception)Activator.CreateInstance(exceptionType, [.. args])!;
Exception exp = (Exception)Activator.CreateInstance(exceptionType, args.ToArray())!;

throw exp;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Net.Http.Headers;

namespace AdminPanel.Client.Core.Services.HttpMessageHandlers;

public class LocalizationDelegatingHandler
: DelegatingHandler
{
public LocalizationDelegatingHandler(AuthDelegatingHandler handler)
: base(handler)
{

}

public LocalizationDelegatingHandler()
{

}

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
#if MultilingualEnabled
request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(CultureInfo.CurrentCulture.Name));
#endif

return await base.SendAsync(request, cancellationToken);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
namespace AdminPanel.Client.Core.Services.HttpMessageHandlers;

public class RetryDelegatingHandler
: DelegatingHandler
{
public RetryDelegatingHandler(ExceptionDelegatingHandler handler)
: base(handler)
{

}

public RetryDelegatingHandler()
{

}

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var delays = GetDelays(scaleFirstTry: TimeSpan.FromSeconds(3), maxRetries: 3).ToArray();

Exception? lastExp = null;

foreach (var delay in delays)
{
try
{
return await base.SendAsync(request, cancellationToken);
}
catch (Exception exp) when (exp is not KnownException)
{
lastExp = exp;
await Task.Delay(delay, cancellationToken);
}
}

throw lastExp!;
}

private static IEnumerable<TimeSpan> GetDelays(TimeSpan scaleFirstTry, int maxRetries)
{
TimeSpan maxValue = TimeSpan.MaxValue;
var maxTimeSpanDouble = maxValue.Ticks - 1_000.0;
var i = 0;
var targetTicksFirstDelay = scaleFirstTry.Ticks;
var num = 0.0;
for (; i < maxRetries; i++)
{
var num2 = i + Random.Shared.NextDouble();
var next = Math.Pow(2.0, num2) * Math.Tanh(Math.Sqrt(4.0 * num2));
var num3 = next - num;
yield return TimeSpan.FromTicks((long)Math.Min(num3 * 0.7_142_857_142_857_143 * targetTicksFirstDelay, maxTimeSpanDouble));
num = next;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ namespace Microsoft.AspNetCore.Http;

public static class HttpRequestExtensions
{
/// <summary>
/// https://blog.elmah.io/how-to-get-base-url-in-asp-net-core/
/// </summary>
public static string GetBaseUrl(this HttpRequest req)
{
var uriBuilder = new UriBuilder(req.Scheme, req.Host.Host, req.Host.Port ?? -1);
if (uriBuilder.Uri.IsDefaultPort)
{
uriBuilder.Port = -1;
}

return uriBuilder.Uri.AbsoluteUri;
}

public static bool ShouldRenderStaticMode(this HttpRequest request)
{
var agent = GetLoweredUserAgent(request);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public static WebApplication CreateHostBuilder(string[] args)
{
var builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddJsonStream(typeof(MainLayout).Assembly.GetManifestResourceStream("AdminPanel.Client.Core.appsettings.json")!);
builder.Configuration.AddClientConfigurations();

builder.WebHost.UseElectron(args);
builder.Services.AddElectron();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public static WebApplication CreateHostBuilder(string[] args)
{
var builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddJsonStream(typeof(MainLayout).Assembly.GetManifestResourceStream("AdminPanel.Client.Core.appsettings.json")!);
builder.Configuration.AddClientConfigurations();

#if DEBUG
if (OperatingSystem.IsWindows())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//-:cnd:noEmit
#if BlazorWebAssembly
using AdminPanel.Client.Core.Services.HttpMessageHandlers;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.AspNetCore.Components.WebAssembly.Services;
#endif
Expand All @@ -13,13 +14,24 @@ public static WebAssemblyHost CreateHostBuilder(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault();

builder.Configuration.AddJsonStream(typeof(MainLayout).Assembly.GetManifestResourceStream("AdminPanel.Client.Core.appsettings.json")!);
builder.Configuration.AddClientConfigurations();

var apiServerAddressConfig = builder.Configuration.GetApiServerAddress();
Uri.TryCreate(builder.Configuration.GetApiServerAddress(), UriKind.RelativeOrAbsolute, out var apiServerAddress);

var apiServerAddress = new Uri($"{builder.HostEnvironment.BaseAddress}{apiServerAddressConfig}");
if (apiServerAddress!.IsAbsoluteUri is false)
{
apiServerAddress = new Uri($"{builder.HostEnvironment.BaseAddress}{apiServerAddress}");
}

builder.Services.AddSingleton(sp => new HttpClient(sp.GetRequiredService<AppHttpClientHandler>()) { BaseAddress = apiServerAddress });
builder.Services.AddSingleton(sp =>
{
var handler = sp.GetRequiredService<LocalizationDelegatingHandler>();
HttpClient httpClient = new(handler)
{
BaseAddress = apiServerAddress
};
return httpClient;
});
builder.Services.AddScoped<LazyAssemblyLoader>();
builder.Services.AddTransient<IAuthTokenProvider, ClientSideAuthTokenProvider>();

Expand Down
Loading

0 comments on commit fa8c229

Please sign in to comment.