Disposing Com object in ASP.net application - asp.net

I have a com dll built in .net and referred it as a interop.mycomlib.dll in my ASP.NET application. I initialize a class in the com object then call some functions and finally when the user signs off or closes the browser I release the com object.
Below is the code I am using. Initially, for the first user, the InitInstance() is called but when the user signs off the ExitInstance() of the com is not called.
If any other user signs on the InitInstance() is not called again because the same instance of com object is used for all the users. ExitInstance() is called only when an iisreset is performed or the w3wp process is terminated.
Is this the default behavior of how com interop works with asp.net, or is there something I am missing to do to completely dispose the com object?
public class ComFacade : IDisposable
{
public ComFacade()
{
myComObj_ = new MyCOMLib.MyClientClass();
}
..............................
public void Dispose()
{
Dispose(true);
myComObj_ = null;
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
try
{
Marshal.ReleaseComObject(myComObj_);
}
catch (Exception ex)
{
throw;
}
}
this.disposed = true;
}
}
}
Thanks

You don't mention what the scope of the variable containing the ComFacade instance is. If the variable is static then this would be the behavior I would expect.
I would suggest you understand the ASP.NET page lifecyle and the implications of that with variables of different scopes. Unless the COM reference is supposed to be a singleton then you will need to create a new instance each time the page loads and dispose of it as appropriate (probably when the page is rendered).
Update (based on comment)
Note: This answer applies to any object in .NET that you try to keep around longer that a single page request. Eventually all objects are disposed / garbage collected.
You mention that the object is created when the user logs in and disposed when they log off. The only way you could do this is to cache the object in something static to keep reference to it. Keep in mind that every time the user does something in their browser a request goes from the browser back to IIS/ASP.NET for processing and invokes a page life-cycle (over-simplification, but good enough). Each time the user does this the page may be handled by a different thread in the App Pool each time. If more than one user is interacting with the site then over a period of time the same thread may (and most likely will) get used by more than one user. In short this is why with ASP.NET/IIS you must be extremely cautious with using singletons / static members.
On a side note, my question would be why do you need a reference to the COM object for more than a single page request?

Related

How to get caller caller IP address in Application_Start

How to get caller IP addres in ASP.NET MVC4 Global.asax.cs Application_Start event ?
HttpContext.Current.Request object is not available there.
Thread.CurrentPrincipal.Identity exists.
I want to log user name and IP address which were used to start application.
MVC4 application runs in Windows and in Mono
As you can see by the ASP.NET Lifecycle on MSDN, the Application_Start event not only happens long before the AcquireRequestState event where the request object is built, it is also done out of band with the request lifecycle altogether. In other words, Application_Start occurs only once when the application starts or when the application pool recycles, not once per request.
So, the answer to your question is simply that you can't do that (unless of course you set a static variable in the Application_Start event and use either Application_BeginRequest as in Darin's answer or an MVC filter to actually do the logging).
But MVC includes authorization filters and action filters which are meant for implementing cross-cutting concerns such as logging and/or auditing of the current user's IP address. Authorization and action filters do not run until after the request object has been created.
The HttpContext is not available when the application starts. You could achieve that in the BeginRequest method in your global.asax:
private static bool initialized = false;
private static object syncRoot = new object();
protected void Application_BeginRequest()
{
if (!initialized)
{
lock (syncRoot)
{
if (!initialized)
{
// do your stuff with the user IP getting from the current context
initialized = true;
}
}
}
}

Asp.net session never expires when using SignalR and transport mode long polling

