Lazy & Autofac: How to Delay DI Resolution
In this video, I wanted to cover how you can use the C# generic "Lazy" with Autofac in order to delay your resolution of registered types. In my particular case, this has allowed us to put a splash screen in our app (
My Social:
LinkedIn: https://www.linkedin.com/in/nickcosentino
Blog: http://www.devleader.ca/
GitHub: https://github.com/ncosentino/
Twitch: https://www.twitch.tv/ncosentino
Twitter: https://twitter.com/nbcosentino
Facebook: https://www.facebook.com/DevLeaderCa
View Transcript
to talk about all to talk about Otto FAQ and something I kind of learned about this past week that I thought was pretty cool so I'm gonna start by talking about what Otto FAQ is why you might want to use it how I've been using it and then kind of what I was able to learn in this past this past week through a project I've been working on so the idea is that when you're using composition and sort of passing in classes into other classes when you keep following this chain at some point in your application like at the beginning of your application if everything is taken to this extreme you kind of have this one spot in your application where you create all of your objects and kind of pass them in to each other so that your whole dependency trees built up so
it's a lot of work all in one spot and the really feels like magic that it can link in all the pieces that you might need so I'll kind of give you an example of that so I have a Sam or an app here and I gotta jump to the the main activity let's see here so what you're able to do so it's kind of weird if you're if you're not uses Ameren and this is what we're looking at here is sort of the Android you would call it the Android entry point so the oncreate method for a Android activity called main and what we're able to do and I'm going to kind of dive into each of these pieces is that we can do something called creating a scope which is going to be the the lifetime scope of all of the objects that
we want Auto fact to take care of we're going to resolve the application class and then this load application is a method that's built into xamarin for Android so what is you know kind of what's going on here so we'll dive into create scope and I have I made my own thing here called dependency Factory and I'll jump into that right now just so we can kind of see the auto fact pieces so Auto fact is essentially it uses so they call the dependency container so you start by making a container builder and what you're able to do what I like to do at least is I register all of what you call a module for the current assembly that we're in so what's what's a module well I'll give you an example of one and I'm gonna jump over to this spot here so
I have something called the controllers module for my application and essentially what it lets you do is you can register all these types and a nice thing that you're able to do is you can say like you know I want to register this type you can do things like say call it like a singleton so anytime someone asks for one of these things you're always getting the same instance back you can make it so that you can only resolve it by certain interfaces and another other really cool things these ones I have are all controllers and this is going to be I'm going to circle back to this because this is really the one of the core problems that I was overcoming but I have these things called controllers and they have this thing called auto activate as self and the reason why is that
with Auto FAC I'll jump back to this main activity here to explain it but what we wanted to do was resolve this application when you first try to resolve an object like the application it will say okay well what what were the sort of the the dependencies the application needs so I'm going to jump to that and then it says well if I make a new app I need a new i main view so what auto fact is able to do is say okay well who registered themselves as an i main view and then it finds that class then it says okay well what does this class need and then it kind of keeps this this chain of events going so the first time you resolve something like an application level object it fires off this really big chain of events that in theory should
go pretty fast right if you had all these really simple classes like the you know what constructor should run really fast but when you start linking in like a third party live you might have something where it's like okay well I want to to register like an ad or a notification system and just constructing that object in the third-party library might actually do some heavier lifting we're not talking like minutes or anything we're talking you know maybe hundreds of milliseconds which for a constructor is a very long time and when you start having all these pieces get linked up together suddenly your startup time can get pretty big and again pretty big meaning seconds not not like minutes or anything like that so that sort of the idea and Auto faq is able to kind of do that for you so as long as well
I'll jump to a specific example of a controller class that I have to give you an example so the reason why the controller is jumping around all over sorry but in one of the in this module all these controllers are Auto activate itself and the reason why is because I mentioned that in the entry point we wanted to resolve an application so we can use it I have these these controllers which it's gonna sound kind of weird but nothing depends on them so I need them to start up because when they're created they listen and they hook up to different events and then they can control things that way but no one has a dependency on the controllers so if I don't ever auto activate them nothing ever creates them so now to jump to a specific example of what I mean I gotta highlight
this block of code here so when this home controller is created it listens to a bunch of these different events here that I have highlighted and what happens is that once this is created it wires these event handlers up so that when people are interacting with different screens I have all this code behind they can listen to these events but but nothing actually is interested in a home controller so they're there's no spot in the code that says okay like go resolve me the home controller and this will get we eat it I have to explicitly say like no one's interested in this thing but I know what needs to be created which is why we use the auto activate thing so one of the challenges though is that because of this paradigm I have with these controllers I have a whole bunch of these
auto activate as self pieces so this is one of the challenges that we're gonna try to overcome which is that I'm basically saying that as soon as the container is is built to start resolving things from great when that happens actually go create all of these instances but the the crazy thing about these controllers is that they take in a bunch of different parameters right and because they take in a bunch of different parameters like the example I gave earlier all of these things auto FAC has to go resolve so I'll give you I'm just gonna pick like I navigation service okay so what does so homecontroller is going to need one of these but who like what is that what is this thing okay so here's a navigation service and you can see well it takes in I main view and I event tracker
okay so then you keep going up this chain so I main view I'm just gonna jump into this so it needs to take one of these and then you start you keep having this ever-growing chain of dependencies right so the challenge with having these controllers get auto activated is that they essentially force a large portion of my application to have to go get resolved as soon as the containers build and like I mentioned if all the constructors are really really short we wouldn't notice anything but they over time start to grow and take up the resolution time starts to increase to two seconds in my case and I'm gonna kind of illustrate that so that's one challenge and then the other challenge is one of the first things I kind of point though which is when we resolve the application itself it wants to start
getting all these other dependencies even if I didn't have these controllers the application root object search to have a lot of these similar dependencies anyway so it gets it gets kind of it slows down the start up the application and what the user experiences is because this happens on the main thread for the Android application the iOS application it kind of just looks like a like a like a your apps froze and you don't really see anything about all of a sudden everything kind of shows up which is kind of crappy user experience and right now the app isn't very big so this is something I wanted to address early so that as we continue to add more features that the the the startup type doesn't continue to feel like you know you click the app and you're waiting like you know 30 seconds or
something for it to pop up I mean ideally I can reduce the overall startup time but I don't want the experience to feel really bad so what did we do to to make this better so I'll start by talking about something that I was aware of with Auto fact which is really cool and that I didn't know that it didn't more of this so as an example I'm just gonna I gonna mess this one up just to to illustrate something but if we pretend that I had many different implement it can't speak so many different implementations there we go of an I log in navigator if you wanted Auto fact to give you all of them all you need you don't need to like what you don't need to do is like you know do this you know pass them all in or have like
all these special interfaces I'm just gonna like you don't need to do something like this if you had a bunch of different variations of them you can do this really cool thing oops you can put an ienumerable of them okay and then Auto fact will go say for all of the I log in Navigator implementations I have registered here's all of them and you don't have to use I in the we can use my collection kind of it's whatever you want ball not whatever I think I mean why collection maybe list as well but it's it's a pretty powerful way that you can kind of get a whole set of these uh these things but something else that auto fat can do which I didn't know about is it can actually use the lazy object so this is a really cool thing because what lazy
does is that it doesn't actually constrain you explain so if you had lazy eye log in navigator it doesn't actually make a log in navigator for you until you ask for the value of it does that make sense so I'm gonna undo that and they're just gonna make up something else here so if I wanted to do like lazy just going to lazy object called lazy example so if I wanted to do this lazy you have to basically say on your lazy object you ask for the value and the first time oops the first time that you ask for dot value it will actually go resolve it so just to show you how if you wanted to make your own like lazy thing without auto FAC you might do like lazy and you pass in where's my intellisense here you give it like a a
method to run right so so let's get rid of this I'm just going to take off this parameter because it's not really gonna help for example here so if you look at this code that I have written here when you make a new lazy object this code doesn't run until the very four time that you called value the next time you call dot value it's already sort of cached there the return result of this so it runs it only once and it's only the first time you ask for that value so it actually delays and this is the powerful part it delays this block of code that I have highlighted it delays that until you called off value and auto fax actually able to do that so that I mentioned if I have something like a home controller and I go to resolve it or
to to auto activate it it then wants to go resolve all these well that's crappy because it's going to go do all that work all at once and if we look in here really if you ignore this method just for now I only need a true reference to a home view model user manager and an OAuth manager I need these objects here right away so that I can hook up to them but all these other things that I have passed and I don't actually need them yet I don't need the real reference yet I can delay that until the first time I go use that so this is the idea behind like delaying the resolution until we actually go need it which is I'm just gonna save us some startup time so the first thing the first thing I did was I found this spot
in this controllers module so I've already kind of reverted some of the code so I could show you in this video but I had all this auto activate as self stuff going on and what I did was I said well I'm going to implement a interface called AI controller and all of these controllers I'm just gonna say like register them as as an AI controller and someone else at some point in time is going to be responsible for resolving all of these and where did I put that now there okay so if you'll notice I talked about lazy right I actually combined and this is something Auto fact does out-of-the-box which is really cool I have this lazy eye collection of Pi controllers so what does that mean so I've already kind of talked about what Autofac does lazy and what Auto fact does with
an eye collection so the really cool thing here is that when Auto fact creates this reference for us this the startup object that I've created what it's able to do is give us a collection of all of the controllers but it won't actually go resolve them until we ask for the value right so basically I don't want to say this happens instantly but when Auto fact sees this it goes well I don't need to go make all the controllers right now I can give you a delayed like resolution of all of the controllers and when I say all the controllers I mean I collection of my controllers I can give you a delayed resolution of that which is awesome because now all of my controllers instead of taking all that startup time rate and construction right because auto activate self would mean as soon as
the containers ready the dependency container all the controllers go get built which means basically almost all of the objects in my my application give those we don't want that so this delays it for us which is really cool I've kind of wrapped it up in some other stuff like I had this only one stay here but all that that's doing just to make this more clear all that that code is doing is oops lazy controller so it's just calling lazy controllers dot value that's it that's all it's doing and by doing that auto fat goes oh I need to go resolve all these controllers right but I've delayed it until at some point in time when I call startup async so now instead of happening all when my my application is created I can say don't go make all these controllers yet only make them
when I say too which is really powerful for us because we can put that what I wanted to do is put it behind a splash screen so instead of the application starting up and you're kind of waiting and being like you know it's only seconds but still it kind of sucks you're waiting there being like well you know I click the app icon like why isn't it popping up and then all of a sudden everything's there it pops up sooner and then you get less sort of a little splash screen where you wait so it didn't it didn't reduce the overall time it just improves the experience and the reason why is because I can say only go resolve these once I put a splash screen up so that make the user wait once it doesn't feel sorry once it feels like there's some sort
of like progress indicator that kind of thing so that was a really powerful thing for the controllers that might have been kind of hard to follow especially if you haven't used an auto fact before but for me like you can see all these other things are passed and is lazy because these were things that also took some time to start up so I have this this one's actually kind of cool so I have this lazy eye called the eye splash work so in xamarin you heard me at least for us we have an Android app in an iOS application and each of those has some platform specific startup code on Android I found that the startup code specific to that platform was taking about a second and the seconds not really a long period of time but like like I mentioned that's probably gonna keep
increasing because of more dependencies being added it's just it's just time where the user doesn't they're not really getting that out of that feedback of like I'm starting the app why isn't it here so it's a whole second for now the of work that I was able to defer and for our use case that was things like setting up the background push notifications I think that was mostly and a couple of like third-party libraries for analytics and things like that so you can see this lazy splash work thing I have the instance variable up here and it's the first thing we do in this set of background work but again it's not during construction time I've deferred it into a point in time where I have the splash screen up at least which is pretty cool so that was the mechanism that I started to
use and so control is one big part of it this application specific logic was one big part of it and just to kind of show you what that looked like let's find the Android splash work here so this all this code and it doesn't look like too much all this code was in the Android application entry point but that's like registering all of the authentication handlers that's registering push notifications which is also asking the device for a cloud messaging token so and then this is like sort of a crash reporting so it starts to do all this stuff on startup which it was the right spot to put it but for us now like we wanted to fir that until we have a splash screen up so all of this work that you see here I'm just going to jump back all that work is
now called basically right here in this line and that's because I can ask Auto fact to give me a delayed resolution of that class now we can call them when foot the splash screen right so that all sort of makes sense of theory so what did I do to get a splash screen up so I'm going to jump to our main page here you'll notice that I have a combination if some things are lazy and some things aren't so our main view model this is I had to do a bit of like digging around to see like what dependencies we could work with because it doesn't make sense to make them lazy if I have to resolve them right away in the constructor anyway so what I mean by that is well I got a double click view model so it highlights it you can
see it's used right here in the constructor so if I did this if I did and then the first thing I do is this it didn't offer any benefit and the reason why is because like I'm basically forcing the resolution right away anyway right it it happens it's not before this thing was constructed and passed in it's actually like it happens still in the constructor so we don't even have the reference to the object in any way so there's no benefit to making these things lazy but if I pick I'm just gonna backspace that I have this the start of class we were just looking at right so I'm going to jump back it's this thing that we were just looking at because if I didn't delay the resolution of that I mean these are lazy anyway so that's nice this hangry startup thing I
wanted to to put this up once I had a splash screen up so if I highlight this you can see the only spot its uses in this callback here it's not actually I'm pointing on my my screen with my finger so I'm really helping anyone I'm gonna highlight there we go this hangry startup law object is used the application is called hangry by the way in the case that wasn't obvious like he just realized there probably said it a few times now and or you've seen it on screen the application is hangry but the this this this reference here isn't actually used until until later so if I look at delayed hangry started out where we use that strong I'm going to collapse on this code so it's easier to read but when this view appears I'm gonna go run this thing asynchronously when I
go run that asynchronously scroll all the way back to the top here then it's gonna start resolving stuff so what I was able to do is say okay instead of instead of trying to get this the difference is like when this application used to show up you get the main page and everything would be populated but you would have to wait an extra long period of time everything that main page needed to show you which is essentially the whole application had to go get resolved now what I'm able to do is I can give you the main page and then if we look at the things that aren't lazy I have a view model for it and spoiler alert this view model has basically nothing in it so that's really fast for us to get a reference to a splash screen and I didn't make
that lazy because I want that splash screen I need to show it right away right you can see sort of master-detail page is like I don't know the best way to so it's kind of it's gonna be tricky to explain with my hands and so and not running an emulator because the emulator is really slow I'm like computer so I can't show you what it looks like but basically I needed to put the domain what you're gonna see on screen is a splash screen where you write away and I have a slide-out menu that we need to be able to access right away as well so these things could not be lazy or they could be lazy but like I mentioned earlier zero benefit to it and then everything else we can delay so basically the way this code reads is that we put we
set a menu and we set sort of a splash screen right away for you right so the user sees that as soon as the app comes up then while the splash screen is up then I go start resolving the rest of the application which is really cool and then when that's all done there's this other method here and it says invoke on main thread so that's where once we're done all the asynchronous stuff for the the splash screen work then I'm going to actually all this code does this kind of gets rid of the splash screen and puts like our home page up so hopefully that kind of made sense so the again big difference is that all of these things that are marked as lazy up here I don't need auto fact to go make them ahead of time for me I can delay
the resolution which takes time I can delay the resolution of those things until I actually need them so that means I can put a splash screen up I can do some background work and the experience is way better for the user so I think that's mostly and I didn't want to show I wanted to kind of show on my phone it's gonna be kind of hard to to get it up on the webcam but maybe I can do that so I make this bigger boom there we go that's my face sorry I'm just gonna try this quickly yeah so I can probably flip this around pretty quick but what you're gonna see right away is that there is still the white screen not to like I have to do a bit more digging to see like what other things Ameren is doing if there's debug
settings that actually make the startup time a little bit slower so there's still a white screen but hopefully I can flip the phone fast enough around for you so you can see the the splash screen and what you'll what you should hopefully be able to understand from all this is that the time that you see the splash screen that's actually time that previously users wouldn't see anything or they'd see the white screen for even longer and be like well why am i waiting and it's about one to two seconds so so that's my phone I'm gonna try to write so what you could see is why that little spinner is going I'll do it again wow that spinner was going that was actually just dead time before so white screen spinner right so because we were able to use lazy with Auto I could defer
all of that extra work until I put this flasher you know and like I said before without the splash screen you get that white screen you're like wall what's going on like this kind of sucks and I I can only imagine that's going to get slower as we add more things and so like we don't have we don't have ads or anything like that and I'm assuming if we put an ad SDK in that's going to have some extra communication with external servers to reach out to be able to fetch the ads sort of configure your your API keys and things like that so when that happens that's extra load time we don't want that to happen while the user has a white screen we'd want that while with safari is up so for me reflecting on on this what I learned with sort of
the lazy combination with Auto fact when I was building desktop applications we already we already had a splash screen so our I never really had to think about this because we had the splash screen up and we could just say go over solve all the things by the time we were building the container because I was able to put Auto fact in from the start of this application it meant that as soon as I was building it I was already set up to experience this delay so yeah it's it's one of those things like if you already have a splash screen and you're not resolving a dependency container until you have the splash screen up this way not really benefit you maybe it might actually it might benefit you if you know that you're not gonna have to resolve certain things until way later in
your application lifecycle that could be hugely beneficial I guess for me for me I I needed those controllers to be resolved pretty early on in the application lifecycle so essentially once a splash screen goes away I need those controllers to be there because they hook up to all the button presses and things like that but maybe maybe you have an application and like there's some workflow that gets really cumbersome with in terms of creating objects and things like that and the you don't need to do that until the user actually navigates to that part of the application well great lazy can work for you in that case because you can save all your startup time and defer that to way later maybe it's something that the user they never even like it's an optional workflow they never have to navigate to it so I make
them wait that extra startup time to resolve those objects if they're never even gonna use it like I said for me I need those controllers to be resolved because once they're on the home screen and you say like you want to start a session or join a session or or do any work in the application I need those controllers resolved so there's for me there was no way around it but you might have instances where you're like you know I don't I don't need all those objects created right now you want the you want your code to be able to have those access to those dependencies but you might not need the actual concrete references until later in the app so yeah I mean that's I think that's all for today yeah I just wanted to be able to share that because I been using
Auto fact for a few years now when I didn't even know
Frequently Asked Questions
What is Autofac and why should I use it?
Autofac is a dependency injection container that helps manage the creation and resolution of your application's dependencies. I find it useful because it simplifies the process of managing complex object graphs and helps improve the maintainability of my code.
How does lazy resolution work in Autofac?
Lazy resolution in Autofac allows me to defer the creation of certain dependencies until they are actually needed. This means that instead of resolving all dependencies at startup, which can slow down the application, I can wait until a specific point in time to create them, improving the user experience.
What challenges did you face when using Autofac with controllers?
One challenge I encountered was that when I auto-activated my controllers, it forced Autofac to resolve a large number of dependencies all at once, which increased startup time. To address this, I implemented lazy resolution for my controllers, allowing me to delay their creation until they were actually needed, which significantly improved the startup experience.
These FAQs were generated by AI from the video transcript.