问题
In a C# WindowForms application I start an OWIN WebApp that creates a singleton instance of my other class Erp:
public partial class Engine : Form
{
const string url = "http://*:8080"; //49396
private IDisposable webApp;
public Engine()
{
InitializeComponent();
StartServer();
}
private void StartServer()
{
webApp = WebApp.Start<Startup>(url);
Debug.WriteLine("Server started at " + url);
}
private void btnDoSomething(object sender, System.EventArgs e)
{
// needs to call a method in erp
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
Trace.Listeners.Remove("HostingTraceListener");
app.UseCors(CorsOptions.AllowAll);
var builder = new ContainerBuilder();
var config = new HubConfiguration();
builder.RegisterHubs(Assembly.GetExecutingAssembly()).PropertiesAutowired();
var erp = new Erp();
builder.RegisterInstance<Erp>(erp).SingleInstance();
var container = builder.Build();
config.Resolver = new AutofacDependencyResolver(container);
app.UseAutofacMiddleware(container);
app.MapSignalR(config);
}
}
After the creation of the WebApp I want to retrieve in other part of my code (i.e. in the button's event handler above) the singleton erp
instance created.
As far as I understand I need to use the resolve function:
var erp = container.Resolve<Erp>();
but it's not clear to me how to retrieve the container
outside the Configuration function.
回答1:
I wouldn't overthink it. Set a static variable somewhere and just hold onto it.
public static class ContainerProvider
{
public static IContainer Container { get; set; }
}
and in the block in Startup:
var container = builder.Build();
ContainerProvider.Container = container;
config.Resolver = new AutofacDependencyResolver(container);
Now you can get the container wherever you need it.
回答2:
EDIT: I have just realised the accepted answer is by a co-owner of the Autofac project, which has left me confused as it seems to go against what is in the documentation. I am going to leave the answer for now in hope of clarification.
Just wanted to provide my own answer is because whilst the accepted answer will work; it is generally considered bad practice.
From the Best Practices and Recommendations section in Autofac's documentation:
Use Relationship Types, Not Service Locators
Giving components access to the container, storing it in a public static property, or making functions like Resolve() available on a global “IoC” class defeats the purpose of using dependency injection. Such designs have more in common with the Service Locator pattern.
If components have a dependency on the container (or on a lifetime scope), look at how they’re using the container to retrieve services, and add those services to the component’s (dependency injected) constructor arguments instead.
Use relationship types for components that need to instantiate other components or interact with the container in more advanced ways.
You haven't given a specific scenario of how you want to use it in your code, so I can't provide you with an exact solution, but is there any reason you need to resolve the instance yourself? Could you not just deliver the Erp instance via dependency injection?
If the answer is yes, the following code I adapted from the Windows Forms Integration Guide page in Autofac's documentation demonstrates how this would be done:
public partial class Form1 : Form {
private readonly Erp _erp;
public Form1(Erp erp) {
this._erp = erp;
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) {
//do stuff with erp here
}
}
Then Autofac, assuming the registration has been setup correctly, should inject the instance into that class.
I hope this helps!
来源:https://stackoverflow.com/questions/48216003/retrieving-autofac-container-to-resolve-services