Giter Site home page Giter Site logo

dadhi / dryioc Goto Github PK

View Code? Open in Web Editor NEW
964.0 21.0 120.0 41.95 MB

DryIoc is fast, small, full-featured IoC Container for .NET

License: MIT License

Batchfile 0.21% PowerShell 0.01% C# 99.79%
dryioc di-ioc-container dependency-injection inversion-of-control netstandard xamarin netcore performance simplicity prism

dryioc's People

Contributors

alexandrnikitin avatar arabasso avatar azure-pipelines[bot] avatar bitwreckage avatar dadhi avatar errcode avatar havunen avatar jbrookssmokeball avatar jeuxjeux20 avatar kirodge avatar leszek-kowalski avatar lobster2012-user avatar metadorius avatar mkarpusiewicz avatar mshgh avatar pecanw avatar pobiega avatar rdeago avatar rootzhou avatar samcragg avatar serg046 avatar seriousm avatar slowlogicboy avatar t-castelan avatar thstrauss avatar vicfergar avatar vladina avatar wgebczyk avatar wjrogers avatar yallie 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

dryioc's Issues

Open generic registration error

My type definition:

    public interface ITestInterface<TKey>
    {
        
    }

    public abstract class AbsTestClass<TKey> : ITestInterface<TKey>
    {
        
    }

    public class TestClass<TKey> : AbsTestClass<string>
    {
        
    }

I use it like this:

var c = new Container(r=>r.WithTrackingDisposableTransients());
c.Register(typeof(ITestInterface<>),typeof(TestClass<>),Reuse.Singleton);

However, he seems to be unable to work, prompting the following exception information:

DryIoc.ContainerException: Registering implementation type ConsoleApp1.TestClass<> is not assignable to service type ConsoleApp1.ITestInterface<>.
  at DryIoc.Throw.It(Int32 error, Object arg0, Object arg1, Object arg2, Object arg3) in D:\Dev\DryIoc\src\DryIoc\Container.cs:9491
  at DryIoc.ReflectionFactory.ThrowIfImplementationAndServiceTypeParamsDontMatch(Type implType, Type serviceType) in D:\Dev\DryIoc\src\DryIoc\Container.cs:7548
  at DryIoc.ReflectionFactory.ThrowIfInvalidRegistration(Type serviceType, Object serviceKey, Boolean isStaticallyChecked, Rules rules) in D:\Dev\DryIoc\src\DryIoc\Container.cs:7516
  at DryIoc.Container.Register(Factory factory, Type serviceType, Object serviceKey, Nullable`1 ifAlreadyRegistered, Boolean isStaticallyChecked) in D:\Dev\DryIoc\src\DryIoc\Container.cs:177
  at DryIoc.Registrator.Register(IRegistrator registrator, Type serviceType, Type implementationType, IReuse reuse, Made made, Setup setup, Nullable`1 ifAlreadyRegistered, Object serviceKey) in D:\Dev\DryIoc\src\DryIoc\Container.cs:4534
  at ConsoleApp1.Program.Main(String[] args) in E:\Tes\PRoject\2018.11.10\ConsoleApp1\ConsoleApp1\Program.cs:43

Consider hierarchical route-like resolution cache for default delegates

Currently there is only one resolution cache and it is located in root container. OpenScope does not create its own.

This inflicts number of problems with scope (name) drpendent services, e.g. we need different implementations for scoped and singleton service, or between different named scopes. To solve it we fallback to more powerful but slow context aware Resolve(...Request preResolveParent,...) and keyed resolution cache.

The new idea is to have cache-like structure with the root cache and multiple scope caches. Each scope cache will contain delegates resolved in scope, and the cache will be identifed by whole nested scopes route, e.g. "/*/*/name/*". Then OpenScope will set the matching scope cache as default to look for, or will create a new scope cache for the first time.

Real world benchmarks

Goals:

  1. Avoid real performance regressions

  2. Automate testing without false positives

  3. Allow to experiment with improvement against self.

  4. Provide other containers with exampele of testing and containers to live longer against pure functional composition.

  5. Allow reasonably measure implementation of https://bitbucket.org/dadhi/dryioc/issues/197

