Click here to Skip to main content
15,878,809 members
Articles / Web Development / IIS

Browser Detection using ASP.NET

Rate me:
Please Sign up or sign in to vote.
4.63/5 (56 votes)
6 May 2009CPOL5 min read 557.7K   6.3K   186  
Using and updating your machine.config file to better detect browser type in ASP.NET
/*
Used to determine Browser Capabilities by the Browsers UserAgent string.
Copyright (C) 2002-Present  Owen Brady (Ocean at xvision.com)

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
using System;
namespace Ocean.Web.HttpCapabilities
{
	/// <summary>
	/// Summary description for HttpBrowserCapabilities.
	/// </summary>
	public class Settings
	{
		/// <summary>
		/// 
		/// </summary>
		private System.Collections.Specialized.StringDictionary UseVars;
		/// <summary>
		/// 
		/// </summary>
		private System.Collections.Specialized.StringDictionary Items;
		/// <summary>
		/// 
		/// </summary>
		private System.Collections.ArrayList Nodes;
		/// <summary>
		/// 
		/// </summary>
		private System.Web.HttpRequest Request;
		/// <summary>
		/// 
		/// </summary>
		private string UserAgent;
		/// <summary>
		/// 
		/// </summary>
		private string this [string key]
		{
			get 
			{ 
				if (key==null || key =="")
				{
					key ="%{HTTP_USER_AGENT}";
				}
				if (UseVars.ContainsKey(key.ToLower())==true)
				{
					return UseVars[key.ToLower()]; 
				}
				
				if (key[0]=='%' && key[1]=='{' && key[key.Length -1]=='}')
				{
					key = key.Substring(2);
					key = key.Substring(0,key.Length -1);
				}

				if (Items.ContainsKey(key.ToLower())==true)
				{
					return Items[key.ToLower()]; 
				}				

				return "";
			}
		}


		/// <summary>
		/// Get the current settings from the xml config file
		/// </summary>
		public static Settings GetSettings() 
		{
			Settings settings = (Settings)System.Configuration.ConfigurationSettings.GetConfig("Ocean.Web/BrowserCaps");
			if(settings == null)
			{
				return Settings.Default;
			}
			else
			{
				return settings;
			}
		}

		/// <summary>
		/// The default settings.  Deflate + normal.
		/// </summary>
		public static Settings Default 
		{
			get 
			{ 
				return new Settings(); 
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="node"></param>
		public void AddSettings(System.Xml.XmlNode node)
		{
			Nodes.Add(node);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="File"></param>
		public void AddSettings(Ocean.Web.HttpCapabilities.EmbededFile File)
		{
			//------------------------------------------------------
			//
			//------------------------------------------------------
			System.Reflection.Assembly assem = this.GetType().Assembly;

			string Resources="Ocean.Web.HttpCapabilities.Resources.";
			switch (File)
			{
				case Ocean.Web.HttpCapabilities.EmbededFile.BrowserCap:
					Resources+="xml.BrowserCap";
					break;
				case Ocean.Web.HttpCapabilities.EmbededFile.MobileCap:
					Resources+="xml.Mobile";
					break;
				case Ocean.Web.HttpCapabilities.EmbededFile.SpidersBots:
					Resources+="xml.SpidersBots";
					break;
				case Ocean.Web.HttpCapabilities.EmbededFile.CodeProject:
					Resources+="xml.CodeProject";
					break;
			}

			foreach( string resourceName in assem.GetManifestResourceNames()) 
			{
				if (resourceName==Resources)
				{
					//---------------------------------------------------------------------
					//The javascript code which we need has been embeded as a resource in this
					//dot.net libary dll. So all we have to do is use the stream method to get
					//the raw stream from the dll, so that we can work with it.
					//---------------------------------------------------------------------
					System.Xml.XmlDocument Doc = new System.Xml.XmlDocument();
					Doc.Load(assem.GetManifestResourceStream(resourceName));
					this.AddSettings(Doc.DocumentElement);
				}
			}
		}
		/// <summary>
		/// 
		/// </summary>
		private void Reset()
		{
			UseVars= new System.Collections.Specialized.StringDictionary();
			Items = new System.Collections.Specialized.StringDictionary();
		}
		/// <summary>
		/// 
		/// </summary>
		public Settings()
		{
			Reset();
			Nodes = new System.Collections.ArrayList();
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="File"></param>
		public Settings(Ocean.Web.HttpCapabilities.EmbededFile File):this()
		{
			this.AddSettings(File);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="node"></param>
		public Settings(System.Xml.XmlNode node):this()
		{
			this.AddSettings(node);
		}	
		/// <summary>
		/// 
		/// </summary>
		/// <param name="useragent"></param>
		/// <returns></returns>
		public Result Process(string useragent)
		{
			System.Diagnostics.Trace.WriteLine("Process");
			Reset();
			UserAgent = useragent;
			ProcessBase();
			return new Ocean.Web.HttpCapabilities.Result(Items);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="request"></param>
		/// <returns></returns>
		public Result Process(System.Web.HttpRequest request)
		{
			Reset();
			Request =request;
			UserAgent =request["HTTP_USER_AGENT"];
			ProcessBase();
			return new Ocean.Web.HttpCapabilities.Result(Items);
		}
		/// <summary>
		/// 
		/// </summary>
		internal void ProcessBase()
		{
			System.Diagnostics.Trace.WriteLine("ProcessBase");
			foreach (System.Xml.XmlNode node in Nodes)
			{
				ProcessNode(node);
			}
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="node"></param>
		internal void ProcessNode(System.Xml.XmlNode node)
		{
			System.Diagnostics.Trace.WriteLine("ProcessNode");
			if (node==null || node.ChildNodes ==null)
			{
				return;
			}
			foreach (System.Xml.XmlNode E in node.ChildNodes)
			{
				switch (E.Name.ToLower())
				{
					case "result":
						//do nothing with this currently
						break;
					case "use":
						ProcessUse(E);
						break;
					case "#text":
						ProcessItems(E);
						break;
					case "filter":

						if( E.HasChildNodes ==true)
						{
							Processfilter(E);
						}
						break;
				}
			}
		
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="node"></param>
		/// <returns></returns>
		internal bool ProcessCase(System.Xml.XmlNode node)
		{
			return ProcessCase(node,null);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="node"></param>
		/// <param name="RegMatch"></param>
		/// <returns></returns>
		internal bool ProcessCase(System.Xml.XmlNode node,Ocean.Web.HttpCapabilities.CaseFilter RegMatch)
		{
			System.Diagnostics.Trace.WriteLine("ProcessCase");
			string matchvalue ="";
			string matchwith ="";
			if (node.Attributes["match"]!=null)
			{
				matchvalue = node.Attributes["match"].Value;
			}
			if (node.Attributes["with"]!=null)
			{
				matchwith = node.Attributes["with"].Value;

				if (matchwith.Length >0 && matchwith[0]=='$' && RegMatch.CountGroups >0)
				{
					matchwith =RegMatch.Result(matchwith);
				}
				else if (matchwith.Length >0 && matchwith[0]=='%')
				{
					matchwith = this[matchwith];
				}
			}
			else
			{
				matchwith = this[matchwith];
			}
			
			Ocean.Web.HttpCapabilities.CaseFilter LocalMatch = new Ocean.Web.HttpCapabilities.CaseFilter(matchvalue,matchwith);
			if (LocalMatch.Success ==false)
			{
				return false;
			}
			else
			{
				System.Diagnostics.Trace.WriteLine(string.Format("value:{0}\twith:{1}",matchvalue,matchwith));
			}
			foreach (System.Xml.XmlNode E in node.ChildNodes)
			{
				switch (E.Name.ToLower())
				{
					case "#text":
						string raw = E.Value;
						if (LocalMatch.CountGroups >0)
						{
							raw = LocalMatch.Result(raw);
						}
						if (RegMatch!=null && RegMatch.CountGroups >0)
						{
							raw = RegMatch.Result(raw);
						}
						ProcessItems(raw);
						break;
					case "case":
						if( E.HasChildNodes ==true)
						{
							bool CaseValue=false;
							if (LocalMatch.CountGroups >1)
							{
								CaseValue = ProcessCase(E,LocalMatch);
							}
							else
							{
								CaseValue = ProcessCase(E,RegMatch);
							}
							if (CaseValue==true)
							{
								return true;
							}
						}
						break;
					case "filter":
						if( E.HasChildNodes ==true)
						{
							if (LocalMatch.CountGroups >1)
							{
								Processfilter(E,LocalMatch);
							}
							else
							{
								Processfilter(E,RegMatch);
							}
						}
						break;
				}
			}

			return true;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="node"></param>
		internal void Processfilter(System.Xml.XmlNode node)
		{
			Processfilter(node,null);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="node"></param>
		/// <param name="RegMatch"></param>
		internal void Processfilter(System.Xml.XmlNode node,Ocean.Web.HttpCapabilities.CaseFilter RegMatch)
		{
			System.Diagnostics.Trace.WriteLine("Processfilter");
			string matchvalue ="";
			string matchwith ="";
			if (node.Attributes["match"]!=null)
			{
				matchvalue = node.Attributes["match"].Value;
			}
			if (node.Attributes["with"]!=null)
			{
				matchwith = node.Attributes["with"].Value;

				if (matchwith.Length >0 && matchwith[0]=='$' && RegMatch.CountGroups >0)
				{
					matchwith =RegMatch.Result(matchwith);
				}
				else if (matchwith.Length >0 && matchwith[0]=='%')
				{
					matchwith = this[matchwith];
				}
			}
			else
			{
				matchwith = this[matchwith];
			}
			if (matchwith==null)
			{
				matchwith =string.Empty;
			}
			
			Ocean.Web.HttpCapabilities.CaseFilter LocalMatch = new Ocean.Web.HttpCapabilities.CaseFilter(matchvalue,matchwith);
			if (LocalMatch.Success ==false)
			{
				return ;
			}
			foreach (System.Xml.XmlNode E in node.ChildNodes)
			{
				switch (E.Name.ToLower())
				{
					case "#text":
						string raw = E.Value;
						if (LocalMatch.CountGroups >0)
						{
							raw = LocalMatch.Result(raw);
						}
						if (RegMatch!=null && RegMatch.CountGroups >0)
						{
							raw = RegMatch.Result(raw);
						}
						ProcessItems(raw);
						break;
					case "case":
						if( E.HasChildNodes ==true)
						{
							bool CaseValue=false;
							if (LocalMatch.CountGroups >1)
							{
								CaseValue = ProcessCase(E,LocalMatch);
							}
							else
							{
								CaseValue = ProcessCase(E,RegMatch);
							}
							if (CaseValue==true)
							{
								return;
							}
						}
						break;
					case "filter":
						if( E.HasChildNodes ==true)
						{
							if (LocalMatch.CountGroups >1)
							{
								Processfilter(E,LocalMatch);
							}
							else
							{
								Processfilter(E,RegMatch);
							}
						}
						break;
				}
			}
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="node"></param>
		internal void ProcessUse(System.Xml.XmlNode node)
		{
			System.Diagnostics.Trace.WriteLine("ProcessUse");
			string matchvar = node.Attributes["var"].Value;
			string matchas  = null;
			string HeaderResult ="";
			if (node.Attributes["as"]!=null)
			{
				if (node.Attributes["as"].Value!=null)
				{
					matchas  = node.Attributes["as"].Value.Trim();
				}
				else
				{
					matchas =string.Empty;
				}
			}
			else
			{
				matchas="HTTP_USER_AGENT";
			}
			System.Diagnostics.Trace.WriteLine("matchas:{0}",matchas);

			if (matchvar!=null)
			{
				if (matchas!=string.Empty)
				{
					matchas ="%{" + matchas.Trim() +"}";
					if (matchas=="%{HTTP_USER_AGENT}")
					{
						HeaderResult = UserAgent;
					}
					else if (Request!=null && Request[matchvar]!=null && Request[matchvar]!=string.Empty)
					{
						HeaderResult = Request[matchvar];
					}
					else
					{
						//no header that matches it so we have to put something there
						//so I put in an empty string.
						HeaderResult =string.Empty;
					}
					if (UseVars.ContainsKey(matchas)==false)
					{
						UseVars.Add(matchas,HeaderResult);
					}
					else
					{
						UseVars[matchas] = HeaderResult;
					}
				}
			}
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="node"></param>
		internal void ProcessItems(System.Xml.XmlNode node)
		{
			ProcessItems(node.Value);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="raw"></param>
		internal void ProcessItems(string raw)
		{
			System.Diagnostics.Trace.WriteLine("ProcessItems");
			//--------------------------------------------------
			//removing all the tabs out of the raw string
			//--------------------------------------------------
			while (raw.IndexOf("\t")>-1)
			{
				raw = raw.Replace("\t","");
			}
				
			//--------------------------------------------------
			//removing all the line feeds out of the raw string
			//--------------------------------------------------
			while (raw.IndexOf("\n")>-1)
			{
				raw = raw.Replace("\n","");
			}
			//--------------------------------------------------
			//removing all the double control breaks out of the 
			//raw string
			//--------------------------------------------------
			while (raw.IndexOf("\r\r")>-1)
			{
				raw = raw.Replace("\r\r","\r");
			}
				
			//--------------------------------------------------
			//removing all double blank spaces from the raw string
			//--------------------------------------------------
			while (raw.IndexOf("  ")>-1)
			{
				raw = raw.Replace("  "," ");
			}
			System.Text.RegularExpressions.Match M;
			M = System.Text.RegularExpressions.Regex.Match(raw,@"%{\w*}");
			while (M.Success==true)
			{
				for (int a=0;a<=M.Captures.Count -1;a++)
				{
					string s= M.Captures[a].Value;
					raw =raw.Replace(s,this[s]);
				}
				M = System.Text.RegularExpressions.Regex.Match(raw,@"%{\w*}");					
			}
			
			//--------------------------------------------------
			//Split the Array
			//--------------------------------------------------
			string[] itemsArray = System.Text.RegularExpressions.Regex.Split(raw,"\r");
			for (int i=0; i<= itemsArray.Length -1;i++)
			{
				itemsArray[i] = itemsArray[i].Trim();
				if(itemsArray[i]!="")
				{
					//--------------------------------------------------
					//only have to act if there is equal sign in the string
					//--------------------------------------------------
					if ( itemsArray[i].IndexOf("=")>-1)
					{
						string[] a = itemsArray[i].Split('=');
						a[1] = a[1].Trim();

						//--------------------------------------------------
						//always use lower case keys
						//--------------------------------------------------
						a[0] = a[0].Trim().ToLower();

						//--------------------------------------------------
						//just remove the quotes and move on
						//--------------------------------------------------
						while (a[1].IndexOf("\"")>-1)
						{
							a[1] = a[1].Replace("\"","");
						}

						//--------------------------------------------------
						//just making sure the varables are cleared out if they 
						//didn't take
						//--------------------------------------------------
						if (a[1].Length >2)
						{
							if (a[1].Substring(0,2) =="${")
							{
								a[1]=string.Empty;
							}
						}
						
						//--------------------------------------------------
						//this assigns the key/value pair to the string dictionary
						//--------------------------------------------------
						if (a[1]!=string.Empty)
						{
							if (Items.ContainsKey(a[0])==true)
							{
								Items[a[0]] = a[1];
							}
							else
							{
								Items.Add(a[0],a[1]);
							}
						}
					}					
				}
			}
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder CodeProject
Canada Canada
Chris Maunder is the co-founder of CodeProject and ContentLab.com, and has been a prominent figure in the software development community for nearly 30 years. Hailing from Australia, Chris has a background in Mathematics, Astrophysics, Environmental Engineering and Defence Research. His programming endeavours span everything from FORTRAN on Super Computers, C++/MFC on Windows, through to to high-load .NET web applications and Python AI applications on everything from macOS to a Raspberry Pi. Chris is a full-stack developer who is as comfortable with SQL as he is with CSS.

In the late 1990s, he and his business partner David Cunningham recognized the need for a platform that would facilitate knowledge-sharing among developers, leading to the establishment of CodeProject.com in 1999. Chris's expertise in programming and his passion for fostering a collaborative environment have played a pivotal role in the success of CodeProject.com. Over the years, the website has grown into a vibrant community where programmers worldwide can connect, exchange ideas, and find solutions to coding challenges. Chris is a prolific contributor to the developer community through his articles and tutorials, and his latest passion project, CodeProject.AI.

In addition to his work with CodeProject.com, Chris co-founded ContentLab and DeveloperMedia, two projects focussed on helping companies make their Software Projects a success. Chris's roles included Product Development, Content Creation, Client Satisfaction and Systems Automation.

Comments and Discussions