Thursday, April 27, 2017

Creating an IOC Container for ASP.NET Core

I recently added support for ASP.NET Core to my Tact.NET IOC Container, and I thought that I would share some of the interesting requirements I discovered while doing so. I had originally expected the default ASP.NET Core container would follow the same rules as the official Microsoft Unity container, but that turned out not to be the case!

1) Register is first in win.

The Unity container was last in win, and it would completely disregard the original registration. With ASP.NET Core you need to preserve the original registration and then treat all subsequent registrations as addition registrations that will only be resolved when ResolveAll is invoked, similar to keyed registrations in Unity. Which brings us to our next difference...

public class RegisterIsFirstInWinTests
{
    [Fact]
    public void Unity()
    {
        var log = new EmptyLog();
        using (var container = new TactContainer(log))
        {
            container.RegisterSingleton<IExample, ExampleA>();
            container.RegisterSingleton<IExample, ExampleB>();
 
            var example = container.Resolve<IExample>();
            Assert.IsType<ExampleB>(example);
        }
    }
 
    [Fact]
    public void AspNetCore()
    {
        var log = new EmptyLog();
        using (var container = new AspNetCoreContainer(log))
        {
            container.RegisterSingleton<IExample, ExampleA>();
            container.RegisterSingleton<IExample, ExampleB>();
 
            var example = container.Resolve<IExample>();
            Assert.IsType<ExampleA>(example);
        }
    }
 
    public interface IExample
    {
        string Name { get; }
    }
 
    public class ExampleA : IExample
    {
        public string Name => nameof(ExampleA);
    }
 
    public class ExampleB : IExample
    {
        public string Name => nameof(ExampleB);
    }
}

2) ResolveAll includes single registrations.

Unity has the concept of keyed registrations, where you can register the same type multiple times with distinct keys (strings) and then resolve them individually by key or as an IEnumerable with ResolveAll. In ASP.NET Core there is no concept of keyed registration, and ResolveAll will return all registrations made for a given type. This means that registering a single type will cause ResolveAll to return an IEnumerable with one value.

public class ResolveAllIncludesSingleRegistrations
{
    [Fact]
    public void Unity()
    {
        var log = new EmptyLog();
        using (var container = new TactContainer(log))
        {
            container.RegisterSingleton<IExample, ExampleA>();
            container.RegisterSingleton<IExample, ExampleB>();
 
            var examples = container.ResolveAll<IExample>();
            Assert.Equal(0, examples.Count());
        }
    }
 
    [Fact]
    public void AspNetCore()
    {
        var log = new EmptyLog();
        using (var container = new AspNetCoreContainer(log))
        {
            container.RegisterSingleton<IExample, ExampleA>();
            container.RegisterSingleton<IExample, ExampleB>();
 
            var examples = container.ResolveAll<IExample>();
            Assert.Equal(2, examples.Count());
            }
    }
 
    public interface IExample
    {
        string Name { get; }
    }
 
    public class ExampleA : IExample
    {
        public string Name => nameof(ExampleA);
    }
 
    public class ExampleB : IExample
    {
        public string Name => nameof(ExampleB);
    }
}

3) Generic resolution is required.

This was a neat feature that I had not used before! You can register generic types without any generic parameters, and then the container will fill in the generic parameters based on the resolve request. So, for example, I could register IRepository<> to type DataRepository<>, and then when I call container.Resolve<IRepository<User>>, the IOC container will automatically try to construct a DataRepository<User>

public class TactContainerTests
{
    [Fact]
    public void GenericResolution()
    {
        var log = new EmptyLog();
        using (var container = new TactContainer(log))
        {
            container.RegisterSingleton(typeof(IRepository<>), typeof(Repository<>));
 
            var userRepository = container.Resolve<IRepository<User>>();
            Assert.IsType<Repository<User>>(userRepository);
        }
    }
 
    public interface IRepository<T>
    {
        string ClassName { get; }
        string GenericName { get; }
    }
 
    public class Repository<T> : IRepository<T>
    {
        public string ClassName => nameof(Repository<T>);
        public string GenericName => typeof(T).Name;
    }
 
    public class User
    {
    }
}

4) You have to convert IServiceCollection to your container.

I like how the new .NET separates their service registration from the container itself. In your ASP.NET Core wire up you will work with an IServiceCollection, which will then be converted into a container after you are done filling in your registrations. This means that if you want to create your own container, you will need to map the service collection into your container.

Enjoy,
Tom

17 comments:

  1. You’ve written a really great article here. Your writing style makes this material easy to understand.. I agree with some of the many points you have made. Thank you for this is real thought-provoking content.
    MSBI Online Training
    MSBI Online Certification
    Learn MSBI Course

    ReplyDelete
  2. Good Post! , it was so good to read and useful to improve my knowledge as an updated one, keep blogging.After seeing your article I want to say that also a well-written article with some very good information which is very useful for the readers....thanks for sharing it and do share more posts likethis. https://www.3ritechnologies.com/course/data-science-online-training/

    ReplyDelete
  3. Online casino, football betting website, the best price, we are ufabet, a direct website from the parent company. Did not pass agent Out of the problem of cheating More reliable with faster service Financial stability, deposit-withdrawal within 1 minute with an automated system.

    ReplyDelete
  4. Thanks for the great post you posted. I like the way you describe the unique content. The points you raise are valid and reasonable. I am a tech support expert telling you about.
    Safemoon Wallet
    Login to Citi Card
    Kraken Login
    Gemini Login
    Regions Bank login

    ReplyDelete
  5. Thank you. I authentically greeting your way for writing an article. I safe as a majority loved it to my bookmark website sheet list and will checking rear quite than later.
    섯다

    ReplyDelete
  6. Thanks for the informative and helpful post, obviously in your blog everything is good..
    스포츠토토

    ReplyDelete
  7. It's really nice and meanful. it's really cool blog. Linking is very useful thing. You have really helped lots of people who visit blog and provide them useful information.
    한국야동

    ReplyDelete
  8. This post is disseminating valuable information to people who are most concerned of the following issues being targeted by this site. Many certainly will keep coming back to check out updated posts.
    안전놀이터 모음

    ReplyDelete
  9. Nice Information I read this hope you share another ane thanks.here, is Nora our organization are providing security software and build your website and promote your brand you can go and read this.
    crypto wallet|
    exodus wallet|
    metamask wallet|
    trezor wallet|
    phantom wallet|

    ReplyDelete
  10. The KuCoin exchange is a popular name in the crypto world. To buy coinbase pro login | vend cryptos on this exchange, you're asked to subscribe up for a new account. Losing access to your Coinbase account .cryptocurrency. At times, users create a kucoin login account and then do not use it for a long duration.But, the next time they try to log in, they seem to have forgotten the Coinbase login password.

    ReplyDelete
  11. Fantom is fully compatible with fantom crypto wallet Metamask, Ledger and the leading mobile wallets. fWallet is Fantom fantom wallet Official wallet. QuickSwap (QUICK) is an Ethereum token that powers QuickSwap, a decentralized exchange that runs on the Polygon Network in order to quickswap provide faster and cheaper transactions on Ethereum.


    ReplyDelete
  12. Uniswap Exchange is an innovative exchange protocol built on Ethereum. It allows anyone with an Ethereum wallet to exchange tokens without the involvement of any central party. Kráken Ĺǒgiń : Bitcoin & Cryptocurrency. uniswap exchange Kraken Login | Sign In to Kraken. That is the reason crypto trade stages and crypto wallets have been advancing toward the spotlight so fast. Line through the characteristics that Kraken login. kraken login Gemini Login is a straightforward, beautiful, and safe platform for building your cryptocurrency portfolio. Gemini is a cryptocurrency exchange that allows consumers to invest their money in cryptocurrency trading. This exchange is one of the most popular for Bitcoin trading owing to its user-friendly and safe trading features. gemini login Available as a browser extension and as a mobile app, MetaMask equips you with a key vault, secure login, token wallet, and token exchange—everything you need to manage your digital assets. Explore blockchain apps. MetaMask provides the simplest yet most secure way to connect to blockchain-based applications. You are always in control when. metamask login

    ReplyDelete
  13. I'm writing a paper on the subject of your article. I feel like I've found a very precious treasure. Thanks to you, I think I can finish my thesis safely. Please come to my blog and read my post related to yours. 먹튀검증업체

    ReplyDelete
  14. This platform offers comprehensive insurance protection, ensures your ongoing liquidity, supports APIs, and enables program customization. This is a cloud-based software as a service (SaaS) that you may access through your web browser. To utilize Coinbase Prime Login , you don't need to run any additional downloads or use any special hardware.

    If you wish to receive some cryptocurrency in your MetaMask wallet, you must first know your MetaMask wallet address. Simply login in to your wallet and browse to the location where your account name is listed to obtain your MetaMask wallet address. Following that, you may view your name, which can be located under your name.

    ReplyDelete

Real Time Web Analytics