Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using LightInject with ASP.Net vNext #132

Open
eswann opened this issue Nov 18, 2014 · 16 comments
Open

Using LightInject with ASP.Net vNext #132

eswann opened this issue Nov 18, 2014 · 16 comments

Comments

@eswann
Copy link

eswann commented Nov 18, 2014

Hi Berhard, I was trying out some IOC containers with ASP.Net vNext, and thought I'd try to implement the built in DI using LightInject, as it's one of the DI containers I like. There's already an opensource project on Github hosted by M$ for this purpose. It has a few of the popular containers implemented and has a base set of tests that it runs on all containers. (https://github.com/aspnet/DependencyInjection)

I've created a fork and made an attempt to implement this with LightInject, (https://github.com/eswann/DependencyInjection) but I've got several failing tests to work out and I'm stuck on one failing test in particular. It's essentially a scope issue. I'm guessing there's a decent way to handle this. There is a test (ScopedServiceCanBeResolved) which basically goes like:

 var container = CreateContainer();
 var scopeFactory = container.GetService<IServiceScopeFactory>();
 using (var scope = scopeFactory.CreateScope())
 {
            //This is expected to get an "unscoped" instance
            var containerScopedService = container.GetService<IFakeScopedService>();
            //The following items are expected to get "scoped" instances
            var scopedService1 = scope.ServiceProvider.GetService<IFakeScopedService>();
            Thread.Sleep(200);
            var scopedService2 = scope.ServiceProvider.GetService<IFakeScopedService>();
            //This fails because we're really just accessing the same container inside of the scope so 
            //the same instance is returned
            Assert.NotEqual(containerScopedService, scopedService1);
            Assert.Equal(scopedService1, scopedService2);
 }

So a scope is created, and the test asks for an instance from the main container (which it expects to be unscoped) and it then it asks for an instance from the scope (which essentially amounts to a child container) and expects it to be different. But LightInject doesn't really have a child container concept that I can see. Once I start a scope, my original LightInject container also operates within that scope.

There are two main interfaces that have to be implemented: IServiceScope and IServiceScopeFactory.
The scope is a common interface that I had to implement and I just for now have it just wrapping an LI IServiceFactory and creating/disposing a new scope. But obviously this doesn't meet the requirements of the DI tests. Whether or not this is important...I don't really know but passing all of the provided tests would probably be a good idea.

internal class LightInjectServiceScope : IServiceScope
{
    private readonly IServiceFactory _factory;
    private readonly Scope _scope;
    public LightInjectServiceScope(IServiceFactory factory)
    {
        _factory = factory;
        _scope = _factory.BeginScope();
    }

    public IServiceProvider ServiceProvider => new LightInjectServiceProvider(_factory);

    public void Dispose()
    {
        _scope.Dispose();
    }
}

Anyway...any ideas on how to accomplish this would be appreciated.

Thanks!
Eric

@seesharper
Copy link
Owner

Hi Eric.

I understand that you live on the bleeding edge from a technological point
of view ;)

When it comes to ASP.Net vNext, I have not looked into this yet as it seems
to require Visual Studio 2015.
At least in order to open the projects in this repository.

I could not help but notice that you have committed something similar for
SimpleInjector. I can only assume that you ran into a similar problem there
since LightInject and SimpleInjector are quite similar when in comes to
scope handling. I also suspect that this DI abstraction can change before
it goes RTM.

Do you know if it is possible to run any of this in Visual Studio 2013?

Anyway, I appreciate the effort and I will take a look at it as soon as I
get VS2015 installed.

Best regards

Bernhard Richter

On Tue, Nov 18, 2014 at 4:51 PM, Swannee [email protected] wrote:

