Created
April 5, 2010 02:04
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Scans a WebApplication project for UserControls and creates matching instances in the web.config file.