@Shazwazza

Shannon Deminick's blog all about web development

ASP.Net 5 - Re-learning a few things (part 1)

November 14, 2014 03:20

ASP.Net 5 (aka vNext) is now in Beta and the Visual Studio 2015 preview is now out! So, what is this new ASP.Net? The 2 biggest features is that it’s totally open source and it will support a cross platform runtime = great!! But it’s worth knowing that this is more or less a rebuild of ASP.Net and there’s quite a few things that we’ve become accustomed to that will now be totally different.

Configuration files

You know all of that junk in the web.config and perhaps in a bunch of other *.config files? Well that is gone! I think this is wonderful news because creating those configuration sections was a huge pain. Even better news is how easy creating custom configuration inputs will be in  ASP.Net 5 using the new IConfiguration and ConfigurationModel sources. OOTB Microsoft is releasing support for JSON, XML and INI files for configuration but of course you can easily create your own.  The repository for the configuration bits is here and a nice tutorial can be found here.

So what about configuration transforms?? That is also a thing of the past. In ASP.Net 5, “configuration” will mostly be done with code found in your Startup.cs file, anything that you want to enable in your application is done in this class. Any package that is installed in your app, you will need to opt-in to use it in your Startup.cs file. In some cases however, a configuration file might need to be updated/transformed… this could be due to an upgrade of a package. The good news is that the configuration sources in ASP.Net 5 are writable (IConfigurationSource) which means during startup or first access to your config, you could detect what needs to be updated to support your new version, make the updates in code and commit (ICommitableConfigurationSource) the changes.

Wait… isn’t that going to restart the app domain?? 

NOTE: If you are using IIS, there can still be a web.config which can be used to configure IIS settings under the system.webserver section.

AppDomain restarts

This is something that we’ve all become familiar with… you want to restart your app, just bump/touch the web.config and your app domain is restarted. This is something we’ll all have to un-learn. In ASP.Net 5 auto app domain restarts don’t happen. First, there is no web.config (or global.asax for that matter) so there are no files to bump/touch. Next, a big reason why auto app domain restarts can’t occur is because ASP.Net 5 will be able to be run on various different web servers which don’t really know about what it means to restart an app domain. For example if you’ve been playing around with vNext before you had a chance to use VS 2015, you might be familiar with the command line “k web” (see docs for details). This command will start up a simple web server: Microsoft.AspNet.Server.WebListener which will serve web requests. In order for app domain restarts to occur, it would need to know how to restart itself after it’s been shutdown which isn’t exactly possible with a simple command line process. Instead if you made any changes to your code and wanted to restart your app, you’d kill the process (ctrl + c) and just call k web again. Another thing to be aware of is that when you kill a process like this, your app domain does not gracefully shutdown/unwind, it’s simply terminated.

But not to worry! If you have a web app that requires restarting (i.e. maybe it installs plugins, etc…) and needs to gracefully unwind, it’s still possible and actually much more pleasant since you’ll be in full control of how/when it happens. In order for this to work you’ll need to be running a web server that knows how to start itself back up again - like IIS! The way to gracefully shutdown your app domain is by using: IApplicationShutdown when you want to gracefully shutdown your app. You could even use that in combination with an IFileWatcher and your own configuration files … if you really wanted to mimic an app domain restart by bumping/touching a file.

Deployments, bin folder and App_Code

Speaking of app domain restarts, how will ASP.Net 5 work when I put a new assembly in the /bin folder or add a new class to App_Code?? These are a couple more things that need to be un-learned. There really isn’t a /bin folder anymore (well, there is but it only contains one very special assembly if you are running IIS) and there isn’t any App_Code folder.  So where does all of this go?

When you publish a web project in VS 2015 (which uses kpm pack) you end up with a very different looking deployment structure. There’s two folder: approot and wwwroot.

wwwroot – is the content of your website, nothing more. Even things like configuration files don’t exist here, it’s just content that your webserver can serve.

approot – this is the brains of your website. It includes all of the binaries, config files, source code, etc… that is used to run your website.

Here’s a blog post that describes the deployed file structure 

Did you say source code?? Yup! By default kpm pack will deploy your site with all of it’s packages and the source code for all of your projects. The Roslyn compiler will take care of everything for you when your site needs to start serving requests. You can of course opt-out of this and have your site deployed as a compiled package.

Did you say Package?? Yup, as in Nuget package! Instead of a /bin folder full of assemblies, all of your dependencies will actually be Nuget references and stored in approot/packages and if you choose to deploy your website without source, it will be compiled into a Nuget package and deployed in the packages folder as well.

More to come….

So there’s a a few of the things that are pretty different in ASP.Net 5, there’s still more to come and hopefully I’ll find some time to write them all up!

Taming the BuildManager, ASP.Net Temp files and AppDomain restarts

March 28, 2012 08:14

I’ve recently had to do a bunch of research in to the BuildManager and how it deals with caching assemblies since my involvement with creating an ASP.Net plugin engine. Many times people will attempt to restart their AppDomain by ‘bumping’ their web.config files, meaning adding a space character or carriage return and then saving it. Sometimes you may have noticed that this does not always restart your AppDomain the way you’d expect and some of the new types you’d expect to have loaded in your AppDomain simply aren’t there. This situation has cropped up a few times when using the plugin engine that we have built in to Umbraco v5 and some people have resorted to manually clearing out their ASP.Net temp files and then forcing an IIS Restart, but this is hardly ideal. The good news is that we do have control over how these assemblies get refreshed, in fact the BuildManager reloads/refreshes/clears assemblies in different ways depending on how the AppDomain is restarted.

The hash.web file

An important step during the BuildManager initialization phase is a method call to BuildManager.CheckTopLevelFilesUpToDate which does some interesting things. First it checks if a special hash value is on disk and is not zero. You may have noticed a file in your ASP.Net temp files: /hash/hash.web and it will contain a value such as: 4f34227133de5346. This value represents a unique hash of many different combined objects that the BuildManager monitors. If this file exists and the value can be parsed properly then the BuildManager will call: diskCache.RemoveOldTempFiles(); What this does is the following:

  • removes the CodeGen temp resource folder
  • removes temp files that have been saved during CodeGen such as *.cs
  • removes the special .delete files and their associated original files which have been created when shutting down the app pool and when the .dll files cannot be removed (due to file locking)

Creating the hash value

The next step is to create this hash value based on the current objects in the AppDomain. This is done using an internal utility class in the .Net Framework called: HashCodeCombiner (pretty much everything that the BuildManager references is marked Internal! ). The process combines the following object values to create the hash (I’ve added in parenthesis the actual properties the BuildManager references):

  • the app's physical path, in case it changes (HttpRuntime.AppDomainAppPathInternal)
  • System.Web.dll (typeof(HttpRuntime).Module.FullyQualifiedName)
  • machine.config file name (HttpConfigurationSystem.MachineConfigurationFilePath)
  • root web.config file name, please note that this is not your web apps web.config (HttpConfigurationSystem.RootWebConfigurationFilePath)
  • the hash of the <compilation> section (compConfig.RecompilationHash)
  • the hash of the system.web/profile section (profileSection.RecompilationHash)
  • the file encoding set in config (appConfig.Globalization.FileEncoding)
  • the <trust> config section (appConfig.Trust.Level & appConfig.Trust.OriginUrl)
  • whether profile is enabled (ProfileManager.Enabled)
  • whether we are precompiling with debug info (but who precompiles :) (PrecompilingWithDebugInfo)

Then we do a check for something I didn’t know existed called Optimize Compilations which will not actual affect the hash file value for the following if it is set to true (by default is is false):

  • the ‘bin’ folder (HttpRuntime.BinDirectoryInternal)
  • App_WebReferences (HttpRuntime.WebRefDirectoryVirtualPath)
  • App_GlobalResources  (HttpRuntime.ResourcesDirectoryVirtualPath)
  • App_Code (HttpRuntime.CodeDirectoryVirtualPath)
  • Global.asax (GlobalAsaxVirtualPath)

Refreshing the ASP.Net temp files (CodeGen files)

The last step of this process is to check if the persisted hash value in the hash.web file equals the generated hash value from the above process. If they do not match then a call is made to diskCache.RemoveAllCodegenFiles(); which will:

  • clear all codegen files, removes all files in folders but not the folders themselves,
  • removes all root level files except for temp files that are generated such as .cs files, etc...

This essentially clears your ASP.Net temp files completely, including the MVC controller cache file, etc…

Then the BuildManager simply resaves this calculated has back to the hash.web file.

What is the best way to restart your AppDomain?

There is really no ‘best’ way, it just depends on your needs. If you simply want to restart your AppDomain and not have the overhead of having your app recompile all of your views and other CodeGen classes then it’s best that you simply ‘bump’ your web.config by just adding a space, carriage return or whatever. As you can see above the hash value is not dependant on your local web.config file’s definition (timestamp, etc…). However, the hash value is dependent on some other stuff in your apps configuration such as the <compilation> section, system.web/profile section, the file encoding configured, and the <trust> section. If you update any value in any of these sections in your web.config it will force the BuildManager to clear all cached CodeGen files which is the same as clearing your ASP.Net temp files.

So long as you don’t have optimizeCompilations set to true, then the easiest way to clear your CodeGen files is to simply add a space or carriage return to your global.asax file or modify something in the 4 other places that the BuildManager checks locally: App_Code, App_GlobalResources, App_WebResources, or modify/add/remove a file in your bin folder.

How does this affect the ASP.Net plugin engine?

Firstly, i need to update that post as the code in the plugin engine has changed quite a bit but you can find the latest in the Umbraco source code on CodePlex. With the above knowledge its easy to clear out any stale plugins by perhaps bumping your global.asax file, however this is still not an ideal process. With the research I’ve done in to the BuildManager I’ve borrowed some concepts from it and learned of a special “.delete” file extension that the BuildManager looks for during AppDomain restarts. With this new info, I’ve already committed some new changes to the PluginManager so that you shouldn’t need to worry about stale plugin DLLs.

