saritasa-nest / saritasa-dotnet-tools

Development Tools For Company'S .NET Projects.
BSD 2-Clause "Simplified" License
27 stars 13 forks source link

Query pipeline does not resolve query handler correctly when interface is used #38

Closed dermeister0 closed 7 years ago

dermeister0 commented 7 years ago

Query pipeline does not resolve query handler correctly when interface is used

UseInternalObjectResolver is false in all tests.

pipeline.Query<SomeClass> works always.

pipeline.Query<ISomeInterface> works only if 3 conditions are met:

namespace Domain
{
    public interface IStringQueries
    {
        string GetString();
    }
}
using Domain;
using Saritasa.Tools.Messages.Abstractions.Queries;

namespace DataAccess
{
    [QueryHandlers]
    public class StringQueries : IStringQueries
    {
        public string GetString()
        {
            return "test";
        }
    }
}
namespace DataAccess
{
    public class IntegerQueries
    {
        public int GetNumber()
        {
            return 42;
        }
    }
}
using DataAccess;
using Domain;
using Microsoft.Extensions.DependencyInjection;
using Saritasa.Tools.Messages.Abstractions;
using Saritasa.Tools.Messages.Common;
using Saritasa.Tools.Messages.Queries;
using Saritasa.Tools.Messages.Queries.PipelineMiddlewares;
using System;
using System.Reflection;

internal class Program
{
    private static void Main(string[] args)
    {
        var p = new Program();
        p.Test1();
        p.Test2();
        p.Test3();
    }

    private void Test1()
    {
        var sp = Prepare1();
        Run1(sp); // System.InvalidOperationException: 'Query object of type DataAccess.StringQueries cannot be resolved.'
    }

    private void Test2()
    {
        var sp = Prepare2();
        Run1(sp); // Works.
        Run2(sp); // Works.
        Run3(sp); // Works.
    }

    private void Test3()
    {
        var sp = Prepare3();
        Run1(sp); // System.InvalidOperationException: 'Cannot find implementation for query with type Domain.IStringQueries.'
        Run2(sp); // Works.
        Run3(sp); // Works.
    }

    private IServiceProvider Prepare1()
    {
        var services = new ServiceCollection();

        services.AddTransient<IStringQueries, StringQueries>();

        return RegisterPipeline(services, typeof(StringQueries).GetTypeInfo().Assembly);
    }

    private IServiceProvider Prepare2()
    {
        var services = new ServiceCollection();

        services.AddTransient<StringQueries>();
        services.AddTransient<IntegerQueries>();

        return RegisterPipeline(services, typeof(StringQueries).GetTypeInfo().Assembly);
    }

    private IServiceProvider Prepare3()
    {
        var services = new ServiceCollection();

        services.AddTransient<StringQueries>();
        services.AddTransient<IntegerQueries>();

        return RegisterPipeline(services);
    }

    private IServiceProvider RegisterPipeline(IServiceCollection services, params Assembly[] assemblies)
    {
        var pipelineContainer = new DefaultMessagePipelineContainer();
        pipelineContainer.AddQueryPipeline()
            .AddMiddleware(new QueryObjectResolverMiddleware(assemblies) { UseInternalObjectResolver = false })
            .AddMiddleware(new QueryExecutorMiddleware())
            .AddMiddleware(new QueryObjectReleaseMiddleware());

        services.AddSingleton<IMessagePipelineContainer>(pipelineContainer);
        services.AddScoped<IMessagePipelineService, DefaultMessagePipelineService>();

        return services.BuildServiceProvider();
    }

    private void Run1(IServiceProvider serviceProvider)
    {
        var pipeline = serviceProvider.GetRequiredService<IMessagePipelineService>();
        var result = pipeline.Query<IStringQueries>().With(q => q.GetString());
        Console.WriteLine(result);
    }

    private void Run2(IServiceProvider serviceProvider)
    {
        var pipeline = serviceProvider.GetRequiredService<IMessagePipelineService>();
        var result = pipeline.Query<StringQueries>().With(q => q.GetString());
        Console.WriteLine(result);
    }

    private void Run3(IServiceProvider serviceProvider)
    {
        var pipeline = serviceProvider.GetRequiredService<IMessagePipelineService>();
        var result = pipeline.Query<IntegerQueries>().With(q => q.GetNumber());
        Console.WriteLine(result);
    }
}
krasninja commented 7 years ago

Should be fixed in new release.