Compare commits

..

3 Commits

7 changed files with 146 additions and 16 deletions

View File

@@ -0,0 +1,40 @@
using Microsoft.AspNetCore.Components.Authorization;
using Sandbox.Models.ViewModels;
namespace Sandbox.App.Services.AuthService;
public class AuthService : IAuthService
{
private readonly HttpClient _http;
//private readonly AuthenticationStateProvider _authenticationStateProvider;
// public AuthService(HttpClient httpClient, AuthenticationStateProvider authenticationStateProvider)
public AuthService(HttpClient httpClient)
{
_http = httpClient;
//_authenticationStateProvider = authenticationStateProvider;
}
public async Task<ServiceResponse<int>> Register(UserRegister request)
{
var result = await _http.PostAsJsonAsync("api/auth/register", request);
return await result.Content.ReadFromJsonAsync<ServiceResponse<int>>();
}
// public async Task<ServiceResponse<string>> Login(UserLogin request)
// {
// var result = await _http.PostAsJsonAsync("api/auth/login", request);
// return await result.Content.ReadFromJsonAsync<ServiceResponse<string>>();
// }
//
// public async Task<ServiceResponse<bool>> ChangePassword(UserChangePassword request)
// {
// var result = await _http.PostAsJsonAsync("api/auth/change-password", request.Password);
// return await result.Content.ReadFromJsonAsync<ServiceResponse<bool>>();
// }
// public async Task<bool> IsUserAuthenticated()
// {
// return (await _authenticationStateProvider.GetAuthenticationStateAsync()).User.Identity.IsAuthenticated;
// }
}

View File

@@ -0,0 +1,11 @@
using Sandbox.Models.ViewModels;
namespace Sandbox.App.Services.AuthService;
public interface IAuthService
{
Task<ServiceResponse<int>> Register(UserRegister request);
// Task<ServiceResponse<string>> Login(UserLogin request);
// Task<ServiceResponse<bool>> ChangePassword(UserChangePassword request);
// Task<bool> IsUserAuthenticated();
}

View File

@@ -1,36 +1,41 @@
@page "/register"
@using Sandbox.Models.ViewModels
@inject Sandbox.App.Services.AuthService.IAuthService AuthService
@* @inject AuthenticationStateProvider AuthenticationStateProvider *@
@* @inject NavigationManager NavigationManager *@
<title>Register</title>
<EditForm Model="user" OnValidSubmit="HandleRegistration" FormName="registerForm">
<EditForm Model="user" OnValidSubmit="HandleRegistration" OnInvalidSubmit="HandleInvalidSubmit" FormName="registerForm">
<DataAnnotationsValidator/>
<div class="d-flex justify-content-center align-items-center">
<div class="col-md-4 p-5 shadow-sm border rounded-3">
<h2 class="text-center mb-4 text-primary">Register Form</h2>
<div class="mb-3">
<label for="email" class="form-label">Email address</label>
<InputText type="email" @bind-Value="user.Email" class="form-control border border-primary" id="email" aria-describedby="email"/>
<InputText type="email" @bind-Value="user.Email" class="form-control border border-primary" id="email"
aria-describedby="email"/>
<ValidationMessage For="@(() => user.Email)"/>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<InputText type="password" @bind-Value="user.Password" class="form-control border border-primary" id="password" aria-describedby="password"/>
<InputText type="password" @bind-Value="user.Password" class="form-control border border-primary"
id="password" aria-describedby="password"/>
<ValidationMessage For="@(() => user.Password)"/>
</div>
<div class="mb-3">
<label for="confirmPassword" class="form-label">Confirm password</label>
<InputText type="password" @bind-Value="user.ConfirmPassword" class="form-control border border-primary" id="confirmPassword" aria-describedby="confirmPassword"/>
<InputText type="password" @bind-Value="user.ConfirmPassword" class="form-control border border-primary"
id="confirmPassword" aria-describedby="confirmPassword"/>
<ValidationMessage For="@(() => user.ConfirmPassword)"/>
</div>
<div class="d-grid">
<button class="btn btn-primary" type="submit">Register</button>
</div>
<div class="mt-3">
<p class="mb-0 text-center">You have an account? <a href="login" class="text-primary fw-bold">Sign In</a></p>
<p class="mb-0 text-center">You have an account? <a href="login" class="text-primary fw-bold">Sign
In</a></p>
</div>
</div>
</div>
@@ -45,18 +50,29 @@
</div>
@code {
UserRegister user = new();
HttpClient _http = new();
[SupplyParameterFromForm] private UserRegister user { get; set; }
//HttpClient _http = new() { BaseAddress = new("https://localhost:7122") };
private string message = string.Empty;
private string messageCssClass = string.Empty;
private string errorMessage = string.Empty;
async void HandleRegistration()
protected override void OnInitialized() => user ??= new();
async Task HandleRegistration()
{
var response = await _http.PostAsJsonAsync("api/auth/register", user);
var result = await response.Content.ReadFromJsonAsync<ServiceResponse<int>>();
// var response = await _http.PostAsJsonAsync("/api/register", user);
// var result = await response.Content.ReadFromJsonAsync<ServiceResponse<int>>();
var result = await AuthService.Register(user);
message = result.Message;
messageCssClass = result.Success ? "text-success" : "text-danger";
}
async Task HandleInvalidSubmit()
{
message = "Data annotations validation failed.";
messageCssClass = "text-danger";
}
}

