Skip to content

Instantly share code, notes, and snippets.

@hugoware
Created April 5, 2010 02:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hugoware/355921 to your computer and use it in GitHub Desktop.
Save hugoware/355921 to your computer and use it in GitHub Desktop.
Scans an ASP.NET WebApplication project to find UserControls and adds them to the web.config file
/*
* Hugo Bonacci
* http://hugoware.net
*
* UserControls in Web Application projects do not appear unless
* you use the Register tag at the top of the page or add them and
* their virtual path to the web.config file.
*
* This code allows you to add the namespace of your UserControls
* to the web.config file and it will automatically scan for any
* new .ascx files and add them for you automatically.
*
* Use this code as part of the Application_Start method in
* the Global.ascx.
*
* NOTE: This code causes a single redirect for the first request
* to the site if a change is found in the web.config
*
*/
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Web.Configuration;
using System.Web.UI;
using System.Xml.Linq;
using System.Text.RegularExpressions;
namespace Web {
/// <summary>
/// Located existing UserControls and attaches them to the Web.config
/// </summary>
public class UserControlScanner {
#region Constants
private const string SCAN_FILE_TYPE = "*.ascx";
#endregion
#region Constructors
/// <summary>
/// Creates a new UserControl scanner that finds .ascx files
/// and then attaches them to the web.config
/// </summary>
public UserControlScanner()
: this("asp") {
}
/// <summary>
/// Creates a new UserControl scanner that finds .ascx files
/// and then attaches them to the web.config
/// </summary>
public UserControlScanner(string prefix) {
this.DefaultTagPrefix = prefix;
this._Root = HttpContext.Current.Server.MapPath("~/");
this._Controls = new List<_UserControlDetail>();
this._Types = new List<Type>();
}
#endregion
#region Properties
/// <summary>
/// The tag prefix to use if the control doesn't have
/// a matching namespace in the web.config file
/// </summary>
public string DefaultTagPrefix { get; set; }
//scan details
private string _Root;
private List<_UserControlDetail> _Controls;
private List<Type> _Types;
#endregion
#region Public Methods
/// <summary>
/// Scans for .ASCX files and updates the web.config
/// folder with the new files
/// </summary>
public void ScanAndUpdate() {
//find the types that inherit from UserControl
this._FindUserControlTypes();
//find the .ascx files
this._ScanForAscxFiles();
//assign types to the correct UserControls
this._SyncTypes();
//update the web.config for changes
this._UpdateConfig();
}
/// <summary>
/// Shuts down the current site and reloads it - This
/// causes a redirect for the connecting user
/// </summary>
public void Reset() {
//get the path to redirect to
string url = HttpContext.Current.Request.Url.AbsolutePath;
//then reset the system
HttpRuntime.UnloadAppDomain();
//and redirect the request to start over
HttpContext.Current.Response.Redirect(url);
}
#endregion
#region Private Methods
//scans for ascx files to compare against
private void _ScanForAscxFiles() {
foreach (string path in Directory.GetFiles(this._Root, SCAN_FILE_TYPE, SearchOption.AllDirectories)) {
this._Controls.Add(_UserControlDetail.Parse(path));
}
}
//finds all of the matching user controls
private void _FindUserControlTypes() {
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) {
this._Types.AddRange(
assembly.GetTypes()
.Where(item => item.IsSubclassOf(typeof(UserControl))));
}
}
//syncs all of the types to a matching value
private void _SyncTypes() {
//update the types
foreach (_UserControlDetail detail in this._Controls) {
detail.Type = this._Types.FirstOrDefault(item => item.FullName.Equals(detail.FullName));
}
//drop anything that is missing
this._Controls.RemoveAll(item => item.Type == null);
}
//returns a list of existing controls found for the site
private void _UpdateConfig() {
//open the configuration section
Configuration config = WebConfigurationManager.OpenWebConfiguration("~");
//grab the details for the controls
ConfigurationSection section = config.GetSection("system.web/pages");
string content = section.SectionInformation.GetRawXml();
//get the controls section
XElement xml = XElement.Parse(content);
//start by getting a hash of the starting setup
string start = this._GetHash(xml.ToString());
//make sure the controls node is available
XElement controls = xml.Element("controls");
if (controls == null) {
controls = new XElement("controls");
xml.Add(controls);
}
//reach each type to find tagPrefix names
foreach (XElement element in controls.Elements()) {
XAttribute @namespace = element.Attribute("namespace");
XAttribute prefix = element.Attribute("tagPrefix");
//check for a namespace value
if (!(@namespace is XAttribute && prefix is XAttribute)) {
continue;
}
//update all of the correct elements
foreach (_UserControlDetail detail in this._Controls) {
if (detail.Type.Namespace.Equals(@namespace.Value.Trim())) {
detail.Prefix = prefix.Value;
}
}
}
//make sure all of the controls have a prefix
foreach (_UserControlDetail control in this._Controls) {
control.Prefix = string.IsNullOrEmpty(control.Prefix)
? this.DefaultTagPrefix
: control.Prefix;
}
//next, remove any controls with paths
for (int i = controls.Elements().Count(); i-- > 0; ) {
XElement element = controls.Elements().ElementAt(i);
if (element.Attribute("src") is XAttribute) {
element.Remove();
}
}
//then add back all of the new paths
foreach (_UserControlDetail detail in this._Controls) {
controls.Add(
new XElement("add",
new XAttribute("tagPrefix", detail.Prefix),
new XAttribute("tagName", detail.Type.Name),
new XAttribute("src", detail.VirtualPath)
));
}
//check if anything changes
string finish = this._GetHash(xml.ToString());
if (start.Equals(finish)) { return; }
//update the XML information
section.SectionInformation.SetRawXml(xml.ToString());
config.Save();
//since this has changes, go ahead and reset
this.Reset();
}
//creates a hash for comparing changes
private string _GetHash(string content) {
return Convert.ToBase64String(SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(content)));
}
#endregion
}
#region User Control Details
//contains information about a user control and how
//to map the control
internal class _UserControlDetail {
#region Static Constructors
//prepares the UserControlDetail expressions
static _UserControlDetail() {
_UserControlDetail.RegexFindControlInformation = new Regex(@"^\s*<%@ Control.*%>", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase);
_UserControlDetail.RegexFindControlInherit = new Regex(@"Inherits=""(?<inherit>[^""]+)""", RegexOptions.IgnoreCase);
}
#endregion
#region Static Values
private static Regex RegexFindControlInformation;
private static Regex RegexFindControlInherit;
#endregion
#region Properties
public string PhysicalPath;
public string VirtualPath;
public string FullName;
public string Prefix;
public Type Type;
#endregion
#region Static Creation
//parses the values for a user control
public static _UserControlDetail Parse(string path) {
_UserControlDetail detail = new _UserControlDetail();
detail.PhysicalPath = path;
//get the virtual path
string root = HttpContext.Current.Server.MapPath("~/");
string file = detail.PhysicalPath.Replace(root, string.Empty);
detail.VirtualPath = string.Concat("~/", file.Replace("\\", "/"));
//determine the virtual path for this
string content = File.ReadAllText(path);
Match control = _UserControlDetail.RegexFindControlInformation.Match(content);
if (!control.Success) { return null; }
//find what class it inherits from
Match inherit = _UserControlDetail.RegexFindControlInherit.Match(control.Value);
if (!inherit.Success) { return null; }
detail.FullName = inherit.Groups["inherit"].Value;
//return the result to work with
return detail;
}
#endregion
}
#endregion
}
@hugoware
Copy link
Author

hugoware commented Apr 5, 2010

Scans a WebApplication project for UserControls and creates matching instances in the web.config file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment