Giter Site home page Giter Site logo

shortbus's Introduction

ShortBus

ShortBus is an in-process mediator with low-friction API

Command

public class DoSomething : ICommand { }

public class DoesSomething : ICommandHandler<DoSomething> {
	public void Handle(DoSomething command) {
	   // does something
	}
}

_mediator.Send(new DoSomething());

Query

public class AskAQuestion : IQuery<Answer> { }

public class Answerer : IQueryHandler<AskAQuestion, Answer> {
    public Answer Handle(AskAQuestion query) {			
		return answer;
	}
}

var answer = _mediator.Request(new AskAQuestion());

IOC Containers

ShortBus currently supports 6 IOC containers

  • AutoFac
  • Ninject
  • Simple Injector
  • Structure Map
  • Unity
  • Windsor

Example configuration of registering handlers using StructureMap:

ObjectFactory.Initialize(i => i.Scan(s =>
{
    s.AssemblyContainingType<IMediator>();
    s.TheCallingAssembly();
    s.WithDefaultConventions();
    s.AddAllTypesOf(typeof (IQueryHandler<,>));
    s.AddAllTypesOf(typeof (ICommandHandler<>));
}));	

Low-friction API

No type parameter noise.

What for?

  • Query objects
  • Enables subcutaneous testing
  • Business concepts as first class citizens

In Production

ShortBus is in production powering the server APIs for major ecommerce applications.

shortbus's People

Contributors

dvins avatar e-larrambebere avatar guyharwood avatar jbogard avatar jrnail23 avatar kmc059000 avatar mhinze avatar mxmissile avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

shortbus's Issues

Following instructions in readme is a compilation error

I tried to create a simple command handler as in the example on the README but this is giving me a compilation error due to Handle not returning anything.

    public class UserRegistered : ICommandHandler<RegisterUser>
    {
        public void Handle(RegisterUser user) {
        }
    }

Versioning:

Id                             Version              Description/Release Notes
--                             -------              -------------------------
ShortBus                       3.0.46-beta          ShortBus is an in-process mediator with low-friction API
ShortBus.Markers               3.0.43-beta          ShortBus is an in-process mediator with low-friction API
ShortBus.StructureMap          3.0.48-beta          ShortBus is an in-process mediator with low-friction API
structuremap                   3.0.5.130            StructureMap is a Dependency Injection / Inversion of Control tool for .Net that can be used to improve the architectural qualities of an object oriented syst...
xunit                          1.9.2                xUnit.net is a developer testing framework, built to support Test Driven Development, with a design goal of extreme simplicity and alignment with framework fe...

Why support multiple handlers for the same command?

All I read about CQRS says that it's bad practice to have multiple handlers for the same command, it should be 1:1 relationship.

As Mediator.Send supports multiple handlers, how can I interpret the above statement?

  1. it's really bad practice, so Mediator.Send should be updated to call only one handler; or
  2. it's ok to have multiple handlers, it's just not so common (ShortBus is covering most specifics use cases)

BTW thank you for ShortBus, it's simple and brilliant! :)

UnityDependencyResolver.GetInstances<T>() GetInstances does not return all registered instances

Because the UnityDependencyResolver.GetInstances() method is using the ResolveAll() method of Unity it will not return any unnamed instances that were registered in the Unity container. I'm not sure if this is intentional since this is the default behavior for Unity, however it did cause me some confusion when I ran into it.

If this is not intentional I have a fix I implemented and can do a pull request to resolve it.

Thanks,
Kent

AutoFac support

Does it work with Autofac (or any other DI container)? Can it be plugged in?

Make ShortBus compatible with existing usages of other IoC containers

I'm kicking myself for not finding ShortBus sooner -- I went and wrote mostly the same thing for my current project, although I use Autofac.

In my implementation, I abstracted away from Autofac by encapsulating the handler lookup into an IMessageHandlerResolver (catchy name, right?).

It looks like it would be relatively trivial to do something similar here.

I'd be happy to take that on, if you think it would improve the project.

Why do Commands return a result instead of Send() being void?

I had always thought the "right way" to do commands was to following CQS and therefore any command should be void (and be assumed to successful or it throws an exception)., but ShortBus doesn't do it that way.

I'd be interested to hear the reasoning for having Commands return results.

Removing non-async methods?

public interface IMediator
{
  Task<Response<TResult>> RequestAsync<TResult>(IAsyncQuery<TResult> query);
  Task<Response<TResult>> SendAsync<TResult>(IAsyncCommand<TResult> command);
}

If this is acceptable, what about this?

public interface IMediator
{
  Task<Response<TResult>> HandleAsync<TResult>(IOperation<TResult> op);
}

Notify fails when event is cast into an interface

e.g:

var n = new Notification();
_mediator.Notify(n); // succeeds
_mediator.Notify((ISomeInterface) n); // fails

as it resolves to Notify<ISomeInterface>, which uses DependencyResolver.GetInstances<INotificationHandler<ISomeInterface>>()
which won't find the appropriate handlers.

I propose a similar usage through MediatorPlan instead, if I find time I will propose a pull request.

My problem is that I aggregate my IDomainEvents into an array, and then dispatch them, loosing the type info.

For now the workaround I use is_mediator.Notify((dynamic) n);

Updates for Nuget

What should the release cycle be for getting the change published to nuget.

Do we need to automate this process with the build.

What's your feeling about how message validation should be treated when using ShortBus

@mhinze, in the context of using ShortBus to mediate between MVC/WebApi controllers and the application layer, what's your take on how validation should be done?

As we know, some kinds of validation need to be performed on the other side of the Mediator, at or below the application layer (i.e., enforcing a unique name for an entity, enforcing domain invariants, etc.).

How would you recommend handling these kinds of things?

Would you use a composite exception to roll up multiple validation failures into one exception?

Example Autofac usage in ASP.NET MVC5 application

I've had some troubles with StructureMap, so I decided to try Autofac instead:

Global.ascx.cs

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        IoCConfig.RegisterDependencies();
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

IoCConfig.cs

public class IoCConfig
{
    public static void RegisterDependencies()
    {
        var builder = new ContainerBuilder();

        builder.RegisterSource(new ContravariantRegistrationSource());
        builder.RegisterAssemblyTypes(typeof(IMediator).Assembly)
            .AsClosedTypesOf(typeof(IQueryHandler<,>))
            .AsImplementedInterfaces();

        //builder.RegisterType<Mediator>().As<IMediator>().InstancePerRequest();

        builder.RegisterType<Mediator>().AsImplementedInterfaces().InstancePerLifetimeScope();

        builder.RegisterType<AutofacDependencyResolver>()
            .AsImplementedInterfaces()
            .InstancePerLifetimeScope();

        builder.RegisterControllers(typeof(MvcApplication).Assembly)
                .InstancePerHttpRequest();
        builder.RegisterAssemblyModules(typeof(MvcApplication).Assembly);
        builder.RegisterModule<AutofacWebTypesModule>();

        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    }
}

In my controller I then have:

public class HomeController : Controller
{
    private readonly IMediator Mediator;

    public HomeController(IMediator mediator)
    {
        Mediator = mediator;
    }

    public ActionResult Index()
    {
        var result = Mediator.Request(new Framework.Queries.ListCustomers { Name = "test", Skip = 0, Take = 10 });
        return View(result);
    }
}

And the error returned by index is:

None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'ShortBus.Mediator' can be invoked with the available services and parameters:
Cannot resolve parameter 'StructureMap.IContainer container' of constructor 'Void .ctor(StructureMap.IContainer)'.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: Autofac.Core.DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'ShortBus.Mediator' can be invoked with the available services and parameters:
Cannot resolve parameter 'StructureMap.IContainer container' of constructor 'Void .ctor(StructureMap.IContainer)'.

[DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'ShortBus.Mediator' can be invoked with the available services and parameters:
Cannot resolve parameter 'StructureMap.IContainer container' of constructor 'Void .ctor(StructureMap.IContainer)'.]
   Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) +528
   Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters) +109
   Autofac.Core.Resolving.InstanceLookup.<Execute>b__0() +61
   Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator) +201
   Autofac.Core.Resolving.InstanceLookup.Execute() +262
   Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters) +282
   Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) +72
   Autofac.Core.Activators.Reflection.<>c__DisplayClass2.<CanSupplyValue>b__0() +82
   Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate() +233
   Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) +563
   Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters) +109
   Autofac.Core.Resolving.InstanceLookup.<Execute>b__0() +61
   Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator) +201
   Autofac.Core.Resolving.InstanceLookup.Execute() +262
   Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters) +282
   Autofac.Core.Resolving.ResolveOperation.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) +60
   Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters) +111
   Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) +279
   Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance) +175
   Autofac.ResolutionExtensions.ResolveOptionalService(IComponentContext context, Service service, IEnumerable`1 parameters) +242
   Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType, IEnumerable`1 parameters) +72
   Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType) +48
   Autofac.Integration.Mvc.AutofacDependencyResolver.GetService(Type serviceType) +57
   System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +87

[InvalidOperationException: An error occurred when trying to create a controller of type 'Website.Controllers.HomeController'. Make sure that the controller has a parameterless public constructor.]
   System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +247
   System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +437
   System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +257
   System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +326
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +157
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +88
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +50
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +103
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

It appears to be trying to resolve StructureMap.IContainer, but I have set the DependencyResolver to use Autofac.

Does anyone have any ideas on how to solve this? I love the idea of Shortbus, but I'm having a lot of problems getting up and running. Does anyone have an example Github ASP.NET MVC project they can direct me to?

Query re-use best practice?

Is it good practice, or frowned upon for queries or commands to call other queries or commands?

Say I want a command that adds all Foo items with a category property set to Bar to a database table. Should my command have a category property and the command handler use a GetFoosByCategory query to get the desired items? Or should the command have an IEnumerable property and leave it up to the calling code to get the list by calling the GetFoosByCategory query? Or indeed refactor the code from GetFoosByCategory into a FooRepository.FindByCategory and call this from both query and command?

Mocking Mediators and Handlers

I am looking for a best practice on mocking a handler that returns a result.

For instance I have a service that I would like to get under test. This service has an IMediator injected via constructor injection. Throughout the service I make use of Mediator.Request(SomeDataQuery).Data to get data for processing. I have multiple Mediator requests using different requests.

I am looking for a recommended way to mock the mediator and then setup the results from the various Handle methods.

If it helps I am using Ninject as my IoC container in my main application.

Thanks.

Reason for IAsyncRequest<TResponseData>

Hi,

Is there a reason for having a separate interface for async requests? Isn't a request a request and it can be handled in either a synchronous or asynchronous fashion? I've only recently started using this pattern and was looking to replace my personal implementation with ShortBus and so far I haven't had a need for a separate interface in my own code.

Also, do you have any idea when version 3 will move towards being stable?

Thanks for your work!

Is an upgrade of StructureMap to v3 on the roadmap?

Are there any plans to upgrade Shortbus to StructureMap v3. I'm having a few dependency versioning issues because Shortbus is still on 2.6.3. Assembly redirects are failing due to the Major Version change. (I'm using StructureMap.MVC5).

ShortBus 3.0 simple excample and basecontroller

Hi,

is ShortBus 3.0 already usable and do you have a little example of how to use it in combination with your basecontroller.

That would be really appreciated. Thanks in advance.

Nice project!

CommandHandler as abstract class

When we have the CommandHandler as a abstract class we can't have a single class with multiple handlers. I was hoping to have one handler class per entity .

Something like this.

CommentHandler : CommandHandler, CommandHandler

Does creating class like this make sense or should I bee create a single handler class for each command?

If not should we thinking the abstract class

Shortbus distributed as a code file a la PetaPoco

I think it may be best to distribute ShortBus as a single code file like PetaPoco and others.

Reasons:

  1. While implementing mediator is a common task in many projects, it's also common to need slightly different changes to the implementation. For example, in my current project we do not need the non-async methods. Some folks may want to do something fancier like log all requests. I can see a lot of cross cutting concerns that, if implemented in ShortBus proper, would cause bloat.
  2. ShortBus is a very simple thing, it is not really doing that much on its own. It started as a gist, actually, and doesn't really have the hallmark of a useful library - it's just a simple, single implementation of a design pattern.

Counter-arguments:

ShortBus is pretty easy to get up and running as is. We could bake in support for cross cutting concerns that could be nice, and we have managed to make something pretty cool in spite of all this.

I'm really on the fence. Thoughts?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.