ajaxprochelper.cs

来自「AJAX开发工具包」· CS 代码 · 共 271 行

CS
271
字号
/*
 * MS	06-04-13	changed content type to "application/json; charset=utf-8"
 * 
 * 
 * 
 */
using System;
using System.Reflection;
using System.Web;
using System.Web.Caching;
using System.IO;

namespace AjaxPro
{
	internal class AjaxProcHelper
	{
		private IAjaxProcessor p;
		private ImDone done;
		private IntPtr token = IntPtr.Zero;
		private System.Security.Principal.WindowsImpersonationContext winctx = null;

		internal AjaxProcHelper(IAjaxProcessor p)
		{
			this.p = p;
		}

		internal AjaxProcHelper(IAjaxProcessor p, ImDone done, IntPtr token) : this(p)
		{
			this.done = done;
			this.token = token;
		}

		internal void Run()
		{
			if(p.Context.Trace.IsEnabled) p.Context.Trace.Write(Constant.AjaxID, "Begin ProcessRequest");


			try
			{
				// If we are using the async handler we have to set the ASPNET username
				// to have the same user rights for the created thread.

				if(token != IntPtr.Zero)
					winctx = System.Security.Principal.WindowsIdentity.Impersonate(token);


				// We will check the custom attributes and try to invoke the method.
		
				p.Context.Response.Expires = 0;
				p.Context.Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);
				p.Context.Response.AddHeader("Content-Type", "application/json; charset=utf-8");


				if(!p.IsValidAjaxToken(Utility.CurrentAjaxToken))
				{
					p.SerializeObject(new System.Security.SecurityException("The Ajax-token is not valid."));

					if(p.Context.Trace.IsEnabled) p.Context.Trace.Write(Constant.AjaxID, "End ProcessRequest");
					return;
				}


				AjaxMethodAttribute[] ma = (AjaxMethodAttribute[])p.Method.GetCustomAttributes(typeof(AjaxMethodAttribute), true);
				AjaxServerCacheAttribute[] sca = (AjaxServerCacheAttribute[])p.Method.GetCustomAttributes(typeof(AjaxServerCacheAttribute), true);

				object[] po = null;
				object res = null;


				#region Retreive Parameters from the HTTP Request

				try
				{
					// The IAjaxProcessor will read the values either form the 
					// request URL or the request input stream.

					po = p.RetreiveParameters();
				}
				catch(Exception ex)
				{
					p.SerializeObject(ex);

					if(p.Context.Trace.IsEnabled) p.Context.Trace.Write(Constant.AjaxID, "End ProcessRequest");
					return;
				}

				#endregion 

//				if(ca.Length > 0)
//				{
//					if(ca[0].IsClientCacheEnabled)
//					{
//						p.Context.Response.Cache.SetCacheability(System.Web.HttpCacheability.Public);
//						p.Context.Response.Cache.SetExpires(DateTime.Now.Add(ca[0].ClientCacheDuration));
//					}
//				}				

				string cacheKey = p.Type.FullName + "|" + p.GetHashCode();
				if(p.Context.Cache[cacheKey] != null)
				{
					if(p.Context.Trace.IsEnabled) p.Context.Trace.Write(Constant.AjaxID, "Using cached result");

					p.Context.Response.Write(p.Context.Cache[cacheKey]);

					if(p.Context.Trace.IsEnabled) p.Context.Trace.Write(Constant.AjaxID, "End ProcessRequest");
					return;
				}

				#region Reflection part of Ajax.NET

				try
				{
					if(p.Context.Trace.IsEnabled) p.Context.Trace.Write(Constant.AjaxID, "Invoking " + p.Type.FullName + "." + p.Method.Name);

					// If this is a static method we do not need to create an instance
					// of this class. Some classes do not have a default constructor.

					if(p.Method.IsStatic)
					{
						try
						{
							res = p.Type.InvokeMember(
								p.Method.Name,
								System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.IgnoreCase,
								null, null, po);
						}
						catch(Exception ex)
						{
							if(ex.InnerException != null)
								p.SerializeObject(ex.InnerException);
							else
								p.SerializeObject(ex);

							if(p.Context.Trace.IsEnabled) p.Context.Trace.Write(Constant.AjaxID, "End ProcessRequest");
							return;
						}
					}
					else
					{
						// Create an instance of the class using the default constructor that will
						// not need any argument. This can be a problem, but currently I have no
						// idea on how to specify arguments for the constructor.

						if(p.Context.Trace.IsEnabled) p.Context.Trace.Write(Constant.AjaxID, "Reflection Start");

						try
						{
							object c = (object)Activator.CreateInstance(p.Type, new object[]{});

							// Because the page context properties (Request, Response, Cache...) are 
							// not set using Reflection we will set the context by using the IContextInitializer
							// interface.

							if(typeof(IContextInitializer).IsAssignableFrom(p.Type))
							{
								((IContextInitializer)c).InitializeContext(p.Context);
							}

							if(c != null)
							{
//								if(po == null)
//									po = new object[p.Method.GetParameters().Length];

								res = p.Method.Invoke(c, po);
							}
						}
						catch(Exception ex)
						{
							if(ex.InnerException != null)
								p.SerializeObject(ex.InnerException);
							else
								p.SerializeObject(ex);

							if(p.Context.Trace.IsEnabled) p.Context.Trace.Write(Constant.AjaxID, "End ProcessRequest");
							return;
						}

						if(p.Context.Trace.IsEnabled) p.Context.Trace.Write(Constant.AjaxID, "Reflection End");

					}
				}
				catch(Exception ex)
				{
					if(ex.InnerException != null)
						p.SerializeObject(ex.InnerException);
					else
						p.SerializeObject(ex);

					if(p.Context.Trace.IsEnabled) p.Context.Trace.Write(Constant.AjaxID, "End ProcessRequest");
					return;
				}

				#endregion


				try
				{
					if(res != null && res.GetType() == typeof(System.Xml.XmlDocument))
					{
						// If the return value is XmlDocument we will return it direct
						// without any convertion. On the client-side function we can
						// use .responseXML or .xml.

						p.Context.Response.ContentType = "text/xml";
						((System.Xml.XmlDocument)res).Save(p.Context.Response.OutputStream);


						if(p.Context.Trace.IsEnabled) p.Context.Trace.Write(Constant.AjaxID, "End ProcessRequest");
						return;
					}


					string result = null;;

					System.Text.StringBuilder sb = new System.Text.StringBuilder();

					try
					{
						result = p.SerializeObject(res);
					}
					catch(Exception ex)
					{
						p.SerializeObject(ex);

						if(p.Context.Trace.IsEnabled) p.Context.Trace.Write(Constant.AjaxID, "End ProcessRequest");
						return;
					}

					if(sca.Length > 0)
					{
						if(sca[0].IsCacheEnabled)
						{
							p.Context.Cache.Add(p.Type.FullName + "|" + p.GetHashCode(), result, null, DateTime.Now.Add(sca[0].CacheDuration), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null);
							p.Context.Trace.Write(Constant.AjaxID, "Adding result to cache for " + sca[0].CacheDuration.TotalSeconds + " seconds (HashCode = " + p.GetHashCode().ToString() + ")");
						}
					}

					if(p.Context.Trace.IsEnabled)
					{
						p.Context.Trace.Write(Constant.AjaxID, "Result (maybe encrypted): " + result);
						p.Context.Trace.Write(Constant.AjaxID, "End ProcessRequest");
					}
				}
				catch(Exception ex)
				{
					p.Context.Response.Write(p.SerializeObject(ex));

					if(p.Context.Trace.IsEnabled) p.Context.Trace.Write(Constant.AjaxID, "End ProcessRequest");
					return;
				}
				
			}
			catch(Exception ex)
			{
				p.Context.Response.Write(p.SerializeObject(ex));

				if(p.Context.Trace.IsEnabled) p.Context.Trace.Write(Constant.AjaxID, "End ProcessRequest");
				return;
			}
			finally
			{
				if(token != IntPtr.Zero)
					winctx.Undo();

				if(done != null)
					done();
			}
		}
	}
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?