Hi Berhard, I was trying out some IOC containers with ASP.Net vNext, and
thought I'd try to implement the built in DI using LightInject, as it's one
of the DI containers I like. There's already an opensource project on
Github hosted by M$ for this purpose. It has a few of the popular
containers implemented and has a base set of tests that it runs on all
containers. (https://github.com/aspnet/DependencyInjection)

I've created a fork and made an attempt to implement this with
LightInject, (https://github.com/eswann/DependencyInjection) but I've got
several failing tests to work out and I'm stuck on one failing test in
particular. It's essentially a scope issue. I'm guessing there's a decent
way to handle this. There is a test (ScopedServiceCanBeResolved) which
basically goes like:

var container = CreateContainer();
var scopeFactory = container.GetService();
using (var scope = scopeFactory.CreateScope())
{
//This is expected to get an "unscoped" instance
var containerScopedService = container.GetService();
//The following items are expected to get "scoped" instances
var scopedService1 = scope.ServiceProvider.GetService();
Thread.Sleep(200);
var scopedService2 = scope.ServiceProvider.GetService();
//This fails because we're really just accessing the same container inside of the scope so
//the same instance is returned
Assert.NotEqual(containerScopedService, scopedService1);
Assert.Equal(scopedService1, scopedService2);
}

So a scope is created, and the test asks for an instance from the main
container (which it expects to be unscoped) and it then it asks for an
instance from the scope (which essentially amounts to a child container)
and expects it to be different. But LightInject doesn't really have a child
container concept that I can see. Once I start a scope, all my original
LightInject container also operations within that scope.

There are two main interfaces that have to be implemented: IServiceScope
and IServiceScopeFactory.
The scope is a common interface that I had to implement and I just for now
have it just wrapping an IServiceFactory and creating/disposing a new
scope. But obviously this doesn't meet the requirements of the DI tests.
Whether or not this is important...I don't really know but passing all of
the provided tests would probably be a good idea.

internal class LightInjectServiceScope : IServiceScope
{
private readonly IServiceFactory _factory;
private readonly Scope _scope;
public LightInjectServiceScope(IServiceFactory factory)
{
_factory = factory;
_scope = _factory.BeginScope();
}

public IServiceProvider ServiceProvider => new LightInjectServiceProvider(_factory);

public void Dispose()
{
    _scope.Dispose();
}

}

Anyway...any ideas on how to accomplish this would be appreciated.

Thanks!
Eric


Reply to this email directly or view it on GitHub
#132.

@eswann
Copy link
Author

eswann commented Nov 18, 2014

Hey Bernhard...yeah I was also playing with SimpleInjector as that is another DI container I like :). As you mentioned, I ran into some similar issues with SimpleInjector so thought I'd try my luck with LightInject. Both of them have similar issues in this vein, but frankly I feel that LightInject has a simpler approach to some things (in a good way) and that might make it easier.

The main reason I'm trying out VS 2015 is that I really like the "combined aspnet" and the unified DI concepts. In addition, I was also trying out their Cordova project time so decided to jump in feet first. There really is a lot of truly exciting stuff in this release. I do have to warn you that VS 2015 is still pretty buggy in the intellisense area and if you use Resharper as I do, it's also very buggy (but kinda works). The core stuff all seems really solid though.

Any help will be appreciated...I'll continue to work through the other failing tests and see where I get.

@eswann
Copy link
Author

eswann commented Mar 6, 2015

Hey Bernhard...did you ever try this out with vNext? I hear it's going to drop ~mid-year...I basically ran into a wall with the primary issue I had here:
There is a test (ScopedServiceCanBeResolved) which basically goes like:

 var container = CreateContainer();
 var scopeFactory = container.GetService<IServiceScopeFactory>();
 using (var scope = scopeFactory.CreateScope())
 {
        //This is expected to get an "unscoped" instance
        var containerScopedService = container.GetService<IFakeScopedService>();
        //The following items are expected to get "scoped" instances
        var scopedService1 = scope.ServiceProvider.GetService<IFakeScopedService>();
        Thread.Sleep(200);
        var scopedService2 = scope.ServiceProvider.GetService<IFakeScopedService>();
        //This fails because we're really just accessing the same container inside of the scope so 
        //the same instance is returned
        Assert.NotEqual(containerScopedService, scopedService1);
        Assert.Equal(scopedService1, scopedService2);
 }

So a scope is created, and the test asks for an instance from the main container (which it expects to be unscoped) and it then it asks for an instance from the scope (which essentially amounts to a child container) and expects it to be different. But LightInject doesn't really have a child container concept that I can see. Once I start a scope, my original LightInject container also operates within that scope.

@seesharper
Copy link
Owner

I might have to look into adding support for child containers in order to support this scenario.

@mwhelan
Copy link

mwhelan commented May 3, 2015

Hi @seesharper. I would also be very interested in child container support. I am wanting a fresh child container per test, so that I can override registrations in a test, and then have them disposed at the end of the test. Is that something I can do already with scopes, or would the new child container support be the only way to achieve that? Thanks.

@geirsagberg
Copy link
Contributor

Now that ASP.NET 5 RC1 is out and production ready, what is the status of ASP.NET 5 support in LightInject? Strongly considering migrating to ASP.NET 5, would like to have my favourite DI library on board :)

