简体   繁体   中英

Webforms Autofac parameter to constructor using VB.NET

So, i want to do what I feel should be such a simple task... pass in a parameter to a constructor using Autofac!

However, I have managed to get a work around working, but just dont think this is correct, I feel i am chaning too much of the recommended code from the Autofac guides

I am more than happy for answers in C# or VB.net it doesnt matter, the location of code is all the same

So, here is my setup (im not fussed about neatness, just trying to get this to work for now)

In my global.asax I have:

'***Note, the autofac guide had this a a private shared, see below for why i changed it***
' Provider that holds the application container. 
Public Shared _containerProvider As IContainerProvider

' Instance property that will be used by Autofac HttpModules
' to resolve And inject dependencies.
Public ReadOnly Property ContainerProvider As IContainerProvider Implements IContainerProviderAccessor.ContainerProvider
        Get
            Return _containerProvider
        End Get
End Property

then within my global.asax within application_start I have:

***again, note, originally I was using IMyClass when registering type... not sure this or that is correct***
Dim builder As New ContainerBuilder()
builder.RegisterType(Of MyClass)().As(Of MyClass)().InstancePerLifetimeScope()

'... continue registering dependencies...
' Once you're done registering things, set the container
' provider up with your registrations.
_containerProvider = New ContainerProvider(builder.Build())

As you can see, origianly the _containerProvider was just public, but I have had to make it "Shared" for this to work, this feels wrong right away!

so, now, in my webForm1.aspx.vb I have this:

Public Property MyClass2 As IMyClass
Private _myClass As IMyClass

Now, because I have adjusted the global to "registerType" to use the actual object, not the interface (which, again seems wrong having to change that too), means now my webform public property is not being set (but, because of my work around, i dont need that anyway)

Also, note the private _myClass ... this is for my workaround

so, now in my Webform init method, i have the following:

WebForm1.aspx.vb*

_myClass = [Global]._containerProvider.RequestLifetime.Resolve(Of MyClass)(New TypedParameter(GetType(HttpRequest), Request))

which now instantiates my _myClass with the parameter correctly injected in... this is great, whoopadeedoo

...but... I dont think this is correct.

Now, when I didnt need to pass in a parameter to the construtor, it all worked nice, didnt need to change any of the code from the autofac guide, it just worked, set the public property on my webform.aspx page fine, was really nice.

But, as soon as I start to work with a paramter being passed into the construtor, it seems everything needs to be tweaked so it will work? is this correct?

I have even tried the deligate guide from autofac, but that also doesnt work for me at all by doing this within my webForm.aspx page:

Dim container As ILifetimeScope = [Global]._containerProvider.RequestLifetime
Dim myClassFactory As MyClass = container.Resolve(Of MyClass.Factory)
Dim myClassholding As MyClass = myClassFactory.Invoke("ABC")

even tried without the "Invoke", but "cannot be indexed because it has no default property"

Just incase it helps, here is "myClass"

Private _myID as integer
Public Delegate Sub Factory(myID As integer)

Sub New()
End Sub
Sub New(myID As integer)
    _myID = myID
End Sub
Public Sub DoSomething() Implements IDfCookieManager.DoSomething
    'do something with myID
End Sub


I know I can pass the id in as a parameter to DoSomething, but i want to understand how to pass this into the constructor so, my questions:

If this is not how to do this (which I am hoping its not correct), how would I do this without needing to change all the global setup??

Is it best to use a deligate factory or just resolve?

do I really need to change the global container to be shared/static, so that i can access the container from within my code?

So, there are two ways, but firstly, shouldnt need to mess around with how Autofac suggests setting up the ContainerProvider in global.asax... i can keep it as non shared (not static), and to access this value I do the following:

   Dim cpa As IContainerProviderAccessor = (CType(HttpContext.Current.ApplicationInstance, IContainerProviderAccessor))
   Dim scope As ILifetimeScope = cpa.ContainerProvider.RequestLifetime

Also, in our webform.aspx page, Public Property MyClass As IMyClass should not be added when we need to pass in parameters to the constructor when resolving (otherwise it will be resolved before we try to manually resolve it!

1: Passing in using TypedParameter

Here is my adjusted code to pass in the parameters using resolve (including the lines above):

Dim cpa As IContainerProviderAccessor = (CType(HttpContext.Current.ApplicationInstance, IContainerProviderAccessor))
Dim scope As ILifetimeScope = cpa.ContainerProvider.RequestLifetime
Dim myClass As MyClass = scope.Resolve(Of IMyClass)(New TypedParameter(GetType(Integer), 123))

Also, having the public property at the top of my WebForm1.aspx needed to be removed, because that will auto resolve, meaning, if i try to "resolve" the object manually, it has already been automatically resolved by autofac (which is why i thought my code wasnt working initially), and has already instantiated the object with the empty constructor!

2: Using a Deligate Factory

the line Public Delegate Sub Factory(myID As integer) isnt correct, it should use a function for Autofac to automaticly set this up! so should be: Public Delegate Function Factory(myID As integer) as MyClass

In Global.asax, I just need to add this builder.RegisterType(Of MyClass)().InstancePerLifetimeScope() , because we require a parameter and using a factory, we cant append the .As(Of IMyClass)

Finally, our webform1.aspx.vb just needs this:

Dim cpa As IContainerProviderAccessor = (CType(HttpContext.Current.ApplicationInstance, IContainerProviderAccessor))
Dim scope As ILifetimeScope = cpa.ContainerProvider.RequestLifetime
Dim myClassFactory As MyClass.Factory = scope.Resolve(Of MyClass.Factory)
_myClass = myClassFactory.Invoke(123)


however, I tweaked that slightly to this:

Dim cpa As IContainerProviderAccessor = (CType(HttpContext.Current.ApplicationInstance, IContainerProviderAccessor))
Dim scope As ILifetimeScope = cpa.ContainerProvider.RequestLifetime
Dim myClass As MyClass = scope.Resolve(Of MyClass.Factory).Invoke(123)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM