ASP.NET COM+ Dispose Exception - asp.net

our ASP.NET application is using COM+ to connect to Database
we have this structure:
A Base Class :
Imports System.EnterpriseServices
Public Class Base Inherits ServicedComponent
A Child Class:
Public Class Member Inherits Base
'Propreties
.
.
.
'Methods
Public Sub SetMember(ByVal SelectedQueue As String)
...
End Sub
In a Aspx page, we search for a member and set details:
Dim newMember As Member = New Member
newMember.SetMember(MemberNumber)
Session("SelectedMember") = newMember
We then dispose newMember:
If Not newMember Is Nothing Then
newMember.Dispose()
End If
but whenver we access the session we got an exception:
If Not Session("SelectedMember") Is Nothing Then
'Something
Else
'Something else
End If
the exception is :
Cannot access a disposed object. Object name: 'ServicedComponent'.
How can I dispose the object but keep my session valid?

I can see what you're doing wrong, but can't be clear on what would be right. Your logic as stated is:
Obtain object.
Store object.
Clean-up object, rendering it useless.
Retrieve object.
Use object.
Having 3 before 5 makes no sense.
If the object is quick to obtain, you should just do so on every page. (Often people over-estimate the cost of this).
If the object is slow to obtain, and it makes sense to store for a long term, then it shouldn't need to be cleaned-up. What is Dispose() actually doing here? With it obtaining and releasing resources used by members as needed.
I suspect that the first is the one to go for here, but that's mostly a guess.
I'd also be concerned when you talk about the database, does your object hold a database connection? If so, and pooling is available, then you should be releasing those connections as fast as possible, rather than holding onto them.

Related

Why is my global variable not being initialized?

I'm trying to create a singleton object in my ASP.NET web app. The definition is like this:
Public Module Providers
Public AppConnectionStringProvider As IConnectionStringProvider
End Module
And I'm setting this in Global.asax like this:
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
...
'create a default connection string provider
AppConnectionStringProvider = New MyConnectionStringProvider
....
End Sub
This works fine, but sometimes I see errors in my log file that are caused, ultimately, by using AppConnectionStringProvider when it is Nothing/null. I thought that by initializing it in Application_Start I would guarantee that this variable is always non-null, but there seem to be some circumstances where this is not so. What could cause this? I'm thinking of threading issues, but I can't see what they would be.
Edit: Below is the stack trace. Roughly, it's a simple request for the site home page:
Exception of type 'System.Web.HttpUnhandledException' was thrown.
System.Web.HttpApplication.ExecuteStep
System.Web.HttpApplication.CallHandlerExecutionStep
System.Web.HttpApplication.IExecutionStep.Execute
ASP.default_aspx.ProcessRequest
System.Web.UI.Page.ProcessRequest
System.Web.UI.Page.ProcessRequest
System.Web.UI.Page.ProcessRequest
System.Web.UI.Page.ProcessRequestMain
System.Web.UI.Page.HandleError
Object reference not set to an instance of an object.
System.Web.UI.Page.ProcessRequestMain
System.Web.UI.Control.LoadRecursive
MyApp.Default.Page_Load.21[Default.aspx.vb]
...
MyApp.SomeModule..ctor.6[Utilities.vb]
MyApp.get_ConnectionString.70[Connections.vb]
And in that last method, at that line of code, it's trying to use the object that was initialized in Application_Start, but it seems to be null, when it should have a value.
If your singleton object should dispose at sessions end then add your object to a session variable. Session[MyConnectionStringProvider] = New MyConnectionStringProvider(). alternatively if you'd like your singleton object to be alive for the application and share it with all users then add it to an application variable. Application[MyConnectionStringProvider] = New MyConnectionStringProvider. This way your object will not be null and available for all requests. I hope this helps.
The problem turned out to be a very subtle sequencing issue. I had a class that referenced the AppConnectionStringProvider object, but the code that set the provider object had a constructor that implicitly created an object that created another object that created another object that depended on the provider. So even though it looked like the object could not be null, the code that set it depended on it not being null. I had to refactor a bit to disentangle these dependencies, but now it's working fine. Thanks for everyone's comments.

Any issues using HTTPContext outside of web project