Means:

  1. Several scenarios (web site, web server, desktop, mobile, cli, networking server, database, nano services(actors) ). [2]. Try to check Java world for documented cases. Document each case and reasoning for object graph.
  2. Generate all classes via tt. Not manual coding.
  3. Choose DI of several versions and last references csproj. E.g. major or specified version changes downloaded from nuget.
  4. Run BDN to get structured output against each chosen previous version.
  5. Apply proper statistical comparisons measures to avoid false negatives because of fluctuations (need to recall CS article about that I have seen and act accordingly). Stat on {moment0, monent1, moment2} * {gc, mem, time, cpu} * {workload1, workload2, ..., workloadX}. Possible prune outliers, rerun on fail.
  6. Setup and document each assert and reasoning so easy to tune.
  7. Run tests on several machines/vms/while gaming to ensure did stats/comparisons right.
  8. Use complex features of container not available in tests which cover many containers.

Will not:

  1. Store and compares historical data.
  2. Will not test other containers.
  3. Run real code (host http or read from storage).

Links:

#27

danielpalme/IocPerformance#103

UsingInTestsWithMockingLibrary sample creates transient mock instances

I've been using the auto-mocking code at:

UsingInTestsWithMockingLibrary

However, each instance it creates using NSubstitute is transient; I would like to reuse the same substitute object however I resolve it within the scope.

I've attached the code I came up with; I created a Dictionary indexed by Type to hold all the NSubstitute instances I created. But this feels like reinventing the wheel, isn't this something the container should do?

Am I missing a way to make WithUnknownServiceResolvers store the created object at SingletonOrScoped in the container on first creation?

public static IContainer WithNSubstituteFallback(this IContainer container, IReuse reuse = null)
{
    // Cache all the NSubstitute instances we create by Type.
    container
        .ThrowIfNull()
        .Register<INSubstituteInstanceCache, NSubstituteInstanceCache>(reuse ?? Reuse.ScopedOrSingleton);

    return container.With(rules =>
    {
        return rules
            .WithUnknownServiceResolvers(request =>
            {
                var serviceType = request.ServiceType;
                if(!serviceType.IsAbstract)
                    return null; // Mock interface or abstract class only.

                // resolveNSubstitute() will be called each time we try to resolve a missing
                // type, so we use the cache to reuse the substitutes we've already created.

                // Pass serviceType to arg0, resolve the cache in arg1.
                return new ReflectionFactory(
                    made: Made.Of(
                        () => resolveNSubstitute(
                            Arg.Index<Type>(0),
                            Arg.Of<INSubstituteInstanceCache>()
                        ),
                        _ => serviceType
                    )
                );
            });
    });
}

private static object resolveNSubstitute(Type t, INSubstituteInstanceCache cache)
{
    return cache.Resolve(t);
}


public class NSubstituteInstanceCache : INSubstituteInstanceCache
{
    private readonly ConcurrentDictionary<Type, object> dict = new ConcurrentDictionary<Type, object>();

    public object Resolve(Type t) => dict.GetOrAdd(t, _ => Substitute.For(new Type[] { t }, (object[])null));
}

public interface INSubstituteInstanceCache
{
    object Resolve(Type t);
}

Consider expression interpretation to speed-up first time resolution

Idea is to have fast first-time (cold start) performance, and compile and cache the expression in parallel to have a later fastest performance.

Assumptions:

  1. Activator.CreateInstance much faster than Expression.Compile.
  2. Creating expression is much faster than Compile + caching

If the assumptions are true, we may try do both the expression creation and Activator.CreateInstance. Then schedule expression to ThreadPool and return activated instance right away.

Integrate MediatR like middleware directly to DryIoc

Cons:

  • I already have (not accepted) PR to MediatR 5, here is my fork
  • Most of the MediatR code is for DI registration, will be dropped with direct integration
  • The rest of the code is just a couple of middleware entities, for Request / Response and for Notifications
  • I can come up with some new cool features... likely, probably :)
  • Out-of-the-box solution with no dependencies

Cons:

  • Stuff not related to DI.. at least ditectly
  • Other?

Give me your likes or dislikes :)

DryIoc cold start performance

After one week of investigations we found out, that DryIoc 3.0.2 is rather slow in comparison to 2.12.8 at the first execution time (cold start). In most cases the first call of a C# application doesn't count. But we measured a time increase of ca. six seconds for greater object graphs in our application. So for example our asp.net core 2.1 application starts, DryIoc resolves some small Services, than the applications tries to resolve a controller and .. we can make a cup of coffee. For a web applications this is just uncomfortable (because after the JIT compiling it's fast), but for one of our console applications this is really painful.