50
HttpClientSetupService.cs Normal file
View File

@@ -0,0 +1,50 @@
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
namespace Sandbox;
public class HttpClientSetupService(
HttpClient httpClient,
IServer server,
IHostApplicationLifetime applicationLifetime)
: BackgroundService
{
private readonly HttpClient _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
private readonly IServer _server = server ?? throw new ArgumentNullException(nameof(server));
private readonly IHostApplicationLifetime _applicationLifetime = applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime));
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
var applicationStartedToken = _applicationLifetime.ApplicationStarted;
if (applicationStartedToken.IsCancellationRequested)
{
ConfigureHttpClient();
}
else
{
applicationStartedToken.Register(ConfigureHttpClient);
}
return Task.CompletedTask;
}
private void ConfigureHttpClient()
{
var serverAddresses = _server.Features.Get<IServerAddressesFeature>();
var address = serverAddresses.Addresses.FirstOrDefault();
if (address == null)
{
// Default ASP.NET Core Kestrel endpoint
address = "http://localhost:5000";
}
else
{
address = address.Replace("*", "localhost", StringComparison.Ordinal);
address = address.Replace("+", "localhost", StringComparison.Ordinal);
address = address.Replace("[::]", "localhost", StringComparison.Ordinal);
}
var baseUri = new Uri(address);
_httpClient.BaseAddress = baseUri;
}
}

View File

@@ -1,6 +1,9 @@
using Sandbox;
using Sandbox.Components;
using Sandbox.Models.ViewModels;
using Sandbox.Services.AuthService;
using ClientServices = Sandbox.App.Services;
using ServerServices = Sandbox.Services;
var builder = WebApplication.CreateBuilder(args);
@@ -8,8 +11,16 @@ var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
// Blazor client services
builder.Services.AddScoped<ClientServices.AuthService.IAuthService, ClientServices.AuthService.AuthService>();
// Blazor server services
builder.Services.AddScoped<IAuthService, AuthService>();
// Get server base address when application starts to properly configure HttpClient for client service to call server service
builder.Services.AddSingleton<HttpClient>();
builder.Services.AddSingleton<IHostedService, HttpClientSetupService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
@@ -19,16 +30,18 @@ if (!app.Environment.IsDevelopment())
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true);
app.UseHttpsRedirection();
app.UseAntiforgery();
app.MapPost("/register", async (UserRegister request, IAuthService authService) =>
await authService.Register(request.Email, request.Password));
// Blazor server routing
app.MapPost("/api/auth/register", async (UserRegister request, IAuthService authService) =>
await authService.Register(request));
app.MapStaticAssets();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.Run();
app.Run();

View File

@@ -4,12 +4,12 @@ namespace Sandbox.Services.AuthService;
public class AuthService : IAuthService
{
public async Task<ServiceResponse<int>> Register(string userName, string password)
public async Task<ServiceResponse<int>> Register(UserRegister userRegister)
{
return new ServiceResponse<int>
{
Data = 1,
Message = $"Got register request with user name {userName}",
Message = $"Got register request with e-mail {userRegister.Email}",
Success = true
};
}

View File

@@ -4,5 +4,5 @@ namespace Sandbox.Services.AuthService;
public interface IAuthService
{
Task<ServiceResponse<int>> Register(string userName, string password);
Task<ServiceResponse<int>> Register(UserRegister userRegister);
}