Can I get information about the IIS7 virtual directory from Application_Start? - asp.net

I have 3 IIS7 virtual directories which point to the same physical directory. Each one has a unique host headers bound to it and each one runs in its own app pool. Ultimately, 3 instances of the same ASP.NET application.
In the Application_Start event handler of global.asax I would like to identify which instance of the application is running (to conditionally execute some code). Since the Request object is not available, I cannot interrogate the current URL so I would like to interrogate the binding information of the current virtual directory?
Since the host header binding is unique for each site, it would allow me to identify which application instance is starting up. Does anyone know how to do this or have a better suggestion?

When a request is made, and just prior to the HttpApplication instance being created, ASP.NET initializes core objects such as HttpContext, HttpRequest and HttpResponse which means they will exist when you get to the Application_Start event in Global.asax. Thus, in Application_Start, you can get the requesting url like so:
var url = this.Context.Request.Url;

Related

Owin.Security.OAuth don't fire ValidateClientRedirectUri

I made a web .net application in C#. I started from the ASP.NET Web application (.NET Framework) template project in Visual Studio.
I added the Owin.Security.OAuth library and I implemented the service provider in my code.
When I run the application with IIS Express it works well. When I try to run the application in the remote IIS server, when I try the login it fails on the authorization phase.
The application got 2 areas (AMSCetra and GestDrivMe) with their controllers and views, and a HomeController (the project default controller) with an Index api method that redirect to the specific areas index.
I tried to debug the difference between local and remote behaviour.
When i work in local IIS Express, the chain of requests to my application is a little different:
call Login method of my AccountController, that redirect to "/" after the account authentication and after getting roles
call OnAuthorization method of my AuthorizeAttribute (the AuthorizationContext's controller's request point to the area's file /AMScetra/AMSCetra)
call AuthorizeCore method of my AuthorizeAttribute (HttpContextBase parameter's request is for the same location of the point 2) and the user is Authenticated and "InRole"
call the specific area's controller Index api method (AMSCetraController.Index)
invoke the ValidateClientRedirectUri method of my AuthProvider (override of the OAuthAuthorizationServerProvider method). Here calls the context Validated method (the context's request is for the HomeController's Index - "https://localhost:44375/")
call Authorize method of my AccountController, that invoke the AuthenticationManager.SignIn(identity) method and returns an EmptyResult
call the HomeController Index (i don't now why) that redirect to the specific Area Index - "~/AMSCetra/AMSCetra/Index" (seems unuseful but in local it works)
call for a second time OnAuthorization method (request is for "/AMSCetra/AMSCetra/Index" as the previous redirection suggest)
call for a second time AuthorizationCore method (HttpContextBase parameter's request is for the same location of the point 8)
call for a second time the specific area's controller Index api method (AMSCetraController.Index)
I can't understand why the AMSCetraController Index is called two times, or why the application needs to call the HomeController Index after, but I can postpone 'cause it works well (in local IIS Express) and it happen only after the login.
But when I publish on the remote IIS, the calls chain skip point 5 (ValidateClientRedirectUri) and at point 6 (Authorize) the chains end, and a blank page is shown with the uri "http://XXX.XXX.XXX.XXX/Account/Authorize?client_id=web&response_type=token&state=".
I tried to debug the low level Owin library to understand the problem, but I don't know how debug a referenced DLL without PDB files. I tried to understand how the library works on the GitHub source code, but it's not the same.
Seems that is involved the Javascript's Knockout library, and a js method called Sammy, but as before I can't debug that source code, but only my code (indifferently in local or in remote).
I can't understand why IIS Express works well but remote IIS server don't, I already tried to force the MachineKey in my solution and in the remote IIS server, but it doesn't resolve.

Keep getting null reference error when setting session variables [duplicate]

I have an ASMX webservice hosted alongside my ASP.NET web app. Now, I need to get the users session into the Webservice. To test this I made this simple method:
[WebMethod(EnableSession = true)]
public string checkSession()
{
return HttpContext.Current.Session["userid"].ToString();
}
So, first I login to my web app, then in the browser goto my webservice and click "checkSession" on that auto generated test page. I have tested this on 3 computers. All 3 of those work fine with the webapp(so the sessions are being created etc), and 2 of those return the value of Session["userid"] on invoking the webmethod, however the last computer returns "Object reference not set to an instance of an object" because Session is null.
So, whats the difference between these computers and why can my ASP.NET app get the sessions on all computers but the webservice cant?
maybe it's too late, but have you tried this:
[WebMethod(EnableSession = true)]
public string checkSession()
{
return HttpContext.Current.Session.SessionID
}
SessionIDs are stored as cookies on the client's browser by default (Session State Overview). So check if that cookie is being created properly on that problem computer. Maybe cookies are disabled for some reason? In that case it would not be sending the SessionID to the server when you are hitting that web service.
Can you check how many worker processes is your application using? You can check it in your App pool settings in IIS.
If more than one worker process are being used then it is called to be running a web garden. If that is the case then in proc session will not be useful as this session is not shared among the worker processes. Have a look at http://www.west-wind.com/weblog/posts/2005/Apr/20/Why-you-shouldnt-use-InProc-Session-State-in-ASPNET
Have you got Session disabled in IIS, this would over rule .net.
Have a look at this http://technet.microsoft.com/en-us/library/cc732964(v=ws.10).aspx - it tells you how to disable session, but shows where to check the setting.
Thanks
Fran
By default web services are and should be stateless. However if you must use session information be sure to use the marker interfaces IReadOnlySessionState and IRequiresSessionState in order to access, use, or modify session state information in the webservice.
Web service by default wont support Session. You need to explicitly specify the parameter in web method attribute
These two things work for me
<add name="Session"
type="System.Web.SessionState.SessionStateModule"/> under
<httpModules>
enableSessionState="true" in <page> tag
A session object is accessible by:
var session = this.Session;
var contextSession = this.Context.Session;
best way to do this approach check before your session is not null and in the other side you
initialize the selected session with your value and then when and where web service working with httpcontext.current.session have value !
web services are stateless and best way is get value in web service instead of set or initialize session value

Cookieless ASP.Net sessions for static pages

I'm using ASP.Net cookieless sessions so that the session ID for the application is tracked by placing it in the URL via a 302 redirect, for example if the user were to access the below URL
http://yourserver/folder/default.aspx
They would then be redirect to a URL similar to the following which would then proceed to serve up the actual page content
http://yourserver/folder/(S(849799d1-7ec0-41dc-962d-a77e1b958b99))/default.aspx
The problem I have is that the entry point for the application is actually a static page (e.g. one with a .html extension), and ASP.Net is not issuing a session ID & redirecting the user for this page. This therefore means that links to ASP.Net hosted content (e.g. links, iframes etc...) each result in a new session ID being created for each of these links. I cannot easily change the pages extension for compatability reasons (although this does fix the problem).
How can I prompt ASP.Net to create a session for my page? I've tried adding an explicit handler mapping to ensure that the page is being handled by the ASP.Net modules, however this has no impact - while debugging I can see that a SessionIDManager instance is being created for this page (implying that the ASP.Net is already handling this page via the integrated pipeline regardless of my handler mapping), however ASP.Net is still not creating a session for this page.
I am using IIS 7, however this also needs to work on IIS 6 (with expicit handler mappings) and IIS 8.
I have discovered from experimentation and decompiling the ASP.Net source that the SessionStateModule decides whether or not to create a session for a request based on whether or not the IHttpHandler for the request implements IRequiresSessionState or IReadOnlySessionState. If neither of those are true then its all down to whether or not someone has used SetSessionStateBehavior to set the session state behaviour to either Required or ReadOnly.
By default the static file handler does not do any of these and so the session is not created for static files - to ensure that the session state behaviour is set for the static files that require session state I simply set the session state behaviour during the BeginRequest event for the application
// In Global.asax.cs
void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Default);
}
I'm sure there are better ways, but this worked for me.

Web Garden and Static Objects difficult to understand

I am in the process of investigating to convert our web application to the web farm. So I started with web garden, by converting the 'Maximum Worker Process = 3'. Following is the simplified version of my problem.
Following is my Static Object class.
public static class MyStaticObject
{
public static string MyProperty {get;set;}
}
Then on Page Load I initialized the Static Objects as follows -
MyStaticObject.MyProperty = "My Static Property";
Then using asp.net ajax [WebMethod] create the ajax method on my web page
[WebMethod()]
public static string getStaticProperty()
{
return MyStaticObject.MyProperty;
}
// Then I call this Ajax method using Javascript and set the return to the text box.
This test is not working as expected. Following are my assumptions and wrong outcome from the test.
I thought when we set virtual directory to be web garden, then each request to the virtual directory is handled by different process in web garden, so my next few request to the server, should return null as I have initialized the static objects for one working process. But even if I click the ajax button for 20 times in row (means 20 requests) even then the static objects return me value.
Am i right in assuming on restarting the IIS should kill all the static objects.
Static objects are not shared in web gardens/web farms.
I am surprised by the behaviour of IIS, static objects and web garden.
Is I am assuming wrong or my way of testing is wrong.
Thanks.
Your assumptions about the way static objects are managed in AppPools / web gardens is correct.
However, your assumption about the way that web requests are distributed is not. HTTP requests are round-robined by the http.sys driver to IIS worker processes only when a new TCP connection is established, not when a new request arrives. Since keepalives are enabled by default, even though you made 20 requests in a row, they probably were all served by the same IIS worker process.
You can have IIS disable keepalives for testing purposes from the HTTP Response Headers section in IIS Manager, under Set Common Headers. That should cause your browser to open a new connection for each request.
To test with keepalives enabled, you can use the Web Capacity Analysis Tool (WCAT), available with the IIS 6 Resource Kit, to generate a multi-threaded load that accesses both IIS processes in your web garden.

How do I get the host domain name in ASP .NET without using HttpContext.Current.Request?

I've got an ASP .Net application running on IIS7. I'm using the current url that the site is running under to set some static properties on a class in my application. To do this, I'm getting the domain name using this (insde the class's static constructor):
var host = HttpContext.Current.Request.Url.Host;
And it works fine on my dev machine (windows XP / Cassini). However, when I deploy to IIS7, I get an exception: "Request is not available in this context".
I'm guessing this is because I'm using this code in the static constructor of an object, which is getting executed in IIS before any requests come in; and Cassini doesn't trigger the static constructor until a request happens. Now, I didn't originally like the idea of pulling the domain name from the Request for this very reason, but it was the only place I found it =)
So, does anyone know of another place that I can get the host domain name? I'm assuming that ASP .Net has got to be aware of it at some level independent of HttpRequests, I just don't know how to access it.
The reason that the domain is in the request is...that's what's being asked for. For example these are a few stackexchange sites from http://www.stackexchangesites.com/:
http://community.ecoanswers.com
http://www.appqanda.com
http://www.irosetta.com/
If you ping them, you'll see they all point to the same IP/Web Server and be served by the same app (or multiple apps in this case, but the example holds if it was one big one)...but the application doesn't know which one until a host header comes in with the request asking the server for that site. Each request may be to a different domain...so the application doesn't know it.
If however it doesn't change, you could store it as an appSetting in the web.config.
Use global.asax or write a HttpModule and subscribe to start request events. You will have the request passed into your event handler.
Use this instead:
HttpRuntime.AppDomainAppVirtualPath
Or if you want the physical path:
HttpRuntime.AppDomainAppPath
For further reading:
http://weblogs.asp.net/reganschroder/archive/2008/07/25/iis7-integrated-mode-request-is-not-available-in-this-context-exception-in-application-start.aspx

Resources