We looked at the expression trees which dryioc generates in version 3.0.2 and 2.12.8 for one of our object graphs. Too much to post here and to analyze in depth, but we can say, that the dryioc 3.0.2 expression tree is roundabout 90% bigger and seems even more complex.

We didn't changed the service registrations much. We just replaced Reuse.InWebrequest through Reuse.Scoped and two RegisterDelegates through RegisterMany as you mentioned out here.

Maybe you can say more about this? In most of the cases we use simple service registrations like Register<IA, A>, or factories, or made: Parameters.Of.Type ... We also use the IEnumerable-resolve Feature.

RegisterMany should indicate if no registration was made

Currently it does nothing if no registration was made, when no implementation and no service types to register were detected.
This seems wrong, as the User expects the method to do something.
Throwing the exception in this case may be a breaking, but better to inform the User earlier than to keep a silence and got an eventual surprise later.

ErrorCode: RegisteredFactoryMethodResultTypesIsNotAssignableToImplementationType

DryIoc 3.1 Preview 4 throws a ContainerException Exception with error Code RegisteredFactoryMethodResultTypesIsNotAssignableToImplementationType, because the ThrowIfNotImplementedBy-Method just checks with the C# reflection Method IsAssignableTo, which ignores implicit cast operators.

Is this behavior expected?
Maybe a better check method would be:

        public static bool IsCastableTo(this Type aFrom, Type aTo)
        {
            if(aFrom == null || aTo == null)
            {
                return false;
            }

            if (aTo.IsAssignableFrom(aFrom))
            {
                return true;
            }

            return aFrom.GetMethods(BindingFlags.Public | BindingFlags.Static)
                .Where(m => m.ReturnType == aTo)
                .Where(m => m.Name == "op_Implicit" || m.Name == "op_Explicit")
                .Any();
        }

Create Unity3d package

Resolution root bound dependency expression de-duplication

In V3 I have removed Expression level cache stored once per Factory. This simlified a problem with condition based resolution, and removed a whole lot of adhoc checks.

Problem

  • This also introduced a problem of possibly multiple equivalent but not the same dependency expressions. In case when expression is or contains a lambda, the lambda will be compiled to different multiple delegates by FEC
  • Increased the size of result expession if it contains equivalent sub-expressions.

Solution

Memoize the built dependency expression into resolution root Request by the FactoryId. Exluding wrappers. Use the memoized expression instead of building a new one.
For open-generics we will use id of closed factory.

It is not a cache, cause it will be dropped when result expression is build and compiled.
This is similar to storing expression in a local var and using this var multiple times to build the result.

MediatR - Polymorphic Notification

Hello,

I have the following two classes I use for notifications:

public class InventoryNotificationBase : INotification
{
}

public class InventoryNotificationReceived : InventoryNotificationBase, INotification
{
}

And here is my handler:

public class InventoryDenormalizer : 
    INotificationHandler<InventoryNotificationBase>,
    INotificationHandler<InventoryNotificationReceived>
{

    public Task Handle(InventoryNotificationReceived notification, CancellationToken cancellationToken)
    {
        return Task.CompletedTask;  // This is called twice.
    }

    public Task Handle(InventoryNotificationBase notification, CancellationToken cancellationToken)
    {
        return Task.CompletedTask;  // This is never called.
    }
}

Here is the publishing code:

mediator.Publish(new InventoryNotificationReceived());

The behavior I am noticing is the INotificationHandler<InventoryNotificationReceived> is being called twice and the INotificationHandler<InventoryNotificationBase> is never called.

However, I would have expected each handler to have been called once.

Thoughts?

Thanks for the awesome DI Container!

Context-based injection

I have the following classes:

public interface IValidator { }

public interface IValidator<T>:IValidator { }

public class AbstractValidator<T> : IValidator<T> { }

public class SignInViewModel {
    public SignInViewModel(IValidator validator) { }
}

public class SignUpViewModel {
    public SignUpViewModel(IValidator validator) { }
}

How can I configure registration to achive injection of IValidator<SignInViewModel> in SignInViewModel and IValidator<SignUpViewModel> into SignUpViewModel accordingly?