We have a web application that uses SignalR for its notification mechanism.The problem is when we are browsing our web application using IE ,SignalR uses Long Polling as its transport type thus sends back requests to our web server therefore Session never expires no matter how long the browser is idle.
We were thinking that maybe we could catch the requests in Global.asax and see if they were from SingalR and set the session timeout to the remaining time (Which I don't think it's a straightforward solution).
Is there any other solution the we are missing ?
The workaround I am currently using is an IHttpModule to check if the request is a Signalr request, if so remove the authentication cookie, this will prevent the ASP.net session timeout from being reset, so if your Session Timeout is 20min and the only requests are Signalr the users session will still timeout and the user will have to login again.
public class SignalRCookieBypassModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.PreSendRequestHeaders += OnPreSendRequestHeaders;
}
private bool IsSignalrRequest(string path)
{
return path.IndexOf("/signalr/", StringComparison.OrdinalIgnoreCase) > -1;
}
protected void OnPreSendRequestHeaders(object sender, EventArgs e)
{
var httpContext = ((HttpApplication)sender).Context;
if (IsSignalrRequest(httpContext.Request.Path))
{
// Remove auth cooke to avoid sliding expiration renew
httpContext.Response.Cookies.Remove(DefaultAuthenticationTypes.ApplicationCookie);
}
}
public void Dispose()
{
}
}
I feel this is a real hack solution so would love so other ideas to prevent session timeout renew when data is pushed to the client from the server, or a when javascript client polls an endpoint for data.
If you take a look at the description of the SignalR protocol I wrote a while ago you will find this:
» ping – pings the server
...
Remarks: The ping request is not really a “connection management request”. The sole purpose of this request is to keep the ASP.NET session alive. It is only sent by the the JavaScript client.
So, I guess the ping request is doing its job.
I here post #Simon Mourier's commented solution, with his approval, as a CW answer, as I find the suggested approach the most appropriate and less intrusive, as it just disables the Session for SignalR requests.
A positive side effect is that the request will be processed faster as the Session object doesn't need to be initiated and loaded.
It still uses a IHttpModule for the work, and the preferable place is likely the AcquireRequestState event (not personally tested yet though), or at an event raised earlier, before making use of the Session object.
Do note using this approach that one might need to test that the Session object is available before access any of its members or stored objects.
public class SignalRSessionBypassModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.AcquireRequestState += OnAcquireRequestState;
}
private bool IsSignalrRequest(string path)
{
return path.IndexOf("/signalr/", StringComparison.OrdinalIgnoreCase) > -1;
}
protected void AcquireRequestState(object sender, EventArgs e)
{
var httpContext = ((HttpApplication)sender).Context;
if (IsSignalrRequest(httpContext.Request.Path))
{
// Run request with Session disabled
httpContext.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Disabled);
}
}
public void Dispose()
{
}
}
Here is another completely different approach, simple, yet quite efficient.
Instead of relying on Session/Auth cookies to decide whether a user has timed out, use the Cache object. This have more or less no side effects and work just like if the user simply logged out.
By simply add this small snippet somewhere in the beginning of your web app code, where of course SignalR don't go, you will be able to check if the cache item is there and reinitiate it (with the same expiration time as the Session timeout is set), and if not, just do a logout and remove cookies/session variables.
if (Request.IsAuthenticated) {
if (Cache[Context.User.Identity.Name] == null) {
// Call you logout method here...,
// or just:
// - Sign out from auth;
// - Delete auth cookie
// - Remove all session vars
} else {
// Reinitiate the cache item
Cache.Insert(Context.User.Identity.Name,
"a to you usable value",
null,
DateTime.Now.AddMinutes(Session.Timeout),
Cache.NoSlidingExpiration,
CacheItemPriority.Default,
null
);
}
And within your user login method, you just add this, to create the cache item for the first time
// Insert the cache item
Cache.Insert(Context.User.Identity.Name,
"a to you usable value",
null,
DateTime.Now.AddMinutes(Session.Timeout),
Cache.NoSlidingExpiration,
CacheItemPriority.Default,
null
);
It's more stable and maintainable -in my view- to have your own "session like timeout" . Set your .NET session timeout to infinity since you'll not be using it and then create a global JavaScript counter (in your layout or master page) to track the time passing while the browser is idle (obviously setTimeout or setInterval every few seconds would do the trick). Make sure to have the counter reset on every web request (that should happen automatically since all JavaScript variables would reset). In case you have pages that depend on web services or Web API, make sure to reset your global JavaScript counter on every call. If the counter reaches your desired timeout without being reset, that means that the session is expired and you can logout the user. With this approach you'll have full control over the session lifetime which enables you to create a logout timer popup to warn the user that the session is about to expire. SignalR would perfectly fit with this approach since the JavaScript timer would keep ticking.

Regarding the usage of IRequiresSessionState

please tell me why IHttpHandler need to implement IRequiresSessionState. without implementing it we can not read/write anything in session variable?
can't we access directly HttpContext.Current.session like this way.
please explain.......thanks
public class MyHttpHandler : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
var MyValue = context.Session["MyKey"] as String;
MyValue = "Hello World";
context.Session["MyKey"] = MyValue;
}
public bool IsReusable
{
get { return true; }
}
}
The session state is not a native part of the HTTP infrastructure. This means that the request will need to serialize/load the session information (either from memory or database or another server) for requests that need access to session and save it back when done.
HttpHandler is a the process (frequently referred to as the "endpoint") that runs in response to a request made to ASP.NET http runtime. It is used to handle a particular type of object/class/resource as you define it. If processing of that resource does not need access to session, that particular request does not need to go through the loading/saving of session data unnecessarily. So, by default, session is not available for HTTPhandlers, unless it is a predefined handler like Page handler.
To successfully resolve any call to the Session object, the runtime environment must add the session state to the call context of the request being processed, which is IRequireSessionState in this case.
Check out this msdn link for more details.
To answer your question, no, if you dont implement the IRequireSessionState, you will not have access to the session objects in your handler class due to the above mentioned facts.
If you do not implement this interface you should not be able to successfully use the session object. You are supposed to use this interface if you want access to the session, regardless of how you access it.
It shouldn't work without it. If it does, its a fluke and don't rely on it.
The ASP.NET SessionStateModule will not populate the context's session properties unless the handler is marked with the IRequiresSessionState interface.

