BrandGhost

IT'S ✨MAGIC✨ - Easy Plugin Loading with Reflection + Autofac

This video is part of a series where we will explore how to create a facade in C#. We will be using a repository as a basis for our facade and then exploring some of the challenges and benefits. Our facade will be composed of multiple plugin sources where we will use Autofac to load them in dynamically at runtime. Want the source for this video? Check it out here: https://github.com/ncosentino/DevLeader/tree/master/PluginLoading https://github.com/ncosentino/NexusLabs.Framework/tree/master/Nexu...
View Transcript
so I've been using Auto fact for plug-in loading and dependency management for a long time now and I've come up with a few patterns that I've been using basically across all of my projects but quite honestly when I reflect on it there's a couple of code smells that it's kind of leaving across my code base and more recently I've been trying to come up with a solution for it so before I jump into that just wanted to hear from you in the comments if you use Auto fact or another di framework what are your solutions for plug-in loading and handling dependencies okay so for me at least my big problem is that my solution currently leverages marker interfaces and while this works I kind of feel like it's defeating some of the purpose because when I have things like a facade I need to know about the facade and not just the fact that I want the service I have to know that service is a facade and I don't really like that so I've handled that with marker interfaces and more recently I've come up with the solution that I'm pretty happy about so if that sounds interesting please give the video a thumbs up subscribe to the channel because it really helps me know that you like content like this and with that said let's get right into the code all right so we have our code pulled up where we were doing assembly loading and taking advantage of Auto fact and I'm actually going to jump over to a solution that I put together in my shared Library code what I've been able to do is I solve the problem basically with an implementation that addresses both of the criticisms I had where the discovery issue was present and the dependency on the specific facade marker interface was present as well to elaborate what I was able to do is I ended up creating an extension method for container Builder and this is actually another bit of a helper on top of it but I'll scroll down to the actual implementation this is really where the magic happens for kind of solving these two issues let me explain what's going on here and how this kind of addresses the situation instead of looking at the registrations the way we had previously where we have separate modules for each plug-in registering the plugins themselves and then other may be dependent code that has to register a class that in the Constructor takes in a facade interface what we're looking at here is a extension method that will register the type of the facade and this will be for us requirement that the facade implements the same interface as the source so in our example it was irepository right so the class that you're registering needs to also implement the interface that it takes in kind of like that circular dependency problem we were addressing previously the facade meets the same interface as its sources that it takes in and we call register type so that's similar to what we had before but we use with parameter as part of this Auto fact extension method that I have here so what we're doing this is a simple implementation and you might not be able to take advantage of an extension method like this you might need your own kind of constructed attempt here but what I'm able to do is going to look for the parameter name that matches our source and what I mean by Source here is in our case the set of repository plugins in our facade we just call them repositories so when we would go to do this registration we would have to pass in the word repositories as the parameter name or as we saw above you might not have seen because all these stupid dot comments but this code here actually is another variation that tries to find that Constructor parameter name for us so that's another little shortcut but anyway we try to find that parameter and then when it goes to actually resolve it goes and looks specifically for those types of T source that have this attribute that's on them and this is a discoverable attribute that I created so this is why it solves both problems we move away from the marker interface for the discoverable and so I discoverable repository for us now disappears which is great so one marker interface gone we do replace it with an attribute but I think it's a lot more appropriate because we're decorating a class an implementation and saying I want this implementation to be discoverable and we'll look at the other part to this after but now with that attribute on it we no longer have to actually go explicitly register that type in Auto fact so that's a really cool quality of life aspect to this plug-in loading that I'm really happy about now the next part and I guess sort of the final part to this facade piece here is that we do this extra check at the end and this is my sort of safety net again this extension might not work well for you but what I've done here is it's a safety net that basically says try to resolve all of the T source so in our example it's I repository so give me all the I repositories that are registered and it you should only ever get one back and that one that we get back truly should be and I don't have this explicitly here but we could probably even improve this but that one repository that we get back should be the facade right so if someone goes against this pattern that's being implemented in here this on activated callback will actually blow up for us and say look we actually can't be sure that this is the expected Behavior anymore someone has registered something a different way that meets irepository in our example and by doing so you're no longer guaranteed that you're going to be getting back this facade and I should probably just mention more explicitly that this with parameter part is actually the piece that allows us to get around that circular dependency issue so hopefully that helps a little bit explain here and I'm going to jump over to the extension method we can use for helping with this discovery so as I mentioned yet another extension method and it takes in an assembly that you want to be scanning for plugins and it basically will go through and say get me all the types and give me all of the types that have this discoverable attribute on them and then I just have a couple of different flavors for how you might want to register things so whether or not you want to use the Singleton approach whether or not you want to register your implementation as the exact class or an interface or both so there's a couple of different variations I almost always just will use the implemented interfaces anyway this could be extended if you're if you want to kind of use your own variation of this you can do whatever you'd like here but this is sort of my attempt at covering a few different cases I could foresee in my own code and if uh if something comes up I'll come back to here and add it so this isn't a shared Library I actually published this nuget package and I use it across all of my projects and now I'm going to go back and all these places where I want to update this pattern I will go back to using this so as long as we go to call this method we can go discover truly now discover the types that are flagged and register them the container let's go see how we can use this in our other application that we were looking at and get rid of some of those marker interfaces all right so we're back in our other application first thing I'm going to do is I'm going to go add the nuget package for this so how do we go make this happen well I said we're not going to need these modules anymore for our plugins so let's get rid of them next thing I said is we don't need the marker interfaces anymore either so let's get rid of those two now it's already going to start complaining at us right because here's the marker interface let's just go back to I Repository here's the other marker interface for the other plug-in let's get rid of that the facade no longer needs to say that it's a facade this also doesn't need to actually say that it's discoverable see how this code is getting much more clean great stuff and then we have one last spot here which is just we no longer have a dependency right that is explicitly the repository facade that was one thing that really irked me because I don't want anyone to know that this is actually a facade that's coming in here so what things do we still need to do to make this work I'm gonna need my nougat package also included here because I want to flag this with my attribute right so I don't you don't see discoverable anything kind of coming up here so let me go ahead and add nexuslabs.autofac discoverable for registration and then the mode that we want to use is implemented interfaces and we do want to Singleton in our case so Singleton so here's one of them done I'm not gonna do the other plug-in yet just to kind of show you that one will stop loading but I'm also going to go back to our program we don't need um this same type of registration anymore so what I'm going to do instead is for each assembly and assemblies that autocomplete is so good I'm gonna say container Builder we want to register the discoverable types for the assembly and actually I don't want this module anymore the way that this is set up I actually want to do register Now where's the facade one register facade with discoverable sources so here's the facade that we want to register and that's what we want I didn't include inside of that extension method anything about implemented interfaces or Singletons so this is now what the registration at the facade looks like and if I go back to program you can see that I'm still going to scan for the assemblies that part didn't change but I'm just going to explicitly register the discoverable types so they must be the ones that have the attribute and you saw me only add one attribute so we should only see stuff from plugin one get printed a pretty simple mistake this is because I blew away the modules themselves that actually put in the objects here so to prove to you that the registration for the discoverable type is loading we can debug this super quick we'll go through our container Builder to register the discoverable types we should notice that we have at least one discoverable type right we can't enter an iteration of this for each Loop without a discoverable type so we at least have one very cool if I jump to the repository facade if I check the repositories that came in we do have one um it's behind my video here so let me go back down here we can see that we have one and it's coming from oh it says right there repository for plugin one but there's no objects inside of it I forgot that the other modules I deleted was adding the objects so let's tweak this a little bit just to make it a fair comparison instead of passing in we would either need to add a module or something inside of the plugin that knows how to wire this up or in this case a new array and just kind of repeat the same thing that we had here before we'll stick with the letters again and plug in one this is for plugin two and we'll stick with numbers here I'm pretty confident now we go to run this we're not going to get anything from plugin two we will get them from plugin one but there we go my object these record types are awesome now so plug in one we can see the three that come in and here's how easy it is to get plugin Two showing up now right using Auto fact and we will flag this with the discoverable attribute I'm just going to take it off of plugin one drop it on plug into and now when we run this this one will be discoverable and we get all six in this video I can count properly we got all six plug-in objects showing up here so in summary I was able to use a different Auto fact registration approach that totally let me circumvent all of the marker interfaces I had so finally I can remove those from the code base and try to leverage this different registration pattern so again I'd love to hear from you in the comments if this is an approach that makes sense for you in Auto fact or if you use a different approach or a different di framework to handle this kind of thing so if you like this video please give it a thumbs up and subscribe to the channel because it lets me know that you like content like this thanks and we'll see you next time

Frequently Asked Questions

What is the main issue with using marker interfaces in AutoFac for plugin loading?

I've found that relying on marker interfaces can lead to code smells in my projects. Specifically, when I need to know about a facade, I shouldn't just be aware that I want a service; I should also know that the service is a facade. This reliance on marker interfaces feels like it defeats the purpose of clean dependency management.

How does the new extension method improve plugin loading in AutoFac?

The new extension method I've created allows for a more elegant registration of plugins by using attributes instead of marker interfaces. This way, I can mark classes as discoverable without needing to explicitly register them, which simplifies the code and enhances maintainability.

What should I do if I want to implement this new pattern in my own projects?

To implement this new pattern, you can start by adding the NuGet package I published, which includes the extension methods for discovering and registering types. Then, you can replace your existing marker interfaces with the discoverable attribute on your classes, allowing AutoFac to handle the registration automatically.

These FAQs were generated by AI from the video transcript.
An error has occurred. This application may no longer respond until reloaded. Reload