It's super easy in SimpleInjector:

container.RegisterConditional(
    typeof(IValidator),
    c => typeof(AbstractValidator<>).MakeGenericType(c.Consumer.ImplementationType),
    Lifestyle.Singleton,
    c => true);

Best way to achieve isolated service instance use

I'm not sure what is the best way to achieve what I am trying to accomplish so let me give you an example.

I am using Azure Functions, which are stateless, with the following signature.

public static Task Run(Message message, ILogger logger)
{
    var controller = Main.Container.Resolve<CsoConsumerController>();

    // How can I attach the passed in logger instance so the rest of the services for the current flow re-use this instance?

    return controller.Execute(message);
}

As you can see, the azure function framework passes me an instance of the ILogger already configured and initialized for this function call ONLY.

I read through the documentation and I think I need a new scope here but I'm not sure. I only want this ILogger instance to be used during the async execution of this one method call. Each function call will use their own.

Any help would be great?

Questions about property / field can not be injected

I have two definitions of tool classes:

    public interface ITool
    {
        void Print();
    }

    public class Tool : ITool
    {
        public void Print()
        {
            Console.WriteLine("I'm Tool.");
        }
    }

    public class DefaultTool : ITool
    {
        public void Print()
        {
            Console.WriteLine("Null.");
        }
    }

Interceptor definition:

    public class TestInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            Console.WriteLine("At Interceptor ...");
        }
    }

I injected the tool class as an attribute, but the parsed behavior is completely different:

    public interface IApplicationImpl
    {
        void UseTool();
    }
    
    public class ApplicationImpl :IApplicationImpl
    {
        public ITool Tool { get; set; }

        public ApplicationImpl()
        {
            Tool = new DefaultTool();
        }
        
        public void UseTool()
        {
            Tool.Print();
        }
    }

I did this test:

    class Program
    {
        static void Main(string[] args)
        {
            var c = new Container(r=>r.WithTrackingDisposableTransients());
            c.Register<ITool,Tool>();
            c.Register<TestInterceptor>();
            c.RegisterMany(new[]{typeof(IApplicationImpl),typeof(ApplicationImpl)},typeof(ApplicationImpl),Reuse.Transient,PropertiesAndFields.Auto);
            c.Intercept<ApplicationImpl,TestInterceptor>();
            
            // no.1
            c.Resolve<IApplicationImpl>().UseTool();
            // no.2
            c.Resolve<ApplicationImpl>().UseTool();
            
            Console.ReadKey();
        }
    }

Make New() method available on IResolver/IResolverContext interface

Hi,
would it be possible to add New() method to IResolver or IResolverContext interface?
In DryIoc 2.x IContainer interface was used for containers and opened scopes, so code, that only had access to opened scope, could still create objects by calling New(). DryIoc 3.x now returns IResolverContext after opening scope, and there is no way to create an object without previous registration.

Example code that was valid in DryIoc 2.x, but not in DryIoc 3.x:

var container = new Container();
container.Register<Dependency>();
using (var scope = container.OpenScope())
{
	//somewhere deep in the code, where container value is not available
	scope.New<Object>();
}

Thanks for the great library.

AutoConcreteTypeResolution should not consider a primitive type

Follows the error in the comment,
I suppose that I must register something regarding that function: Func<String, Microsoft.Extensions.Logging.LogLevel, Boolean>. Can you guys provide me some direction? =)

Btw, I am using DryIoc 3.0.2 and DryIoc.Microsoft.DependencyInjection 2.1.0.

//      DryIoc.ContainerException: 'Unable to get constructor of Boolean using provided constructor selector when resolving Boolean {ReturnDefault} #571 with args [_String0]
  //in wrapper Func<String, Microsoft.Extensions.Logging.LogLevel, Boolean> { ReturnDefault} as parameter "filter" #11 with args [_String0]
  //in singleton Microsoft.Extensions.Logging.Console.ConsoleLoggerProvider: Microsoft.Extensions.Logging.ILoggerProvider { ServiceKey = DefaultKey(0), ReturnDefault} #56
  //in wrapper IEnumerable<Microsoft.Extensions.Logging.ILoggerProvider> { ReturnDefault} as parameter "providers" #1
  //in singleton Microsoft.Extensions.Logging.LoggerFactory: Microsoft.Extensions.Logging.ILoggerFactory as parameter "factory" #42
  //in singleton Microsoft.Extensions.Logging.Logger<Microsoft.AspNetCore.Hosting.Internal.WebHost>: Microsoft.Extensions.Logging.ILogger<Microsoft.AspNetCore.Hosting.Internal.WebHost> #570
  //from container.

