I have an ASP.NET 4.5 MVC app. I don't want to set RAMMFAR (runAllManagedModulesForAllRequests) because that would needlessly send requests for static resources through the ASP.NET pipeline; however I do want all requests which begin with the path /Download/ to run through the ASP.NET routing pipeline, regardless of extension. This way I can route them to a Controller and serve dynamically generated resources.
How can this be done? I do not have access to IIS settings but hopefully there is a way to do this through web.config.
The RAMMFAR setting is per application. You'd have to create a separate IIS applications if you want different parts of the site to have different settings, but unfortunately you state this is not an option for you.
I two have two side notes though:
Are you sure you even need RAMMFAR? I think that when using IIS 7.5 and newer it's very rarely needed because IIS and ASP.NET can pretty much handle managed/native requests correctly.
Have you identified this as an actual problem to always have it enabled? Undoubtedly RAMMFAR will make things slower, but the question is whether it's causing a measurable effect in your app. Even if a static file does go through some managed code, the final processing of the file is handled back in native code. So there's a bit of extra work to go "through" the ASP.NET managed pipeline, but once that's done it's back to native IIS/Windows code.
It is surprising to see that this hasn't been answered in Stack Overflow for long time.
As you've mentioned - runAllManagedModulesForAllRequests is not required when you just need to capture all requests for a particular path in your site.
You can specify a path pattern which should be send to MVC handlers as shown below
<add name="DynamicDownloadHandler" path="/download/*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
Above pattern will capture both extensionless and paths with extension.
A sample implementation for serving dynamic images in MVC is linked here.
Related
I'm completing a feature that was started by a previous developer. I notice that he's loading settings from the db in the Global.asax Application_Start method and puts the settings into HttpContext.Current.Application["SettingName"].
In development this works fine on my machine. If I'm not mistaken though this looks like in production it's going to load the data once when the application starts for the first user but settings will not be available to the application for any subsequent user.
Can someone please confirm or deny my suspicions?
The HttpContext.Current.Application["SettingName"] is a static property. It will be available to the next subsequent users as well. But you can not change it that easy, especial if you use web garden.
You can read more details here: Using static variables instead of Application state in ASP.NET
I do not know how the design is, but you can use a simple static dictionary for the same... of direct read from the database your parameters, or from web.config.
I generally wouldn't touch the HttpContext in Application_Start. In fact, I don't think IIS's Integrated Pipeline will even let you do that.
With integrated pipeline, Application_Start could get fired before any requests even hit the server, such as IIS 8's Application Initialization.
I recommend that you place the settings in the web.config file and use the ConfigurationManager object to read those settings. This is a lot simpler, as there is no need to store them in the HttpContext.
e.g.
<configuration>
<appSettings>
<add key="SettingName" value="SettingValue" />
</appSettings>
</configuration>
Doing this means the settings will be available to the entire ASP.NET application - there is no need to store them in the HttpContext.
There is a caveat that when you update the web.config file the application pool for the ASP.NET site will be recycled. But the consequences of this all depend on what that site is doing with, for example, session state and caching. Recylcing the application pool will reset those, but that's for another question.....
EDIT:
Based on the comments, it sounds like session state will help you here. With session state, you can store the user specific settings so that they do not interfere with other users.
In our production environment (only) an excessive number of sessions seem to be getting created from an ASP.NET web application. The eye-catching symptom was that the ASPStateTempSessions table was generating ~25K records per hour (when google analytics indicates less than 500 unique users on this site per hour). This is resulting in a high number of waiting tasks which is then causing slowdowns and issues across other databases and therefore impeding site performance. The vast majority of the sessions don't appear to have any significant amount of data in them.
Any thoughts on what could be causing the phantom sessions? I was originally thinking that image requests and the like were somehow causing new sessions, but that doesn't seem to be sufficient to explain such a high multiplier. Is that even reasonable? Should I explore that avenue further? Why would that not have the same symptoms in my development environment?
Thanks!
Environment Details (I can provide more details, I'm just not sure what else is relevant):
IIS 7
SQL Server 2008
Session mode is SQLServer:
<sessionState mode="SQLServer" sqlConnectionString="[Connection String]" allowCustomSqlDatabase="true" cookieless="false" timeout="120" cookieName="XYZ_SessionId" />
I agree that the likely culprit is flat files running the SessionStateModule, especially if you are using MVC instead of webforms. The reason is that in order to support extensionless URL routing, MVC adds the following tag into your web.config:
<modules runAllManagedModulesForAllRequests="true">
...
The attribute does pretty much what its name implies, which will cause you to experience overhead if you host images off of the same website in IIS. If you don't use extensionless URLs, you can consider turning off that attribute, or you can try moving images to a CDN like akamai or AWS cloudfront.
Alternatively you could look for a SessionStateModule alternative, there are some that exist that might provider alternate behavior. You could even roll your own by inheriting System.Web.SessionState.SessionStateStoreProviderBase, there is an MSDN article on doing that: custom session provider tutorial. If you do that last one, I recently found ResetItemTimeout to be the most commonly run item on every request by the default SessionState module.
Lastly, the reason I think that the expansion you are experiencing is being caused by this is the fact that SessionState module is synchronous by default. This means a browser requesting both imageA.jpg and imageB.jpg will receive imageA then imageB only after imageA has released the Session lock. This is much slower than the default behavior of a webserver, which is to serve up both on separate threads.
Another way to troubleshoot, if this does not solve it, is to look at the current requests going through IIS7. To do that, go to the top level server name in the left hand side of IIS manager and click on Worker Processes. It should list your website process, double-click that and it will show all current requests. You should see a ton of image files in there.
I was under the impression that static files (CSS, images, #font-face files, etc) bypassed ASP.NET completely, and were served directly by IIS.
However, my BeginRequest event handler is being called for every HTTP request, including those for static files. This concerns me because I'm creating an Entity Framework data context to be used for the lifetime of each request in that event handler. I don't want to create those contexts if they're never going to be used.
I'm using IIS 7 on Windows 7 Ultimate with no special handler mappings defined. Do I have it wrong? Should these events be firing?
I believe a default ASP.NET MVC site has this set in the web.config.
<modules runAllManagedModulesForAllRequests="true" />
This means every .NET module will be loaded for every IIS request. This is required for ASP.NET MVC to handle extension-less routing. It's essentially a wildcard mapping that you would write in IIS that would match everything and route it to ASP.NET that lives in the web.config.
Read more here, including a way to disable the behavior if you aren't using .NET 4.0. It is nasty, but it's the cleanest solution for sites that can't deal with the overhead of having static files served by asp.net.
BeginRequest will be triggered for all requests (including static content) if:
You're using Visual Studio's development web server.
You've configured IIS to do so.
Please take a look at:
http://forums.asp.net/t/1220664.aspx
In addition to fixing the issue for your static files, you could use Lazy initialization Lazy<T> for your ObjectContext: http://msdn.microsoft.com/en-us/library/dd997286.aspx
The integrated mode in IIS 7 works differently than it was before.
You could switch to classic mode if desired.
Alternatively you can define your custom route handler and do the context initialization there. That way it's only done for specific routes.
Our customer has a requirement to extend the functionality of their existing large government project. It is an ASP.NET 3.5 (recently upgraded from 2.0) project.
The existing solution is quite a behemoth that is almost unmaintainable so they have decided that they want to provide the new functionality by hosting it on another website that is shown within the existing website.
As to how this is best to be done I'm not quite sure right now and if there is any security issues preventing it or that need to be considered.
Essentially the user would log on to the existing web site as normal and when cliicking on a certain link the page would load as normal with some kind of frame or control that has within it the contents of the page from the other site. IE. They do not want to simply redirect to the other site they want to show it embedded within the current one such that the existing menus etc are still available.
I believe if information needed to be passed to the embedded page it would be done using query strings as I'm not sure if there is even another way to accomplish this.
Can anyone give me some pointers on where to start at looking to implement this or any potential pitfalls I should be aware of.
Thanks
if the 2 sites are hosted from the same network (low latency between them) you could use state server for session management. that way, when you authenticate on one site, you will also be authenticated on the other, and share user state across them.
its pretty simple, in your web config of each web server you'd point to the state server (which could be located on one of the web servers)
<configuration>
<system.web>
<sessionState mode="StateServer"
stateConnectionString="192.168.1.103:42424"
/>
</system.web>
</configuration>
http://en.csharp-online.net/ASP.NET_State_Management%E2%80%94Storing_Session_State_out_of_Process
create a virtual directory under the primary domain. If your domain is www.mydomain.com then create a virtual directory www.mydomain.com/site and port the new website application under /site virtual directory. This was linking should become very much relavant. With this the virtual-directory application will also retain all domain cookies set by primary domain.
I would suggest to make the second website look exactly like the first one or at least use the same MasterPage, so you can redirect from one site to another without any visual difference.
If your site needs authentication, consider that you would need to do something to prevent the user to log in twice, an option could be to send an encrypted token to the second site.
All of this if you are forced to have a second site, if not just use a virtual directory
You could use something like UFrame. I've used it a couple of times and seems to do quite a good job with it...
"goodness of UpdatePanel and IFRAME combined"
http://www.codeproject.com/KB/aspnet/uframe.aspx
I would use an iFrame to embed that website in within your existing application. Just set the "src" attribute and pass in any query string parameters the other site needs to render correctly.
You can still pass in sensitive data in the query string, however it would make sure to encrypt it before sending it in.
I know it is not the most elegant solution, but it gets the job done. And from the description of the existing app, it doesn't seem like your customer cares for "elegance" :)
Hope this helps
Let's say I have the following in a web.config:
<allow roles="Developers" />
<deny users="*"/>
This locks down access on .aspx, .asmx, and other .NET file types, but it's still allowing unauthorized users to open static files like image.jpg. I understand why the web.config isn't asked for authorization information when someone asks for image.jpg (it's not a .NET type, and IIS can bypass it), but how can I lock down a whole application?
Advice I've found online includes:
create a <location> entry for the directory in question and IIS / .NET will pick it up. (It doesn't seem to.)
you need to write your own ISAPI filter and map all sensitive files' extensions to that.
you don't need to write your own ISAPI filter - just mapping the extensions to aspnet_isapi.dll will do it.
you don't need to edit IIS at all, just create an httpHandler entry in the web.config for your extensions. (I'd really rather not try to do this for every extension in the application.)
None of this works quite as easily as I remember it being in Apache. What's the simplest thing that might work to ask a visitor for a password and not serve any files (static or not) to any user that doesn't have it?
Enable wild card mapping for IIS 6. This will send all files through the ASP.NET pipeline, guarantee form auth happens for all files. It will degrade performance (dunno how much).
For IIS 5, um, upgrade to IIS 6.
You list 4 ideas:
location only works if you have wild card mapping (or specific extensions mapped).
Who wants to write an isapi filter? You can't easily do it in managed langauges unless you have IIS7. And who wants to write a c++ isapi filter?
wild card mapping does work with the above caveat (performance)
Again, last option wont work without registering those specific extensions with IIS and routing them through aspnet.
A nice simple way is to upgrade to IIS 7- it now has an integrated pipeline.