Skip to content

Commit

Permalink
#218 - Using event and exception to handle success and failure.
Browse files Browse the repository at this point in the history
  • Loading branch information
maraf committed Feb 21, 2019
1 parent 99767f6 commit 226bf19
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/Money.UI.Backend/Bootstrap/BootstrapTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ private void Domain()

bootstrapTask.Initialize();

commandDispatcher.Handlers.AddAll(new UserHandler(services.BuildServiceProvider().GetRequiredService<UserManager<ApplicationUser>>()));
commandDispatcher.Handlers.AddAll(new UserHandler(services.BuildServiceProvider().GetRequiredService<UserManager<ApplicationUser>>(), eventDispatcher));
}

private void ReadModels()
Expand Down
19 changes: 17 additions & 2 deletions src/Money.UI.Backend/Commands/Handlers/UserHandler.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using Microsoft.AspNetCore.Identity;
using Money.Events;
using Money.Models;
using Neptuo;
using Neptuo.Collections.Specialized;
using Neptuo.Commands.Handlers;
using Neptuo.Events;
using Neptuo.Models;
using Neptuo.Models.Keys;
using System;
using System.Collections.Generic;
Expand All @@ -15,11 +18,14 @@ namespace Money.Commands.Handlers
public class UserHandler : ICommandHandler<Envelope<ChangePassword>>
{
private readonly UserManager<ApplicationUser> userManager;
private readonly IEventDispatcher eventDispatcher;

public UserHandler(UserManager<ApplicationUser> userManager)
public UserHandler(UserManager<ApplicationUser> userManager, IEventDispatcher eventDispatcher)
{
Ensure.NotNull(userManager, "userManager");
Ensure.NotNull(eventDispatcher, "eventDispatcher");
this.userManager = userManager;
this.eventDispatcher = eventDispatcher;
}

public async Task HandleAsync(Envelope<ChangePassword> command)
Expand All @@ -31,7 +37,16 @@ public async Task HandleAsync(Envelope<ChangePassword> command)

IdentityResult result = await userManager.ChangePasswordAsync(user, command.Body.Current, command.Body.New);
if (!result.Succeeded)
throw new InvalidOperationException($"Password change failed for ID '{userKey.Identifier}'.");
{
var ex = new PasswordChangeFailedException();
AggregateRootExceptionDecorator decorator = new AggregateRootExceptionDecorator(ex);
decorator.SetCommandKey(command.Body.Key);
decorator.SetSourceCommandKey(command.Body.Key);
decorator.SetKey(userKey);
throw ex;
}

await eventDispatcher.PublishAsync(new PasswordChanged(GuidKey.Create(Guid.NewGuid(), "PasswordChanged"), userKey));
}
}
}
5 changes: 4 additions & 1 deletion src/Money.UI.Backend/Hubs/ApiHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ public class ApiHub : Hub,
IEventHandler<CategoryCreated>, IEventHandler<CategoryDeleted>, IEventHandler<CategoryRenamed>, IEventHandler<CategoryDescriptionChanged>, IEventHandler<CategoryIconChanged>, IEventHandler<CategoryColorChanged>,
IEventHandler<CurrencyCreated>, IEventHandler<CurrencyDeleted>, IEventHandler<CurrencyDefaultChanged>, IEventHandler<CurrencySymbolChanged>,
IEventHandler<CurrencyExchangeRateSet>, IEventHandler<CurrencyExchangeRateRemoved>,
IEventHandler<OutcomeCreated>, IEventHandler<OutcomeDeleted>, IEventHandler<OutcomeAmountChanged>, IEventHandler<OutcomeDescriptionChanged>, IEventHandler<OutcomeWhenChanged>
IEventHandler<OutcomeCreated>, IEventHandler<OutcomeDeleted>, IEventHandler<OutcomeAmountChanged>, IEventHandler<OutcomeDescriptionChanged>, IEventHandler<OutcomeWhenChanged>,
IEventHandler<PasswordChanged>
{
private readonly FormatterContainer formatters;

Expand Down Expand Up @@ -126,6 +127,8 @@ private Task RaiseEvent<T>(T payload)
Task IEventHandler<OutcomeDescriptionChanged>.HandleAsync(OutcomeDescriptionChanged payload) => RaiseEvent(payload);
Task IEventHandler<OutcomeWhenChanged>.HandleAsync(OutcomeWhenChanged payload) => RaiseEvent(payload);

Task IEventHandler<PasswordChanged>.HandleAsync(PasswordChanged payload) => RaiseEvent(payload);

public void Handle(AggregateRootException exception)
{
string type = exception.GetType().AssemblyQualifiedName;
Expand Down
15 changes: 15 additions & 0 deletions src/Money.UI.Blazor/Commands/PasswordChangeFailedException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Neptuo.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Money.Commands
{
/// <summary>
/// An exception raised when user password change fails.
/// </summary>
public class PasswordChangeFailedException : AggregateRootException
{ }
}
20 changes: 20 additions & 0 deletions src/Money.UI.Blazor/Events/PasswordChanged.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Neptuo.Events;
using Neptuo.Models.Keys;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Money.Events
{
/// <summary>
/// An event raised when user password has been changed.
/// </summary>
public class PasswordChanged : Event
{
public PasswordChanged(IKey key, IKey aggregateKey)
: base(key, aggregateKey, 0)
{ }
}
}
15 changes: 1 addition & 14 deletions src/Money.UI.Blazor/Pages/User/ChangePassword.cshtml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@page "/user/changepassword"
@inject ICommandDispatcher Commands
@inherits ChangePasswordBase

<UserHead />

Expand All @@ -24,16 +24,3 @@
</div>
</div>
</div>

@functions
{
public string Current { get; set; }
public string New { get; set; }
public string Confirm { get; set; }

private async Task OnFormSubmit()
{
if (!String.IsNullOrEmpty(Current) && !String.IsNullOrEmpty(New) && New == Confirm)
await Commands.HandleAsync(new Commands.ChangePassword(Current, New));
}
}
67 changes: 67 additions & 0 deletions src/Money.UI.Blazor/Pages/User/ChangePassword.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using Microsoft.AspNetCore.Blazor.Components;
using Money.Events;
using Neptuo.Commands;
using Neptuo.Events;
using Neptuo.Events.Handlers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Money.Pages
{
public class ChangePasswordBase : BlazorComponent, IEventHandler<PasswordChanged>, IDisposable
{
[Inject]
public ICommandDispatcher Commands { get; set; }

[Inject]
public IEventHandlerCollection EventHandlers { get; set; }

public string Current { get; set; }
public string New { get; set; }
public string Confirm { get; set; }

protected override Task OnInitAsync()
{
BindEvents();
return base.OnInitAsync();
}

protected async Task OnFormSubmit()
{
if (!String.IsNullOrEmpty(Current) && !String.IsNullOrEmpty(New) && New == Confirm)
await Commands.HandleAsync(new Commands.ChangePassword(Current, New));
}

public void Dispose()
{
UnBindEvents();
}

#region Events

private void BindEvents()
{
EventHandlers
.Add<PasswordChanged>(this);
}

private void UnBindEvents()
{
EventHandlers
.Remove<PasswordChanged>(this);
}

Task IEventHandler<PasswordChanged>.HandleAsync(PasswordChanged payload)
{
Current = null;
New = null;
Confirm = null;
return Task.CompletedTask;
}

#endregion
}
}

0 comments on commit 226bf19

Please sign in to comment.