// Startup.cs

public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });
 
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseMySql(
                    Configuration.GetConnectionString("DataBaseIntranetCore")));
            services.AddDefaultIdentity<IdentityUser>()
                .AddEntityFrameworkStores<ApplicationDbContext>();
 
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
 
            return services.ConfigureDI(Bootstrap.RegisterServices);
        }

// IocDiExtensions.cs

public static class IocDiExtensions
    {
        public static IServiceProvider ConfigureDI(this IServiceCollection serviceCollection, Action<IRegistrator> configureServices)
        {
            var container = new Container(rules => rules
                .WithoutThrowOnRegisteringDisposableTransient()
                .WithTrackingDisposableTransients()
                .WithAutoConcreteTypeResolution())
                .WithDependencyInjectionAdapter(serviceCollection);
 
            container.UseInstance(container);
 
            configureServices(container);
 
            return container.Resolve<IServiceProvider>();
        }
    }

// Bootstrap

public static void RegisterServices(IRegistrator registrator)
{
// ILogger here is something I made, is not the same from Microsoft.Extensions.Logging.ILogger

            registrator.Register<ILogger, LogWrapper>(Reuse.Transient);
            registrator.Register<IAppConfig, AppConfig>(Reuse.Transient);
 
            registrator.Register<ICoreDbContext>(made: Made.Of(() => new CoreDbContext()));
            registrator.Register<ICoreDbContext>(made: Made.Of(() => new CoreDbContext("DataBaseCoreRO")), serviceKey: "ReadOnly");
            registrator.Register<IContextFactory, ContextFactory>();

/// etc...
}

DryIocZero installation issues

2 things I noticed that need to be fixed

  1. DryIocZero.props need to have 4.0.0 (not preview)
  2. Since new folder created by tool (DryIocZero) - path need to be specified:
    <#@ include File="$(ProjectDir)\DryIocZero\Registrations.ttinclude" #>
    in Container.Generate.tt

Resolving Wrapped Keyed Services With Condition Fails

I'm using DryIoc in a Xamarin app, with Prism as the Mvvm framework.

I recently updated Prism, which caused my DryIoc version to update from 2.x to 3.0.

In 2.x I was using a generic method to register types for specific services:

public static void Register<TService, TImplementation, TFactory>
(
  this IContainerRegistry This,
  object metadataKey
) where TImplementation : TService
{
  This.GetContainer()
      .Register<TService, TImplementation>(
        setup: Setup.With(
          metadataKey,
          (RequestInfo r) => r.Parent.ServiceType.IsAssignableTo<TFactory>()));
}

And I was able to resolve this using:

TFactory
(
  IEnumerable<Tuple<Func<TService>, metadataType>> serviceFactories 
){ }

In 3.0 this fails, in the constructor the enumerable is empty. The goal is to register keyed Service implementations, and resolve them as an enumerable in a specific parent. How should I update this for 3.0?

In 3.0, registration in the generic has changed slightly due to the removal of the RequestInfo class, and uses Request instead.

TFactory is also registered with the container.

Then, I have a registration:

containerRegistry.GetContainer().Register<TService>(
  setup: Setup.With(
    condition: r => !r.Parent.ServiceType.IsAssignableTo(typeof(TFactory))),
        made: Made.Of(
          r => ServiceInfo.Of<TFactory>(), 
          f => f.Create(Arg.Of<metadataType>())));

Which I use elsewhere through a constructor injected parameter as:
ctor ( Func<metadataType, TService> )

Decorator with servicekey throws exception which gives invalid advice on how to fix the issue for the most common reason to use the servicekey

Was trying to register a service, for which there will be many concrete types, and add a decorator for one specific of them.

I tried the following code (this is LINQPad code, which is there are Dump calls in there):