@seesharper
Copy link
Owner

LightInject is already set up for dnxcore50 (CoreCLR) and dnx451. The
missing piece is the actual DI adapter. MS is working on a test suite that
is going to be available from Nuget. Once that is out, LightInject will
provide the ASP.NET 5 DI abstraction. Maybe it's already published. I have
not checked the last couple of days.

On Monday, 23 November 2015, Geir Sagberg [email protected] wrote:

Now that ASP.NET 5 RC1 is out and production ready, what is the status of
ASP.NET 5 support in LightInject? Strongly considering migrating to
ASP.NET 5, would like to have my favourite DI library on board :)


Reply to this email directly or view it on GitHub
#132 (comment)
.

@geirsagberg
Copy link
Contributor

Seems it was moved to the RC2 milestone: aspnet/DependencyInjection#270, although it's marked as closed. No NuGet package found yet though. I'll see what I can do with eswann's fork in the meantime :)

@geirsagberg
Copy link
Contributor

@seesharper
Copy link
Owner

Do you know if there is one for RC1. They are still making breaking changes (renaming methods and so forth) in the dev branch for RC2. I could of course do an implementation based on RC2, but that would probably not even compile on RC1. As much as would love to get my hands dirty on this one I feel that this is still a moving target to say the least.

@geirsagberg
Copy link
Contributor

The earliest build is 1.0.0-rc2-15788 it seems. I understand if you are reluctant to start implementing support until things have stabilized more; I believe the ASP.NET team mentioned a possible ETA for RC2 in January on a community standup, perhaps this issue might have to wait until then.

What kind of implementation changes to LightInject do you think will be needed for full support? I assume the child container issue is still relevant?

In any case I will give it a go on making the tests pass; will post here if I succeed.

@seesharper
Copy link
Owner

I don't really think any changes to the container are required. The child container behavior can easily be implemented using scopes. Or at least it seemed so the last time I checked. Regardless of the RC2 ETA, trying to write an adapter now would be a good exercise and it would probably require just minor changes to line up with the RC2/RTM version of ASP.NET 5.
I appreciate the effort and don't hesitate to ask if you run into any issues.

@seesharper
Copy link
Owner

I got all tests passing now. Question is ..what should the Nuget package be called?

-- Microsoft.Extensions.DependencyInjection.LightInject ?

This might be good for searching Nuget

-- LightInject.AspNet?
Not really tied to AspNet

LightInject.DependencyInjection?

@seesharper
Copy link
Owner

Decision made. LightInject.Microsoft.DependencyInjection it is.

https://github.com/seesharper/LightInject.Microsoft.DependencyInjection

@geirsagberg
Copy link
Contributor

Good stuff! I agree on the package naming, keeps it under the LightInject namespace but makes it obvious that this is connected to the new Microsoft DI standard.

@seesharper
Copy link
Owner

Here is the first pre release version
https://github.com/seesharper/LightInject.Microsoft.DependencyInjection

Also available from Nuget

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants