Click here to Skip to main content
15,895,011 members
Articles / Web Development / ASP.NET

ASP.NET Advanced Generic Handler ASHX

Rate me:
Please Sign up or sign in to vote.
4.74/5 (49 votes)
9 Jun 2013CPOL5 min read 323.3K   10.2K   138  
Take your Generic Handlers to the next level...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Web;
using System.Web.Script.Serialization;
using System.IO;
using System.ComponentModel;

namespace App.Utilities.Web.Handlers
{
	public class AjaxCallSignature
	{
		public AjaxCallSignature(HttpContext context)
		{
			args = new Dictionary<string, object>();
			method = string.Empty;
			string nullKeyParameter = context.Request.QueryString[null];
			if (string.IsNullOrEmpty(nullKeyParameter))
			{
				if (!string.IsNullOrEmpty(context.Request.QueryString.ToString()) && context.Request.QueryString.ToString().StartsWith("{"))
				{ 
				
				}
			}

			if (context.Request.RequestType.ToUpper() == "POST")
			{
				string[] requestParams = context.Request.Params.AllKeys;
				foreach (var item in requestParams)
				{
					if (item.ToLower() == "method")
					{
						method = context.Request.Params[item];
					}
					else if (item.ToLower().StartsWith("args["))
					{
						string key = item.Trim().TrimEnd(']').Substring(5);
						string value = context.Request.Params[item];
						args.Add(key, value);
					}
					else
					{
						string key = item;
						string value = context.Request.Params[item];
						args.Add(key, value);
					}
				}
			}
			else if (context.Request.RequestType.ToUpper() == "GET")
			{
				// evaluate the data passed as json
				if (!string.IsNullOrEmpty(nullKeyParameter))
				{
					if (nullKeyParameter.ToLower() == "help")
					{
						method = "help";
						return;
					}
					else
					{
						object json = null;
						JavaScriptSerializer serializer = new JavaScriptSerializer();
						json = serializer.DeserializeObject(context.Request.QueryString[null]);

						try
						{
							Dictionary<string, Object> dict = (Dictionary<string, Object>)json;

							if (dict.ContainsKey("method"))
								method = dict["method"].ToString();
							else
								throw new Exception("Invalid BaseHandler call. MethodName parameter is mandatory in json object.");

							if (dict.ContainsKey("returntype"))
								returnType = dict["returntype"].ToString();

							if (dict.ContainsKey("args"))
								args = (Dictionary<string, Object>)dict["args"];
							else
								args = new Dictionary<string, object>();
						}
						catch
						{
							throw new InvalidCastException("Unable to cast json object to AjaxCallSignature");
						}
					}
				}

				// evaluate data passed as querystring params
				foreach (string key in context.Request.QueryString.Keys)
				{
					if (key == null)
						continue;

					if (key.ToLower() == "method")
					{
						if (string.IsNullOrEmpty(method))
						{
							method = context.Request.QueryString[key];
						}
						else
						{
							throw new Exception("Method name was already specified on the json data. Specify the method name only once, either on QueryString params or on the json data.");
						}
					}
					else if (key.ToLower() == "returncontenttype")
					{
						returnType = context.Request.QueryString[key];
					}
					if (key.ToLower().StartsWith("args["))
					{
						string _key = key.Trim().Substring(5).TrimEnd(']').Replace("][", "+");
						args.Add(_key, context.Request.QueryString[key]);
					}
					else
					{
						args.Add(key, context.Request.QueryString[key]);
					}
				}
			}
		}

		public string method { get; set; }
		public string returnType { get; set; }
		public Dictionary<string, object> args { get; set; }

		public object Invoke(object obj, HttpContext context)
		{
			MethodInfo m = obj.GetType().GetMethod(method);
			List<object> a = new List<object>();

			if (m == null)
			{
				if (method.ToLower() == "help")
				{
					m = obj.GetType().BaseType.GetMethod("Help");
				}
				else
				{
					throw new Exception(string.Format("Method {0} not found on Handler {1}.", method, this.GetType().ToString()));
				}
			}
			else
			{
				// security validation: Search for RequireAuthenticationAttribute on the method
				//		value=true the user must be authenticated (only supports FromsAuthentication for now
				//		value=false invoke the method
				object[] attrs = m.GetCustomAttributes(typeof(RequireAuthenticationAttribute), true);
				if (attrs != null && attrs.Length > 0)
				{

					if (!context.Request.IsAuthenticated && ((RequireAuthenticationAttribute)attrs[0]).RequireAuthentication)
					{
						throw new InvalidOperationException("Method [" + m.Name + "] Requires authentication");
					}
				}
			}

			foreach (var param in m.GetParameters())
			{
				/* Handle class arguments (things like custome classes and such) */
				if (param.ParameterType.IsClass && !param.ParameterType.Equals(typeof(String)))
				{
					var argumentObject = Activator.CreateInstance(param.ParameterType);
					var objectProperties = args.Keys.ToList().FindAll(k => k.StartsWith(param.Name + "+"));
					foreach (var p in objectProperties)
					{
						string propertyName = p.Split('+')[1];
						argumentObject.GetType().GetProperty(propertyName).SetValue(argumentObject, args[p], null);
					}

					a.Add(argumentObject);
				}
				/* Handle everything else (like rimitive types and strings) */
				else if (args.Keys.Contains(param.Name))
				{
					// its usual to pass an empty json string property but casting it to certain types will throw an exception
					if (string.IsNullOrEmpty(args[param.Name].ToString()) || args[param.Name].ToString() == "null" || args[param.Name].ToString() == "undefined")
					{
						// handle numerics. convert null or empty input values to 0
						if (param.ParameterType.Equals(typeof(System.Int16)) || param.ParameterType.Equals(typeof(System.Int32)) || 
							param.ParameterType.Equals(typeof(System.Int64)) || param.ParameterType.Equals(typeof(System.Decimal)) ||
							param.ParameterType.Equals(typeof(System.Double)) || param.ParameterType.Equals(typeof(System.Byte)))
						{
							args[param.Name] = 0;
						}
						else if (param.ParameterType.Equals(typeof(System.Guid)))
						{
							args[param.Name] = new Guid();
						}
						else if (param.ParameterType.IsGenericType && param.ParameterType.GetGenericTypeDefinition() == typeof(Nullable<>))
						{
							args[param.Name] = null;
						}
					}

					// evaluate special types that are not directly casted from string
					TypeConverter conv = TypeDescriptor.GetConverter(param.ParameterType);
					if (args[param.Name] == null || param.ParameterType == args[param.Name].GetType())
					{
						a.Add(args[param.Name]);
					}
					else
					{
						a.Add(conv.ConvertFromInvariantString(args[param.Name].ToString()));
					}
				}
				else
				{
					a.Add(null);	// if there are missing arguments try passing null
				}
			}

			return m.Invoke(obj, a.ToArray());
		}

	}
}

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
Architect
Switzerland Switzerland
Senior IT Consultant working in Switzerland as Senior Software Engineer.

Find more at on my blog.

Comments and Discussions