void Main()
{
    var container = new Container();
    container.Register<IService, Service1>(serviceKey: "1");
    container.Register<IService, Service2>(serviceKey: "2");
    container.Register<IService, Decorator>(setup: Setup.Decorator, serviceKey: "1");
    
    $"Main.Before".Dump();
    foreach (var srv in container.Resolve<IEnumerable<IService>>())
        srv.Test();
    $"Main.After".Dump();
}

public interface IService
{
    void Test();
}

public class Service1 : IService
{
    public void Test() => $"Service1.Test()".Dump();
}

public class Service2 : IService
{
    public void Test() => $"Service2.Test()".Dump();
}

public class Decorator : IService
{
    private readonly IService _Service;
    public Decorator(IService service) => _Service = service;

    public void Test()
    {
        $"Decorator.Test()".Dump();
        _Service.Test();
    }
}

This throws this exception:

Registering Decorator 1 with not-null service key  does not make sense,because decorator may be applied to multiple service of any key.If you wanted to apply decorator to services of specific key please use setup: Setup.DecoratorOf(serviceKey: blah)

This advice does not work. First and foremost, there is no overload of ```Setup.DecoratorOf```` that has a serviceKey parameter. Instead there is an overload with `decorateeServiceKey`, but replacing it with that doesn't work either as then it doesn't decorate anything.

Instead I had to follow the advice from here which gave me this code, that worked:

container.Register<IService, Decorator>(setup: Setup.DecoratorWith(req => req.ServiceKey == "1"));

It would be nice if the exception gave the right advice (or that the overload be added or made to work, whichever is the case here)

Speedup scoped items storing and retrieval

Currently Scope has 2 containers: one for all stored items and another one for disposal.

For some services we know their implementation type, and know that it is not dusposable. We may put them into 1st collection, then put the rest possibly disposable to the 2nd collection.

Update

  • 1st idea did not work at the end.
  • Next idea is to replace expression for scoped service in resolution root (e.g. web controllers).

Currently it is

rs.Scope.GetOrAdd(id, () => new Controller(...)).

The expression contains nested lambda and therefore adds an additional compilation and invocation time.

But it is probably safe (considering that it is the a single root) to do:

rs.Scope.SetAndGet(id, new Controller(...));

Btw it may further optimized by replacing nested scoped dependencies with rs.Scope.SetAndGet, if they are single and not Lazy (in Func, Lazy).

Moreover if variable binding is supported (dropping .NET 3.5), we may save the result if SetAndGet to variable and use this var in graph.

Operation is not supported on this platform exception on Xamarin iOS

I am trying to update to the latest preview version (3.1.0-preview-06) but there is an exception when trying to Resolve, the exception is "Operation is not supported on this platform exception" with System.Reflection.Emit on iOS, Resolve works tho on version 3.0.2

Thanks..

Memory leak with ResolveManyBehavior.AzLazyEnumerable?

In a certain situation we have observed a memory leak in ResolveMany where KeyedFactoryDelegateCache gets filled up with "identical" values.

We have something like the following where we iterate over requestType and it's parent types and have previously registered a singleton for IIncomingRequestInterceptor<RequestTypeBase>:

var interceptorType = typeof(IIncomingRequestInterceptor<>).MakeGenericType(requestType);

var interceptors = container.ResolveMany(interceptorType).ToList();

The above line of code will add an item to the KeyedFactoryDelegateCache for each call to ResolveMany.

var interceptors = container.ResolveMany(interceptorType, ResolveManyBehavior.AsFixedArray).ToList();`

This line of code will only add an item to the KeyedFactoryDelegateCache for each unique interceptorType.

If we assume that there will be only one item (which is not true in the real use case) and use Resolve we get an item in DefaultFactoryDelegateCache for each unique interceptorType (with something registered for it).

I don't quite know how to make a useful test for this since those caches are deeper in the implementation and the actual return values from ResolveMany are just fine.

RegisterMany Question

Hello,

I am trying to use the RegisterMany function restricting to the following two interfaces (MediatR):

INotificationHandler<>
IRequestHandler<,>
container.RegisterMany(new[]
{
    typeof(VehicleDenormalizer).GetAssembly(),
}, Registrator.Interfaces);

How could I use the RegisterMany to only register the two interfaces?

Thanks!

Option to speedup Scoped services creation without concurrent Func or Lazy dependencies in object graph

