[Axon 3.2] Metadata value injection into the Event Handler

1,669 views
Skip to first unread message

Jérôme M.

unread,
May 2, 2018, 4:28:59 AM5/2/18
to Axon Framework Users
Hi,

I'm currently using Axon 3.2 and I'm facing an issue with the injection of the Metadata value in my subscribing event handlers.

I've implemented a message dispatch interceptor as following and added it to the Command Bus.


public class AuthenticationInterceptor implements MessageDispatchInterceptor<Message<?>> {

 
@Override
  public BiFunction<Integer, Message<?>, Message<?>> handle(
     
List<Message<?>> messages) {

   
return (index, message) -> SecurityContextHolder.getContext().getAuthentication() == null
        ? message : message
       
.andMetaData(Collections.singletonMap("username",
           
SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString()));
 
}
}

I tried to debug and I get the metadata value correctly injected in the Command Handler but it's always null in the Event Handler method with the following signature :


@EventHandler
public void on(ProjectImportedEvent event, @MetaDataValue("username") String username,
   
@Timestamp Instant timestamp)

Am I missing something ?

Thank you for your help,
B.R
Jerome

Jérôme M.

unread,
May 2, 2018, 7:23:16 AM5/2/18
to Axon Framework Users
Quick update :

I checked the domain_event_entry table and it seems that the metadata attached in the Command Dispatch interceptor aren't persisted and therefore not forwarded to the event handlers.

Investigating further.

Best Regards,
Jerome

Jérôme M.

unread,
May 2, 2018, 8:32:25 AM5/2/18
to Axon Framework Users
Ok it seems I found the (obvious) missing part. As a command message and an event message are two separated messages, you have to explicitely tell Axon that you would like to copy the metadata attached to the former to the latter.

The right component for that seems to be the CorrelationDataProvider, and in my case the SimpleCorrelationDataProvider with the header "username".

If you are using Spring Boot, the easiest way to configure is as following :
@Configuration
public class AxonConfig {

 
@Bean()
 
CorrelationDataProvider correlationDataProviders() {
   
return new SimpleCorrelationDataProvider("username");
 
}

}

The bean will be picked and registered by the Axon auto configuration.
This topic is not really addressed in the official documentation ( correct me if I'm wrong), it might be worth adding a chapter about it.

Best Regards,
Jerome


milan...@axoniq.io

unread,
May 7, 2018, 9:21:32 AM5/7/18
to Axon Framework Users
Hi Jérôme,

I'm glad that you managed to resolve the issue. Sorry for the late response, but let me give an explanation regarding message interceptors in AxonFramework. When you registered the MessageInterceptor on command bus, it is applied only to the command messages. During command processing you're (probably) applying events which are completely different type of messages. If you want to attach a metadata to them, you'd have to register a MessageInterceptor on the event bus. Spring boot autoconfiguration will do that automatically for you.

Cheers,
Milan.

Steven van Beelen

unread,
May 11, 2018, 6:02:38 AM5/11/18
to axonfr...@googlegroups.com
Hi Jerome,

Fair point of you that it's a missing topic on the reference guide.
I'll make the necessary steps to add it to the reference guide somewhere in the future.

Cheers,
Steven

--
You received this message because you are subscribed to the Google Groups "Axon Framework Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to axonframewor...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jérôme M.

unread,
May 14, 2018, 4:55:46 AM5/14/18
to Axon Framework Users
Dear Milan and Steven,

Thank you for your feedback, it's really appreciated.

@Milan : That makes sense, but I guess that when it comes to authentication and authorization, it's better to use the correlation data provider to convey this information from the command side to the read side, instead of assuming that the SecurityContext will be available from an interceptor attached to the Event Bus.

Cheers,
Jerome

milan...@axoniq.io

unread,
May 14, 2018, 8:34:36 AM5/14/18
to Axon Framework Users
Hi Jérôme,

Regarding authorization and authentication, I completely agree with you!

Cheers,
Milan.

Danny Kruitbosch

unread,
Jun 4, 2018, 7:12:50 AM6/4/18
to Axon Framework Users
Hi Jérôme,

I'm trying to accomplish the same, but cannot get it to work.
I've created a MessageDispatchInterceptor that gets some Authentication info from the spring security context and adds it to the metadata. I see this data on the command message. So that part is working.
I've also added a CorrelationDataProvider bean to my config, and it's being invoked (when I debug and set a breakpoint in the CorrelationDataProvider, the code stops there. But in my CorrelationDataProvider, the metaData of the message is always empty.

Do I need to specify all the metadata fields on my @EventHandler annoted methods? Like you I'd like to "transparently" copy over the metadata of the command message to the events being triggered from it.

Thanks,

Danny

Op woensdag 2 mei 2018 14:32:25 UTC+2 schreef Jérôme M.:

Jérôme M.

unread,
Jun 5, 2018, 2:59:36 AM6/5/18
to Axon Framework Users
Hi Danny,

In my case, I'm using a SimpleCorrelationDataProvider, whose behavior is to copy the metadata from the CommandMessage to the EventMessage for a preconfigured set of metadata keys.
Therefore, when you declare your CorrelationDataProvider bean, you have to configure it by explicitly specifying all the metadata keys you would like to access from the events messages.
In your case, you are attaching some metadata in a MessageDispatchInterceptor, let's say credentials for example :

To make it work, you have to :
- Declare a SimpleCorrelationDataProvider in your Spring configuration and pass "credentials" as a parameter as you would like to copy this metadata from the CommandMessage to the EventMessage.
- Add the @MetadataValue("credentials") String credentials as a parameter in your @EventHandler annotated methods, this value will be automatically injected by Axon.

Did you already follow all these steps ?

Hope it helps,
Best Regards,

Brighto Paul

unread,
Jun 24, 2019, 3:54:09 PM6/24/19
to Axon Framework Users
Hi, I had a similar issue where I need to inject user information for auditing purpose. This worked for me.

@Configuration
public class AxonAuditConfiguration {

@Autowired
public void registerInterceptors(CommandBus commandBus) {
if (commandBus instanceof SimpleCommandBus) {
commandBus.registerHandlerInterceptor(new AuthenticationInterceptor());
}
}
}

@NoArgsConstructor
public class AuthenticationInterceptor implements MessageHandlerInterceptor<Message<?>> {

@Override
public Object handle(UnitOfWork<? extends Message<?>> unitOfWork, InterceptorChain interceptorChain) throws Exception {

if (
SecurityContextHolder.getContext().getAuthentication() != null) {
unitOfWork.
transformMessage(message ->
message.
andMetaData(Collections.singletonMap("username",
SecurityContextHolder.getContext().getAuthentication().getPrincipal()().get().toString()))
)
;
unitOfWork.registerCorrelationDataProvider(new SimpleCorrelationDataProvider("username"));
}
return interceptorChain.proceed();
}
}
Reply all
Reply to author
Forward
0 new messages