Open generics and partial generics

28 views
Skip to first unread message

David Keaveny

unread,
Mar 25, 2018, 7:02:42 PM3/25/18
to structuremap-users
Hi there,

I am working on a project which uses CQRS as its main architectural pattern. I've created a POC, but briefly the problem I am having is this:

I define a query and a query handler as:

public interface IQuery<out TResult>
{
}

public interface IQueryHandler<TQuery, TResult> where TQuery : IQuery<TResult>
{
   
TResult Handle(TQuery query);
}


and a mediator class that leans on the IoC container to do the heavy lifting:

public class CqrsDispatcher : ICqrsDispatcher()
{
   
TResult QueryThatResolves<TQuery, TResult>(TQuery query) where TQuery : IQuery<TResult>
   
{
       
var handler = _container.Resolve<IQueryHandler<TQuery, TResult>>();
       
return handler.Handle(query);
   
}

   
TResult QueryThatDoesntResolve<TResult>(IQuery<TResult> query)
   
{
       
var handler = _container.Resolve<IQueryHandler<IQuery<TResult>, TResult>>();
       
return handler.Handle(query);
   
}
}

and finally invoke it thusly:

var query = new SomeQuery();
var thisWorks = _dispatcher.QueryThatResolves<SomeQuery, SomeResult>(query);
var thisDoesnt = _dispatcher.QueryThatDoesntResolve(query);

So how should I configure StructureMap so that the second call, which is much more friendly for the end user to use, correctly resolves the call? I've tried both

config.Scan(scanner =>
{
    scanner
.AssemblyContainingType<StructureMapContainer>();
    scanner
.WithDefaultConventions();
    scanner
.AddAllTypesOf(typeof(IQueryHandler<,>));
    scanner
.AddAllTypesOf(typeof(ICommandHandler<>));
});

and

config.Scan(scanner =>
{
    scanner
.AssemblyContainingType<StructureMapContainer>();
    scanner
.WithDefaultConventions();
    scanner
.ConnectImplementationsToTypesClosing(typeof(IQueryHandler<,>));

    scanner
.ConnectImplementationsToTypesClosing(typeof(ICommandHandler<>));
});

but both give the same error: No default Instance is registered and cannot be automatically determined for type 'IQueryHandler<IQuery<SomeModel>, SomeModel>, and I get a compile time error if I explicitly try to register the handler.



Jeremy Miller

unread,
Mar 25, 2018, 8:58:32 PM3/25/18
to structure...@googlegroups.com
Probably should start by asking what version of StructureMap you’re using, because there was a big years ago similar to what you’re talking about. My second thought though is that if you’re getting a compile time error from trying to register the service against
the interface, you probably don’t have the generic constraints quite right because the type system can’t cast the concrete type to the interface type. You might be missing some co/contra-variance declarations.

Any reason why you aren’t using something off the shelf like MediatR for this?

- Jeremy



--
You received this message because you are subscribed to the Google Groups "structuremap-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to structuremap-us...@googlegroups.com.
To post to this group, send email to structure...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/structuremap-users/6262aa15-2ce4-40bc-b607-e5f112c9af2f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Message has been deleted

David Keaveny

unread,
Mar 25, 2018, 9:09:48 PM3/25/18
to structuremap-users

Sorry, I should have said - we are using v4.6.1 with .NET Framework 4.6.2.

As for not using MediatR, it was a combination of just not wanting to take the dependency on MediatR, and also having explicit separation of IQueryHandler<,> and ICommandHandler<>, whereas MediatR just has the IRequest<,> and command handlers return a fake void type called Unit (although there's a base class which hides some of that); finally, we found our developers were getting confused as to when to use decorator classes and when to use pipeline behaviours to enrich the query/command handlers; so having our own simpler implementation which leaned more heavily on the container made sense.

Of course, it was the original blog series on refactoring a web application using MediatR which inspired us to go down the CQRS route in the first place...

- David
Reply all
Reply to author
Forward
0 new messages