Scoped service in DryIoc is created via nested lambda Scope.GetOrAdd(id, () => new ScopedX());
Then inside GetOrAdd there is a lock held to ensure that () => new ScopedX() is called only once.
That guarantee ensures the service is created once.

Now, let's imagine the case when it may save us:

class Y {
    public Y(Lazy<ScopedX> x, Z z) { XY = x; }
}

class Z {
    public Z(Lazy<ScopedX> x) { XZ = x; }
}

Now we have a concurrent logic which may access XZ.Value and XY.Value in parallel. In this case, without a lock and lambda, there is a chance to create ScopeX multiple times.

BUT I would presume, that the case is rare and may be known before-hand.
Another option would be that creating a ScopeX multiple time is fine, we need just ensure that we select the same instance to be used further, and another instance is dropped (e.g. first created instance wins).

So we may provide an option to simplify an expression by removing the nested lambda and creating service as Scope.GetOrTrySet(id, new ScopedX()). This option will greatly simplify expression compilation and call stack as well.

Following will do:

var c = new Container(rules => rules.WithSmallerExpressionButNoSingleScopedInstanceCreationGuarantee());

Resolve caches object[] args values

Hi,

I'm not sure if this is a issue or by design.
I am trying to create a ViewModel-factory

public class ViewModelFactory
{
        private readonly IResolver _resolver;
        public ViewModelFactory(IResolver resolver)
        {
            _resolver = resolver;
        }

        public T CreateViewModel<T>(params object[] args)
        {
            return (T)_resolver.Resolve(typeof(T), args);
        }
}

On the first call to CreateViewModel with a System.Guid as parameter

var editViewModel = _viewModelFactory.CreateViewModel<IEditViewModel>(guidId);

everything works as expected. The constructor of the registered EditViewModel is run with the provided guidId, and other parameters injected. However on a second call

var editViewModel = _viewModelFactory.CreateViewModel<IEditViewModel>(anotherGuidId);

the guid-value from the first call is injected to the constructor again.

It seems to me that DryIoc's Resolve caches object[] args values.
Is this intended?

I'm aware that I can use

var getter = _resolver.Resolve<Func<Guid,T>>();
getter(guidId)

but not all of my viewmodels require a guid as parameter. Some require no guid, some require two, and some might require other values only known at runtime.

Thanks for any advice

Incompatibility problem?

System.MissingMethodException: Method not found: 'DryIoc.Setup DryIoc.Setup.With(System.Object, System.Func2<DryIoc.Request,Boolean>, Boolean, Boolean, Boolean, Boolean, Boolean, Boolean, Boolean, Boolean, Int32)'. at at DryIoc.Microsoft.DependencyInjection.DryIocAdapter.WithDependencyInjectionAdapter(IContainer container, IEnumerable1 descriptors, Func3 registerDescriptor, Func2 throwIfUnresolved)

I am using:
DryIoc.Microsoft.DependencyInjection 2.2.0-preview-01
DryIoc.dll 3.1.0-preview-05

Make Func wrapper consistent with Lazy to use Resolve call for wrapped dependency

Actually it is my fail to not include this change into v3.0.

The change is in internal but still may be breaking for someone. Comparing to the previous behavior, the change is more permissive (some nested dependencies allowed to be not registered yet) - so now it won't fail where previously it would.

But lets consider this a fix, bringing less surprizes to users. Then making it into 3.1 is fine :)

Add Container.WarmUp(ServiceInfo[] roots)

To enable factory delegate compilation for selected services, without actually creating them.

We may use GenerateResolutionExpressions(roots) followed by compilation.

Parity of registration methods between IContainer and IRegistrator

Since using a composition root seems to be easier with IRegistrator than with IContainer (a nested container is injected?), it would be nice if there was parity between the methods available on the two interfaces so that IRegistrator could be used instead of IContainer.

For instance, these methods are available on/for IContainer but not IRegistrator:

  • UseInstance
  • RegisterMapping
  • RegisterPlaceholder

I didn't check if overloads are missing.

Speed Optimization for short living applications

We figured out, that we can speed up the executionen of an short living application (like a console application) with Expression<TDelegate>.Compile(preferInterpretation: true), because of avoiding some JIT overhead.

Can you maybe add a rule to DryIoc, so we can switch between preferInterpretation: true and preferInterpretation: false for the compilation of the resolve trees?

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.