We have a web application with access to Business logic and data access in separate projects.
The way it is designed, key values is never passed to data access layer or business logic. Instead business layer has a class which contains public read only property through which DAL layer access the values.
Business logic layer is in a different project. Web project gets the reference.
Business logic layer has this class : Public NotInheritable Class clsUserProfile
Which has this property:
Public ReadOnly Property AgencyCode() As Integer
Get
If clsAppInfo.IsWebApplication Then
If (HttpContext.Current.Session(_AgencyCodeKey) Is Nothing) Then
Return 0
Else
Return HttpContext.Current.Session(_AgencyCodeKey)
End If
Else
Return AgencyCodeWIN
End If
End Get
End Property
/** For windows Agency Code is declared as shared
Public Shared Property AgencyCodeWIN() As Integer
Get
Return _AgencyCodeWIN
End Get
Set(ByVal value As Integer)
_AgencyCodeWIN = value
End Set
End Property
/****
To determine whether it is a web app or not .......
Public Shared ReadOnly Property IsWebApplication() As Boolean
Get
If AppCodeWIN IsNot String.Empty Then
'Desk top App is required to pass AppInfo
Return False
Else
'Web App is default
Return True
End If
End Get
End Property
Will the data will be overwritten when multiple users login.
Many people say that it is not advisable, but cannot find any provable reason as to why it is not recommended?
If anybody can give clear reasons that would be great.
Thanks,
sandy .
Will the data will be overwritten when multiple users login
No
Many people say that it is not advisable, but cannot find any provable reason as to why it is not recommended?
In this context, adding a third running mode would be a pain.
In fact, your class clsUserProfile should not be aware of your application running mode (webapp or desktop). It even should not know about HttpContext and Session or choose between two running modes, just to get an AgencyCode.
clsUserProfile should be a plain C# object. The running mode should be handled at a higher level in your app.

How to get a public variable (in a Module) to NOT share value between users

I'm working in an ASP.NET (VB) Web Application with Windows/Active Directory Authentication
I am using a module so that I can call public subroutines and functions, and reference variables, without having to instantiate a new object to access them on each page.
Within that module, I have some Public variables that I am using in multiple pages throughout the web application. I've recently realized that the values for these public variables in the module get shared between all users.
THE GOAL:
I want the value for these global variables to be specific to a single user and not shared between all sessions, and I do not want to have to instantiate a new object/class on every page that uses the variable.
THE CATCH:
I don't want to store the value in a client-side variable such as a cookie or session. I want the value to be stored on the SERVER but specific to each client/user.
The only thing I can think to do is setup a global collection/dictionary and store the variables with the authenticated user names, but then I need to have specific functions to get and set the values. While this will work, it requires all the references to these variables on all pages in the application to be updated.
EXAMPLE OF THE PROBLEM:
The below code shows how I am creating the public variable within the module and how the value is being set from one page and used on another. I'd like to continue to use this variable in the same way and share it's value between pages, but the value of the variable needs to NOT be shared between users.
-- MODULE.VB --
Public Module MyMod
Public myVariable as String = ""
End Module
-- MAINPAGE.VB --
Partial Class _Default
Sub Page_Load() Handles MyBase.Load()
myVariable = "HELLO WORLD"
End Sub
End Class
-- NEXTPAGE.VB --
Partial Class _Default
Sub Page_Load() Handles MyBase.Load()
Response.Write(myVariable)
End Sub
End Class
There are a LOT of pages in this application that will need to be manually updated if I have to use my userID-indexed collection solution, so I'm hoping there is a way to simply scope these variables differently or a way to disable the sharing between sessions.
Thanks in advance!
You didn't indicate whether or not the variables need to be persisted across page round trips or whether they are just used within each page's lifecycle.
If they are not persisted across pages, then perhaps the easiest solution is to have all of your pages inherit from a based page class and then move the values from the module into the base page. This way you won't have to change any variable references, only page inheritance.
If you do want to persist the values, completing the above changes makes it much easier to implement. You can then turn the member variables on the base page into properties and embed your user specific caching and fetching in the getter and setter.
For example, instead of:
Public MyVariable As String = ""
You would have something like:
Public Property MyVariable As String
Get
Return GlobalMyVariableCache(UserNameKey)
End Get
Set (Value As String)
GlobalMyVariableCache(UserNameKey) = Value
End Set
End Property
The problem you are coming across is a very common one in web programming. A Module's members are static - meaning there is one instance of them across the entire AppDomain of your application. Every user that accesses these will get the same object - you have already learned this.
Your options are exactly what you described. You could possibly replace the public variable in your module with a property whose getter you write to access a user-specific field in a dictionary (please remember thread safety when writing this getter code).
The much easier solution would be to use the Session. Session values are stored server-side and are user specific. The only thing that get's sent client side is the session key, and if you are using .Net authentication, this is likely already getting sent.
Good luck,

autofac, ASP.NET integration, and Dispose

Autofac newbie here, but I like what I see so far. I'm trying to take advantage of request-lifetime of my resolved objects and I'm having trouble confirming that a dispose is actually happening after a request is done.
I have a disposable object that I get at the start of a page request and dispose at the end. I'm using autofac to get an instance of the object now and I wanted to see if autofac would do the disposing for me.
i've instrumented the Dispose() method on the object in question, and i can see it 'fire' when my page does the lifetime management. I see no evidence when I don't dispose myself but let autofac do it.
I'm using these instructions to get thigns configured, including the web.config and global.asax changes. I am able to instantiate the object just fine but I can't tell if it's really being disposed. Is there another step?
Whether you dispose the object manually within the page or let the Autofac module do it, there will be a difference in when your object is disposed in respect to the request lifecycle. The Autofac ContainerDisposalModule will not dispose the Request container, and with it your object, until the HttpApplication.EndRequest is fired, which is at the very end of the request lifecycle.
Depending on how you are tracing the call to your objects Dispose method, there could be a possibility that you don't see the output. How are you instrumenting your Dispose method?
Repeat of answer from your re-post:
Most of the time this happens (in any
IoC container) you'll find that one
component along a chain of
dependencies is a singleton.
E.g.
A -> B -> C
If A is 'factory', B is 'singleton'
and C is 'factory', then resolving A
will get a reference to the singleton
B, which will always reference the
same C.
In order for a new C to get created
every time you resolve A, B must also
be 'factory'.
I figured it out!
I was asking the WRONG container for the object instance - I was asking the application-container for the object and not the request-container.
D'oh!
Dispose is nothing more than an interface that allows you to define a "Dispose" method. The most common use for requiring a disposable class is if there are resources in that class that should be freed explicitly (such as a windows resource handle). For the most part the IDisposable interface is not required, as the garbage collector is extremely powerful and will do a much better job at managing memory. However, obviously there are plenty of cases where handles must be freed immediately, which brings me on to the next point, implementation of IDisposable.
What NOT to do:
var myClass = MyDisposableClass();
// do stuff with myClass
myClass.Dispose();
Proper usage:
using (var myClass = MyDisposableClass())
{
// do stuff with myClass
}
The compiler will effectively build the same as the following:
MyDisposableClass myClass = MyDisposableClass();
try
{
// do stuff with myClass
}
finally
{
myClass.Dispose();
}
The important distinction being that no matter what happens, you know your Dispose will get called. In addition, you can tie a destructor (which if exists, is called by the Garbage Collector) which you can then tie in to call your Dispose method; but if you need to do this for whatever reason be sure to not free the same resource twice (set your pointers to null after releasing).

Using IHttpModule Over Global.asax

I've been given the thrilling task of re-writing our exception handling system. Whilst I will state that handling exceptions from an application-wide point of view isn't something we want, typically it's unavoidable when our team are understaffed for the sheer amount of work we need to push out the door, so please, no flaming the globalised solution to exception handling here :)
I've had a good hunt to see what common solutions exist. At the moment we use Global.asax with the Application_Error event to do Server.GetLastError() which is placed in Session state then a redirect is called to another page where the session data is then retrieved and output in a human readable format. The redirect also calls a sproc which will carefully audit the error information which is a) e-mailed to the developers and b) viewed from a web page only viewable by developers.
The new way I've seen of doing things is using the IHttpModule interface using a class in App_Code to do something along these lines (this is my quick implementation)
Imports Microsoft.VisualBasic
Public Class ErrorModule : Implements IHttpModule
Public Sub Dispose() Implements System.Web.IHttpModule.Dispose
' Not used
End Sub
Public Sub Init(ByVal context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init
AddHandler context.Error, AddressOf context_Error
End Sub
Public Sub context_Error(ByVal sender As Object, ByVal e As EventArgs)
Dim ex As Exception = HttpContext.Current.Server.GetLastError
' do something with the error
' call the stored procedure
' redirect the user to the error page
HttpContext.Current.Server.ClearError()
HttpContext.Current.Response.Redirect("index.htm")
End Sub
End Class
My question is, what is the benefit of this solution over using Global.asax events? Additionally, what is the best way to hand the data to an error page?
EDIT: The code above does work by the way ;)
EDIT: Also, how does the HttpModule work behind the scenes? Does it just register the Error event to that particular function on application start?
UPDATE:
Upon much further investigation it seems grabbing session data is really, really messy when it comes to using IHttpModule interface. I don't think MS have matured HttpModule enough for it to be used in our particular scenario - until there are events specific to session data it's too dangerous for us to use.
Using a module has the advantage of being easily removable, all you need to do to disable it is to remove it from <httpModules> in your config.
As far as your data goes, try going with Server.Transfer or Server.RewritePath - that will keep all the current data (including the last server error).
If for some reason it clears the last error, you can save the error to HttpContext.Items before the transfer/rewrite and then retrieve it afterwards.
Edit: In response to your edit, an IHttpModule attaches to any appropriate events in it's IHttpModule.Init implementation.
HttpModule basically does the same thing as Global.asax. It's designed as a more reusable and self-contained module for event handling.

Resources