Catch IIS level error to handle in ASP.NET

I am developing an ASP.NET site with C# on IIS 7, but I hope for an answer that will apply to IIS 6 as well. Part of this site is the ability to upload up to 5 images at a time. I have a nice algorithm to resize the image that is uploaded to my optimal size and ratio.
So the only real size limitation I have is during the initial upload. I have modified my web.config to raise the packet limit from 4MB to 32MB. For the most part this takes care of my issues.
My question comes in the rare cases that a user tries to load more than my limit. I can raise the limit, but there is always a chance a user can find 5 files that are bigger. If a user selects files that are bigger, my try/catch block does not handle the error. The error is coming from IIS.
So how can I catch the error in C# code where I can make modifications to my ASP.NET interface to inform the user to select smaller files instead of them seeing a nasty error screen?
You can get access to the exception when the request length is exceeded. Use an HttpModule, and add a handler for the Error event.
The exception is of type: System.Web.HttpUnhandledException (with an InnerException of type: System.Web.HttpException).
To catch this exception, add this to your web.config:
<httpModules>
<add name="ErrorHttpModule" type="ErrorHttpModule"/>
</httpModules>
And add this class to your App_Code folder:
public class ErrorHttpModule : IHttpModule
{
private HttpApplication _context;
public ErrorHttpModule() {
}
private void ErrorHandler(Object sender, EventArgs e)
{
Exception ex = _context.Server.GetLastError();
//You can also call this to clear the error
//_context.Server.ClearError();
}
#region IHttpModule Members
public void Init(HttpApplication context)
{
_context = context;
_context.Error += new EventHandler(ErrorHandler);
}
public void Dispose()
{
}
#endregion
}
If you're using the traditional asp:FileUpload control, then there isn't a way to check the size of the files before. However, you can use a Flash or Silverlight approach. One option that has been suggested to me is Uploadify
I don't know for sure that this will work, but at least in IIS 7 you might try catching the Error event in an HttpModule that's configured to run for static files. From there, you could redirect to an appropriate error page.
You can catch these in Global (the global.asax.cs file). Add an Application_Error handler - you will get an HttpUnhandledException. Its InnerException will be an HttpException with the message "Maximum request length exceeded".
However, these errors are handled before your page code ever gets loaded or executed, so there is no way for your page to catch the exception or to know it ever happened. After catching this exception, you could stick a message in your Session for later display. You could also call response.Redirect from Global to display a new page, or redisplay the original with the error message from Session.

How to provide a Session/Host object for use in both a windows and web application?

I have a web application that makes heavy use of the Session state to store information about the current user, their personal settings, record their session history and so on.
I have found myself retrieving this session information in my business layer, like so:
((UserSession)HttpContext.Current.Session["UserSession"]).User.Info
This poses a problem - at some point in the future my application will have a Windows client which obviously cannot reference the web Session state. So I need a host or customized session class that I can reference in my business layer that is agnostic of whether the application is running on the web or desktop. Something like:
IHost.User.Info
Behind the scenes, the web implementation will obviously utilize the Session state to store information, but I need to hide this away from my business layer. Has anyone solved this problem or got any practival advice on how best to approach this?
Help appreciated.
Assuming that the business layer is a separate DLL, I would never add a reference to System.Web and in consequence I would never use the Session object directly. This would lead to a different design of the business layer and of the exposed interfaces to a client (either web or winforms).
That said, as a quick workaround I would suggest to write a wrapper class in your business layer that hides the Session object from your code. Your calls from code will be something like this:
((UserSession) DualContext.Current["UserSession"]).User.Info
and the wrapper implementation will be something like this (not completed and tested):
public class DualContext
{
private Dictionary<string, object> winFormsSession = new Dictionary<string, object>();
private static readonly DualContext instance = new DualContext();
public static DualContext Current
{
get { return instance; }
}
public object this[string key]
{
get
{
if (HttpContext.Current != null)
return HttpContext.Current.Session[key];
else
return winFormsSession[key];
}
set
{
if (HttpContext.Current != null)
HttpContext.Current.Session[key] = value;
else
winFormsSession[key] = value;
}
}
}
It would take some re-architecting, but if you switch from using Session State to User Profiles you could then use Client Application Services to share the information.
http://msdn.microsoft.com/en-us/library/bb384297.aspx
I guess you need to create a webservice or RESTfull service. The service will return an XML file representing your user information. You will be able to invoke the service wither from you windows or web application.

Resources