Wildcard mapping in IIS 7 classic pipeline = web.config!

December 9, 2009 00:34
This post was imported from FARMCode.org which has been discontinued. These posts now exist here as an archive. They may contain broken links and images.
After foolishly pulling out my hair trying to find out why my wildcard mapping was disappearing in IIS 7 using classic pipeline mode, i realized it was my own fault!! I followed the instructions on this site: http://learn.iis.net/page.aspx/508/wildcard-script-mapping-and-iis-7-integrated-pipeline/ and unfortunately just skipped over the message about how this modifies your web.config… oops! So basically, every time I deployed my handler mapping would be removed… Doh!

Unfortunately, the method to add a wildcard mapping in this article will actually remove the inheritance of standard handlers from the root of IIS and your machine.config and just make copies of them. This might not be the best approach, but i suppose sometimes it’s necessary. We only need the wildcard mapping for URL Rewriting so i decided to see if i could just simply add the isapi wildcard mapping only, have the rest of the handlers inherit from the root and see if it works… turns out it does!

So instead of having to modify IIS itself, i just needed to add this to my web.config:

<handlers>
	<remove name="ASP.Net-ISAPI-Wildcard" />
	<add name="ASP.Net-ISAPI-Wildcard" path="*"
	verb="*" type="" modules="IsapiModule"
	scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll"
	resourceType="Unspecified"
	requireAccess="None"
	allowPathInfo="false"
	preCondition="classicMode,runtimeVersionv2.0,bitness64"
	responseBufferLimit="4194304" />
</handlers>

Too easy! No fussing around with IIS and now at least i won’t override my changes accidentally.

Guide to installing Cold Fusion 8 on Windows Server 2008 (IIS 7) 64 bit

May 8, 2009 00:27
This post was imported from FARMCode.org which has been discontinued. These posts now exist here as an archive. They may contain broken links and images.
After a lot of trial and error i finally figured out how to get CF 8 running in on Windows Server 2008 x64 in IIS 7. So i figured I’d write a post about it since there’s pretty much no documentation covering this that i could find.

Installation

  • Take a backup of IIS
    • C:\Windows\System32\Inetsrv\AppCmd add backup "backupname"
  • Install CF 8 Enterprise
    • Select Multiserver
    • Keep default paths
    • DO NOT attempt to configure anything for ColdFusion until the update is applied
  • Install CF 8.1 Update
    • Configure for Multiserver

Web Site/Server Configuration

  • Give the IIS users/groups (IUSR, IIS_IUSRS) full control over your JRun install folder (C:\JRun4\lib\wsconfig)
    • After looking at the logs, it seems that the configuration tool is trying to set IIS_WPG permissions on this folder which is for Server 2003, not 2008
  • Create a new application pool called ColdFusion
    • Under advanced settings, enable running in 32 bit mode and make Managed Pipeline mode Classic instead of Integrated
    • CF will not run without 32 bit and Classic enabled (according to my experience so far)
  • Create a new website and ensure it is assigned to the ColdFusion application pool
    • For testing, create a website pointed to your default CFIDE install folder
  • Launch the Web Server Configuration Tool from Start Menu
    • Click Add
    • Select "coldfusion" from the JRun Server drop down list (not "admin")
    • Ensure the Web Server has IIS selected
    • Select the website you just created from the IIS Web Site drop down list (Do not check All, or be prepared to restore IIS if your running other .Net apps!)
    • Check "Configure web server for ColdFusion 8 application"
    • Click Advanced...
      • Check Enable verbose logging for connector if you want details log requests for debugging
    • Save changes and click yes to restart the web server (this will restart IIS!!!)

Testing

  • If you configured a test site to point to your CFIDE folder, go to the website in your browser to the /install.cfm path
    • This should show you a Congratulations screen
  • If you configured your site with your own CF files, test those instead

Debugging

  • After some trial and error, i figured out the above procedure, but there are logs to refer to.
  • the CF web site config tool creates web site configuration structures at this location:
    • \Run4\lib\wsconfig\(some number)
    • Each (some number) corresponds to a different website configured with the tool
    • In each folder is a LogFiles folder that contains logs that you can use to debug the installation
  • There's also a log file at: \Run4\lib\wsconfig\wsconfig.log

Un-configuring a site

  • If a site needs to be un-configured or re-configured, the web configuration tool seem to always fail when trying to remove a site.
  • To remove a site manually:
    • Stop the website in IIS
    • Stop the CF server and CF admin services in the Services administration tools
    • Delete the folder: \Run4\lib\wsconfig\(some number)
      • where (some number) corresponds to the site you want to remove
    • edit the \Run4\lib\wsconfig\wsconfig.properties file and remove the lines referring to the number (some number) of the site folder that you deleted in the previous step
    • Start the CF admin and CF server services
    • Run the web configuration tool and re-add the site you want configured
    • Start the site in IIS