Base solution for your next web application

Activities of "byteplatz"

Debugging Abp, I can see that this is the flow:

  • Creating a new entity:

  • Breakpoint hit in EntityChangedEventHelper.TriggerEntityChangeEvent

  • Breakpoint hit in HandleEvent(EntityCreatedEventData<MyEntity> eventData)

  • Breakpoint hit in HandleEvent(EntityCreatedEventData<MyEntity> eventData) -- second time

  • Breakpoint hit in EntityChangedEventHelper.TriggerEntityChangeEvent

By looking at the code I found this:

public void Trigger(Type eventType, object eventSource, IEventData eventData)
        {
            //TODO: This method can be optimized by adding all possibilities to a dictionary.

            eventData.EventSource = eventSource;

            foreach (var factoryToTrigger in GetHandlerFactories(eventType))
            {
                var eventHandler = factoryToTrigger.GetHandler();
                if (eventHandler == null)
                {
                    throw new Exception("Registered event handler for event type " + eventType.Name + " does not implement IEventHandler<" + eventType.Name + "> interface!");
                }

                var handlerType = typeof(IEventHandler<>).MakeGenericType(eventType);

                try
                {
                    handlerType
                        .GetMethod("HandleEvent", BindingFlags.Public | BindingFlags.Instance, null, new[] { eventType }, null)
                        .Invoke(eventHandler, new object[] { eventData });
                }
                finally
                {
                    factoryToTrigger.ReleaseHandler(eventHandler);
                }
            }

This code get executed when creating entity (perfectly sense), but the foreach get called twice for my handler (maybe registered twice) :

handlerType
                        .GetMethod("HandleEvent", BindingFlags.Public | BindingFlags.Instance, null, new[] { eventType }, null)
                        .Invoke(eventHandler, new object[] { eventData });

This is my Handler code (Im listening for the Changed eventdata as well and I thinkg this might be the problem with the generic event dispatcher):

class MyEntityEventDataHandler : ITransientDependency,
        IEventHandler<EntityCreatedEventData<MyEntity>>,
        IEventHandler<EntityUpdatedEventData<MyEntity>>,
        IEventHandler<EntityChangedEventData<MyEntity>>,
        IEventHandler<EntityDeletedEventData<MyEntity>>
    {
        public ILogger Logger { get; set; }

        public void HandleEvent(EntityDeletedEventData<MyEntity> eventData)
        {
            Logger.Debug("EntityDeleted");
        }

        public void HandleEvent(EntityChangedEventData<MyEntity> eventData)
        {
            Logger.Debug("EntityChanged");
        }

        public void HandleEvent(EntityUpdatedEventData<MyEntity> eventData)
        {
            Logger.Debug("EntityUpdated");
        }

        public void HandleEvent(EntityCreatedEventData<MyEntity> eventData)
        {
            Logger.Debug("EntityCreated");
        }
    }

I will remove the entityChanged and try again

Bruno

Both triggers are exactly the same...

Cant find why the event is being triggered twice...

The event handler is located in a separated module.

I can see that the event is being triggered one for each dbcontext (MainApp and CustomModule)

Can you help me on that ?

Bruno

Thank you !

I will try to implement a login flow without field for tenancy name (using tenant detection by username on Login action)...

Quick question : Why there are no method to FindAllAsync (Users) and only exists for (External) Logins ?

[UnitOfWork]
        public virtual Task<List<TUser>> FindAllAsync(UserLoginInfo login)
        {
            var query = from userLogin in _userLoginRepository.GetAll()
                        join user in _userRepository.GetAll() on userLogin.UserId equals user.Id
                        where userLogin.LoginProvider == login.LoginProvider && userLogin.ProviderKey == login.ProviderKey
                        select user;

            return Task.FromResult(query.ToList());
        }
public virtual Task<TUser> FindAsync(int? tenantId, UserLoginInfo login)
        {
            var query = from userLogin in _userLoginRepository.GetAll()
                join user in _userRepository.GetAll() on userLogin.UserId equals user.Id
                where user.TenantId == tenantId && userLogin.LoginProvider == login.LoginProvider && userLogin.ProviderKey == login.ProviderKey
                select user;

            return Task.FromResult(query.FirstOrDefault());
        }

They both go only in LoginRepository...Are there any specific reasons/arthicteture? Or it is just a matter of "not implemented" ?

Can I implement those methods for Users in UserManager.cs from my application ? Will that interfere with UoW or AuditLogs ?

Bruno

Do you have any other code besides Startup.cs and AccountController.cs for external authentication ?

Bruno

I will need to investigate why the tenancy name is not being set in the callback url. ..

Maybe the controller action need some adjustment...

It is always null on ExternalLoginCallback even when using url tenant detection

I will let you know

Hello

I'm not triggering the event manually...I'm using EntityCreatedEventData...

Breakpoint at Handle event is called twice...I will entity is the same...I will check every field to see if audit related fields are set in both calls

Bruno

Thanks

I'm now investigating why event bus is triggering the event twice, one for each dB context.

Never mind on this...

I was getting null when I register the handler manually...

Usint ITransiendDependency Works fine...

Should It be null when manual registering (EventBus.Default.Register) ?

Bruno

Thank you ! Another issue solved :) My bad on not paying attention to it...

One more thing: I have injected a ILogger (Castle.Core.Logging) inside AllEventsHandler and Im getting it null all the time. Im using property injection since this class must have a parameterless constructor.

Any suggestions ?

Bruno

Thank you...

Just wondering if there is anything special to register these pre defined events

Should I only create a handler like this :

public class AllEventsHandler : IEventHandler<EntityCreatedEventData<MyEntity>>,
 IEventHandler<EntityUpdatedEventData<MyEntity>>,
IEventHandler<EntityDeletedEventData<MyEntity>>

I did that and the handlers are not being invoked.

Even tried placing this code inside web or application Project (not from my separated custom module)

Regarding transaction I did couple tests but that was not the behavior I found at that time...I was using Bus.Send which was throwing exception but the DB were not rolling back.

I found this code on AbpSource code:

private void TriggerEntityChangeEvent(Type genericEventType, object entity)
        {
            var entityType = entity.GetType();
            var eventType = genericEventType.MakeGenericType(entityType);

            if (_unitOfWorkManager == null || _unitOfWorkManager.Current == null)
            {
                EventBus.Trigger(eventType, (IEventData)Activator.CreateInstance(eventType, new[] { entity }));
                return;
            }

            _unitOfWorkManager.Current.Completed += (sender, args) => EventBus.Trigger(eventType, (IEventData)Activator.CreateInstance(eventType, new[] { entity }));
        }

Doesnt that mean that the trigger occurs after UoW has completed ?

Bruno

Showing 11 to 20 of 40 entries