0

Take the standard registration process:

  1. user signs up

  2. user is sent email with link activate account

  3. user activates account

the issue i'm talking about is:

  • when we create the initial account we store the username, password, email, activation key

  • when the user clicks the activation key link we validate the key using the readmodel

  • we then fire the ActivateAccountCommand passing in the username

how do i load the users account to activate it in the domain?


initially I wanted to pass the new users Acount.Id to the readmodel but there is no access (that i'm aware of) from within the CommandExecutorBase - we don't save this:

protected override void ExecuteInContext(IUnitOfWorkContext context,
       CreateAccountViaFormRegistrationCommand command)
{
    var newKey = Guid.NewGuid().ToString();
    var newAccount = new Account(
            command.UserName, command.Email, command.Password, newKey);
    SendWelcomeEmail(command.Email, command.UserName, newKey);
    context.Accept();
}  
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
  • 1
    I've got a bad feeling the UI is meant to set the Id before firing the command. that can't be right surely? –  Nov 16 '11 at 09:53

1 Answers1

2

You can publish an AccountActivationKeySent event, which in turn can be handled to populate whatever projection you need on the read side. Something along the lines of:

// 1. Create and send the command from your client:

var command = new CreateAccountViaFormRegistrationCommand {
    AccountId = Guid.NewGuid(),
    ...
}

// 2. Create a new account in your command handler

var newAccount = new Account(command.AccountId, ...);
context.Accept();

// 3. And your account constructor (assuming it's inheriting from one
//    of EventSource's subclasses, e.g. AggregateRootMappedByConvention) 
//    might look like this:

public Account(Guid accountId, string name, ...) {
  EventSourceId = accountId;
  ApplyEvent(new AccountCreated { AccountId = Id, ... } );
  ApplyEvent(new AccountActivationSent { AccountId = Id, ... })
}
Dennis Traub
  • 50,557
  • 7
  • 93
  • 108
  • How do I publish that? at what point to i hook into NCQRS to get that done? –  Nov 16 '11 at 14:24
  • You can publish it from within your Account-constructor, right after a (presumed) `AccountCreated` event. As far as I know there is no rule that prevents you from publishing multiple events as a result of one command. – Dennis Traub Nov 16 '11 at 14:28
  • so the ID is alloted in the ctor? –  Nov 16 '11 at 14:31
  • Isn't that one of the arguments (`newKey`) in your code example above? `var newAccount = new Account(command.UserName, command.Email, command.Password, newKey);` – Dennis Traub Nov 16 '11 at 14:33
  • newKey is the activation key - not id for the account. am i supposed to allot the ID in the UI? –  Nov 16 '11 at 14:37
  • Oh, then I slightly misunderstood your question. Yes, you would want to create the ID in the UI and pass it to the domain via the command. I'll update my code example above. – Dennis Traub Nov 16 '11 at 14:39
  • but that would mean overriding ravendbs ids. not really into that :s –  Nov 16 '11 at 14:41
  • also - when i go to load the ar from the domain - how does NCQRS know which property is the ID? –  Nov 16 '11 at 14:45
  • or is it that i need them all to be named Id? which i would prefer :) –  Nov 16 '11 at 14:46
  • You didn't mention you were using RavenDb. But anyway, you don't need to tweak RavenDb if you just use Ncqrs's `EventSourceId` with your Accounts, no matter what primary id the storage engine employs. Especially RavenDb can be queried by any field without the need to know the actual id, pretty much like a relational db. – Dennis Traub Nov 16 '11 at 14:49
  • so i need to add EventSourceId to my readmodel and then pass that in instead of id? i don't mind doing that, but raven is optimised to load from Id. –  Nov 16 '11 at 14:52
  • Luckily RavenDb optimizes itself by creating an index if you load by fields other than Id. – Dennis Traub Nov 16 '11 at 14:56
  • gotta love ravendb :) so... I set the eventsourceid and use that as the ID? –  Nov 16 '11 at 14:57
  • Yes. In Ncqrs the EventSourceId is supposed to be the primary Id of the AR in your domain. If the underlying storage mechanism employs something different you can either tweak the storage engine or store both. – Dennis Traub Nov 16 '11 at 15:00
  • when is eventsourceid alloted? will i have that when I call var newAccount = new Account( command.UserName, command.Email, command.Password, newKey); –  Nov 16 '11 at 15:18
  • If your Account class inherits from a subclass of `EventSource` (e.g. `AggregateRootMappedByConvention`,) it has an `EventSourceId` property. You set an `AccountId` in the client, then transmit it via the command, for instance as `command.AccountId`, and then, in your Account constructor set `EventSourceId = accountId`. I'll update my code example above to reflect this. – Dennis Traub Nov 16 '11 at 15:27
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/5150/discussion-between-iwayneo-and-dennis) –  Nov 19 '11 at 11:41