Problem when performing delegate bind in ninject

Asked

Viewed 291 times

1

I am developing an application with ninject for Ioc and Entity framework, but when I perform the bind with delegate it gives this error:

<Message>An error has occurred.</Message>
<ExceptionMessage>
Error activating IntPtr No matching bindings are available, and the type is not self-bindable. Activation path: 5) Injection of dependency IntPtr into parameter method of constructor of type Func{EventStoreDbContext{Pedido}} 4) Injection of dependency Func{EventStoreDbContext{Pedido}} into parameter contextFactory of constructor of type SqlEventSourcedRepository{Pedido} 3) Injection of dependency IEventSourcedRepository{Pedido} into parameter repository of constructor of type PedidoApplicationService 2) Injection of dependency IPedidoApplicationService into parameter pedidoApplicationService of constructor of type HomeController 1) Request for HomeController Suggestions: 1) Ensure that you have defined a binding for IntPtr. 2) If the binding was defined in a module, ensure that the module has been loaded into the kernel. 3) Ensure you have not accidentally created more than one kernel. 4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name. 5) If you are using automatic module loading, ensure the search path and filters are correct.
</ExceptionMessage>

The implementation of the repository:

public class SqlEventSourcedRepository<T> : IEventSourcedRepository<T> where T : class, IEventSourced
    {
        protected static readonly string sourceType = typeof(T).Name;
        protected readonly Func<EventStoreDbContext<T>> contextFactory;
        protected readonly ITextSerializer serializer;
        //private readonly IEventBus eventBus;
        private readonly Func<Guid, IEnumerable<IVersionedEvent>, T> entityFactory;


        public SqlEventSourcedRepository(ITextSerializer serializer, Func<EventStoreDbContext<T>> contextFactory)
        {
            //this.eventBus = eventBus;
            this.contextFactory = contextFactory;
            this.serializer = serializer;

            // TODO: could be replaced with a compiled lambda
            var constructor = typeof(T).GetConstructor(new[] { typeof(Guid), typeof(IEnumerable<IVersionedEvent>) });
            if (constructor == null)
            {
                throw new InvalidCastException("Type T must have a constructor with the following signature: .ctor(Guid, IEnumerable<IVersionedEvent>)");
            }

            this.entityFactory = (id, events) => (T)constructor.Invoke(new object[] { id, events });
        }

        public T Find(Guid id)
        {
            using (var context = this.contextFactory.Invoke())
            {
                var deserialized = context.Set<Event>()
                    .Where(x => x.AggregateId == id && x.AggregateType == sourceType)
                    .OrderBy(x => x.Version)
                    .AsEnumerable()
                    .Select(this.Deserialize)
                    .AsCachedAnyEnumerable();

                if (deserialized.Any())
                {
                    return entityFactory.Invoke(id, deserialized);
                }

                return null;
            }
        }

        public T Get(Guid id)
        {
            throw new NotImplementedException();
        }

        public void Save(T eventSourced, string correlationId)
        {
            var events = eventSourced.Events.ToArray();
            using (var context = this.contextFactory.Invoke())
            {
                var contextSet = context.Set<Event>();
                foreach (var e in events)
                {
                    contextSet.Add(this.Serialize(e, correlationId));
                }

                context.SaveChanges();
            }

            //this.eventBus.Publish(events.Select(e => new Envelope<IEvent>(e) { CorrelationId = correlationId }));
        }

        private Event Serialize(IVersionedEvent e, string correlationId)
        {
            Event serialized;
            using (var writer = new StringWriter())
            {
                this.serializer.Serialize(writer, e);
                serialized = new Event
                {
                    AggregateId = e.SourceId,
                    AggregateType = sourceType,
                    Version = e.Version,
                    Payload = writer.ToString(),
                    CorrelationId = correlationId
                };

                return serialized;
            }
        }

        private IVersionedEvent Deserialize(Event @event)
        {
            using (var reader = new StringReader(@event.Payload))
            {
                return (IVersionedEvent)this.serializer.Deserialize(reader);
            }
        }
    }

The class I’m using with the ninject module (I can’t bind the "Eventstoredbcontext<>" that in the repository implementation constructor receives it as "Func>", and I can’t pass with the code

Bind(typeof(EventStoreDbContext<>)).ToSelf();

):

public class Module : NinjectModule
    {
        public override void Load()
        {
            Bind<ITextSerializer>().To<JsonTextSerializer>();

            Bind(typeof(EventStoreDbContext<>)).ToSelf().InTransientScope().WithConstructorArgument("EventStore");

            Bind<IMessageSender>().To<MessageSender>()
                .WithConstructorArgument("name", "schema")
                .WithConstructorArgument("tableName", "tabela");

            Bind<IDbConnectionFactory>().ToConstant<IDbConnectionFactory>(Database.DefaultConnectionFactory);

            Bind<IEventBus>().To<EventBus>();
            Bind<ICommandBus>().To<CommandBus>();

            Bind<IPedidoApplicationService>().To<PedidoApplicationService>();

            Bind(typeof(IEventSourcedRepository<>)).To(typeof(SqlEventSourcedRepository<>));
        }
    }
  • The part of the Event sourced repository yes.

  • Well, I don’t know Ninject well, but the error is that this doesn’t work: Bind(typeof(EventStoreDbContext<>)).ToSelf().InTransientScope().WithConstructorArgument("EventStore");. The Bind should be a Func<>, not of a Type.

  • So ninject does not allow me to pass this function Bind(typeof(Func<Eventstoredbcontext<>>)). Toself(). Intransientscope(). Withconstructor Argument("Eventstore"); as Bind(typeof(Func<Eventstoredbcontext<>>)). Toself(). Intransientscope(). Withconstructor Argument("Eventstore"); Giving an error that needs to pass some type in Eventstoredbcontext<>, and I would need a generic bind to work properly(when it’s not a generic class it allows to do this).

  • So, I don’t think I can get past the EventStoreDbContext<> thus. I would pass at least with the interface as generic argument.

  • You say hold the bind like this: Bind(typeof<IEventStoreDbContextM<>>).To(typeof<EventStoreDbContext<>>) ? I tried that way too and it didn’t work. I’m thinking of switching to another injector, maybe it’s easier or perform this bind without more problems.

  • No. So: Bind(typeof<IEventStoreDbContextM<IEntidade>>).To(typeof<EventStoreDbContext<IEntidade>>).

  • 1

    I changed the injector and used Unity and it worked, thanks anyway!

  • Could you please put an answer to the community understand what you have done to solve your problem?

Show 4 more comments

2 answers

0


I solved this problem by changing the injector ninject to the unity and he was able to solve this dependency.

0

The Eventstoredbcontext class has a type parameter? if not try something like this:

Bind<EventStoreDbContext>().ToSelf().InTransientScope().WithConstructorArgument("EventStore");
  • The Eventstoredbcontext class is generic but has no type parameter restrictions, but it is not allowed to implement the code line without the "<>" in Eventstoredbcontext, that is, you have to specify the generic(ex.: IEventStoreDbContext<Pedido>) or go generic(ex.:typeof<IEventStoreDbContext<>>).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.