/// <summary>
        /// Generic method to register all routes from a CallbackHandler
        /// that have RouteUrls defined on the [CallbackMethod] attribute
        /// </summary>
        /// <typeparam name="TCallbackHandler"></typeparam>
        /// <param name="routes"></param>
        public static void RegisterRoutes <TCallbackHandler>(RouteCollection routes)
        {
            // find all methods
            var methods = typeof(TCallbackHandler).GetMethods(BindingFlags.Instance | BindingFlags.Public);

            foreach (var method in methods)
            {
                var attrs = method.GetCustomAttributes(typeof(CallbackMethodAttribute), false);
                if (attrs.Length < 1)
                {
                    continue;
                }

                CallbackMethodAttribute attr = attrs[0] as CallbackMethodAttribute;
                if (string.IsNullOrEmpty(attr.RouteUrl))
                {
                    continue;
                }

                // Add the route
                routes.Add(method.Name,
                           new Route(attr.RouteUrl, new CallbackHandlerRouteHandler(method.Name, typeof(TCallbackHandler))));
            }
        }
        /// <summary>
        /// Generic method that handles processing a Callback request by routing to
        /// a method in a provided target object.
        ///
        /// </summary>
        /// <param name="target">The target object that is to be called. If null this is used</param>
        public void ProcessCallbackMethodCall(object target, string methodToCall)
        {
            if (target == null)
            {
                target = this;
            }

            HttpRequest  Request  = HttpContext.Current.Request;
            HttpResponse Response = HttpContext.Current.Response;

            Response.Charset = null;

            CallbackMethodProcessorHelper helper = new CallbackMethodProcessorHelper(this);

            List <string> ParameterList = null;

            string contentType = Request.ContentType.ToLower();


            // check for Route Data method name
            if (string.IsNullOrEmpty(methodToCall) && target is CallbackHandler)
            {
                CallbackHandler chandler = target as CallbackHandler;
                if (chandler.RouteData != null)
                {
                    methodToCall = ((CallbackHandlerRouteHandler)chandler.RouteData.RouteHandler).MethodName;
                }
            }

            // Allow for a single XML object to be POSTed rather than POST variables
            if (contentType.StartsWith(ControlResources.STR_XmlContentType))
            {
                if (string.IsNullOrEmpty(methodToCall))
                {
                    methodToCall = Request.Params["Method"];
                }

                if (string.IsNullOrEmpty(methodToCall))
                {
                    WriteErrorResponse("No method to call specified.", null);
                    return;
                }

                // Pass a Parameter List with our JSON encoded parameters
                ParameterList = new List <string>();

                if (Request.ContentLength > 0L)
                {
                    // Pick up single unencoded JSON parameter
                    string singleParm = UrlUtils.FormBufferToString();

                    if (!string.IsNullOrEmpty(singleParm))
                    {
                        ParameterList.Add(singleParm);
                    }
                }
            }
            // Post AjaxMethodCallback style interface
            else if (contentType.StartsWith(ControlResources.STR_UrlEncodedContentType) && Request.Params["CallbackMethod"] != null)
            {
                // Only pick up the method name - Parameters are parsed out of POST buffer during method calling
                methodToCall = Request.Params["CallbackMethod"];
            }
            else
            {
                if (string.IsNullOrEmpty(methodToCall))
                {
                    methodToCall = Request.QueryString["Method"];
                }

                if (string.IsNullOrEmpty(methodToCall))
                {
                    WriteErrorResponse("No method to call specified.", null);
                    return;
                }
            }

            object Result                = null;
            string StringResult          = null;
            CallbackMethodAttribute attr = new CallbackMethodAttribute();

            try
            {
                if (ParameterList != null)
                {
                    // use the supplied parameter list
                    Result = helper.ExecuteMethod(methodToCall, target, ParameterList.ToArray(),
                                                  CallbackMethodParameterType.Xml, ref attr);
                }
                else
                {
                    // grab the info out of QueryString Values or POST buffer during parameter parsing
                    // for optimization
                    Result = helper.ExecuteMethod(methodToCall, target, null,
                                                  CallbackMethodParameterType.Xml, ref attr);
                }
            }
            catch (Exception ex)
            {
                Exception ActiveException = null;
                if (ex.InnerException != null)
                {
                    ActiveException = ex.InnerException;
                }
                else
                {
                    ActiveException = ex;
                }

                WriteErrorResponse(ActiveException.Message,
                                   (HttpContext.Current.IsDebuggingEnabled ? ex.StackTrace : null));
                return;
            }

            // Special return type handling: Stream, Bitmap, byte[] and raw string results
            // are converted and returned directly
            HandleSpecialReturnTypes(Result, attr, Request, Response);

            // Standard json formatting
            try
            {
                SerializationUtils.SerializeObject(Result, out StringResult);
            }
            catch (Exception ex)
            {
                WriteErrorResponse(ex.Message, HttpContext.Current.IsDebuggingEnabled ? ex.StackTrace : null);
                return;
            }


            // Explicitly set the content type here
            Response.ContentType = ControlResources.STR_XmlContentType;

            Response.Write(StringResult);
            Response.End();
        }
        /// <summary>
        /// This method handles special return types from callback methods
        /// by examining the return type or the ResultFormat query string.
        ///
        /// Checks are performed for:
        /// Stream, Bitmap, byte[] and raw string output
        /// </summary>
        /// <param name="Result"></param>
        /// <param name="callbackAttribute"></param>
        /// <param name="Request"></param>
        /// <param name="Response"></param>
        void HandleSpecialReturnTypes(object Result, CallbackMethodAttribute callbackAttribute, HttpRequest Request, HttpResponse Response)
        {
            string format = (Request.Params["ResultFormat"] ?? "").ToLower();

            if (!string.IsNullOrEmpty(callbackAttribute.ContentType))
            {
                Response.ContentType = callbackAttribute.ContentType;
            }


            // Stream data is just sent back RAW as is. Method code should set ContentType
            if (Result is Stream)
            {
                Stream stream = Result as Stream;
                FileUtils.CopyStream(stream, Response.OutputStream, 4092);
                stream.Close();

                Response.End();
            }
            else if (Result is byte[])
            {
                Response.BinaryWrite(Result as byte[]);
                Response.End();
            }
            else if (Result is Bitmap)
            {
                Bitmap      bm          = Result as Bitmap;
                ImageFormat imageFormat = ImageFormat.Png;

                // if no content type was explicitly specified use bitmap's internal format (loaded from disk or default)
                if (string.IsNullOrEmpty(callbackAttribute.ContentType))
                {
                    Response.ContentType = UrlUtils.ImageFormatToContentType(bm.RawFormat);
                }
                else
                {
                    imageFormat = UrlUtils.ImageFormatFromContentType(callbackAttribute.ContentType);
                }

                if (imageFormat == ImageFormat.Png)
                {
                    // pngs are special and require reloading
                    // or else they won't write to OutputStream
                    bm = new Bitmap(Result as Bitmap);
                    MemoryStream ms = new MemoryStream();
                    bm.Save(ms, imageFormat);
                    ms.WriteTo(Response.OutputStream);
                }
                else
                {
                    bm.Save(Response.OutputStream, imageFormat);
                }

                bm.Dispose();
                ((Bitmap)Result).Dispose();

                Response.End();
            }
            // Raw string result option eith via querystring or CallbackMethod Attribute
            else if ((format == "string" || callbackAttribute.ReturnAsRawString) && Result.GetType() == typeof(string))
            {
                if (!string.IsNullOrEmpty(callbackAttribute.ContentType))
                {
                    Response.ContentType = callbackAttribute.ContentType;
                }

                Response.Write(Result as string);
                Response.End();
            }
        }
        /// <summary>
        /// Executes the requested method. 
        /// to the proper types for execution.
        /// </summary>
        /// <param name="Method"></param>
        /// <param name="methodParameters">An array of the string json parameters to </param>
        /// <param name="target">The object to call the method on</param>
        /// <param name="parameters">An array of json Strings that make up the parameters for the method call. This value can be null in which case parms are parsed out of GET QueryString or POST values</param>
        /// <param name="callbackMethodAttribute">An optional instance of an CallbackAttribute that is set by this method</param>
        /// <returns>the result of the method execution</returns>
        internal object ExecuteMethod(string method, object target, string[] parameters,
                                      CallbackMethodParameterType paramType,
                                      ref CallbackMethodAttribute callbackMethodAttribute)
        {
            HttpRequest Request = HttpContext.Current.Request;
            HttpResponse Response = HttpContext.Current.Response;

            object Result = null;

            // Stores parsed parameters (from string JSON or QUeryString Values)
            object[] adjustedParms = null;

            Type PageType = target.GetType();
            MethodInfo MI = PageType.GetMethod(method, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            if (MI == null)
                throw new InvalidOperationException();

            object[] methods = MI.GetCustomAttributes(typeof(CallbackMethodAttribute), false);
            if (methods.Length < 1)
                throw new InvalidOperationException();

            if (callbackMethodAttribute != null)
                callbackMethodAttribute = methods[0] as CallbackMethodAttribute;

            // Check for supported HTTP Verbs
            if (callbackMethodAttribute.AllowedHttpVerbs != HttpVerbs.All &&
                !string.IsNullOrEmpty(Request.HttpMethod))
            {
                HttpVerbs val = HttpVerbs.None;
                Enum.TryParse<HttpVerbs>(Request.HttpMethod, out val);
                if (val == HttpVerbs.None || !callbackMethodAttribute.AllowedHttpVerbs.HasFlag(val))
                {
                    Response.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
                    Response.StatusDescription = string.Format("NotAllowedMethodExpectsVerb");
                    throw new UnauthorizedAccessException(Response.StatusDescription);
                }
            }

            ParameterInfo[] parms = MI.GetParameters();

            JSONSerializer serializer = new JSONSerializer();

            RouteData routeData = null;
            if (target is CallbackHandler)
                routeData = ((CallbackHandler)target).RouteData;

            int parmCounter = 0;
            adjustedParms = new object[parms.Length];
            foreach (ParameterInfo parameter in parms)
            {
                // Retrieve parameters out of QueryString or POST buffer
                if (parameters == null)
                {
                    // look for parameters in the route
                    if (routeData != null)
                    {
                        string parmString = routeData.Values[parameter.Name] as string;
                        adjustedParms[parmCounter] = ReflectionUtils.StringToTypedValue(parmString, parameter.ParameterType);
                    }
                    // GET parameter are parsed as plain string values - no JSON encoding
                    else if (HttpContext.Current.Request.HttpMethod == "GET")
                    {
                        // Look up the parameter by name
                        string parmString = Request.QueryString[parameter.Name];
                        adjustedParms[parmCounter] = ReflectionUtils.StringToTypedValue(parmString, parameter.ParameterType);
                    }
                    // POST parameters are treated as methodParameters that are JSON encoded
                    else
                        if (paramType == CallbackMethodParameterType.Json)
                            //string newVariable = methodParameters.GetValue(parmCounter) as string;
                            adjustedParms[parmCounter] = serializer.Deserialize(Request.Params["parm" + (parmCounter + 1).ToString()], parameter.ParameterType);
                        else
                            adjustedParms[parmCounter] = SerializationUtils.DeSerializeObject(
                                Request.Params["parm" + (parmCounter + 1).ToString()],
                                parameter.ParameterType);
                }
                else
                    if (paramType == CallbackMethodParameterType.Json)
                        adjustedParms[parmCounter] = serializer.Deserialize(parameters[parmCounter], parameter.ParameterType);
                    else
                        adjustedParms[parmCounter] = SerializationUtils.DeSerializeObject(parameters[parmCounter], parameter.ParameterType);

                parmCounter++;
            }

            Result = MI.Invoke(target, adjustedParms);

            return Result;
        }
        /// <summary>
        /// Generic method that handles processing a Callback request by routing to
        /// a method in a provided target object.
        /// 
        /// </summary>
        /// <param name="target">The target object that is to be called. If null this is used</param>
        public void ProcessCallbackMethodCall(object target, string methodToCall)
        {
            if (target == null)
                target = this;

            HttpRequest Request = HttpContext.Current.Request;
            HttpResponse Response = HttpContext.Current.Response;
            Response.Charset = null;

            CallbackMethodProcessorHelper helper = new CallbackMethodProcessorHelper(this);

            List<string> ParameterList = null;

            string contentType = Request.ContentType.ToLower();


            // check for Route Data method name
            if (string.IsNullOrEmpty(methodToCall) && target is CallbackHandler)
            {
                CallbackHandler chandler = target as CallbackHandler;
                if (chandler.RouteData != null)
                    methodToCall = ((CallbackHandlerRouteHandler)chandler.RouteData.RouteHandler).MethodName;
            }

            // Allow for a single XML object to be POSTed rather than POST variables
            if (contentType.StartsWith(ControlResources.STR_XmlContentType))
            {
                if (string.IsNullOrEmpty(methodToCall))
                    methodToCall = Request.Params["Method"];

                if (string.IsNullOrEmpty(methodToCall))
                {
                    WriteErrorResponse("No method to call specified.", null);
                    return;
                }

                // Pass a Parameter List with our JSON encoded parameters
                ParameterList = new List<string>();

                if (Request.ContentLength > 0L)
                {
                    // Pick up single unencoded JSON parameter
                    string singleParm = UrlUtils.FormBufferToString();

                    if (!string.IsNullOrEmpty(singleParm))
                        ParameterList.Add(singleParm);
                }
            }
            // Post AjaxMethodCallback style interface            
            else if (contentType.StartsWith(ControlResources.STR_UrlEncodedContentType) && Request.Params["CallbackMethod"] != null)
                // Only pick up the method name - Parameters are parsed out of POST buffer during method calling
                methodToCall = Request.Params["CallbackMethod"];
            else
            {
                if (string.IsNullOrEmpty(methodToCall))
                    methodToCall = Request.QueryString["Method"];

                if (string.IsNullOrEmpty(methodToCall))
                {
                    WriteErrorResponse("No method to call specified.", null);
                    return;
                }
            }

            object Result = null;
            string StringResult = null;
            CallbackMethodAttribute attr = new CallbackMethodAttribute();
            try
            {
                if (ParameterList != null)
                    // use the supplied parameter list
                    Result = helper.ExecuteMethod(methodToCall, target, ParameterList.ToArray(),
                                                  CallbackMethodParameterType.Xml, ref attr);
                else
                    // grab the info out of QueryString Values or POST buffer during parameter parsing 
                    // for optimization
                    Result = helper.ExecuteMethod(methodToCall, target, null,
                                                  CallbackMethodParameterType.Xml, ref attr);
            }
            catch (Exception ex)
            {
                Exception ActiveException = null;
                if (ex.InnerException != null)
                    ActiveException = ex.InnerException;
                else
                    ActiveException = ex;

                WriteErrorResponse(ActiveException.Message,
                                  (HttpContext.Current.IsDebuggingEnabled ? ex.StackTrace : null));
                return;
            }

            // Special return type handling: Stream, Bitmap, byte[] and raw string results
            // are converted and returned directly
            HandleSpecialReturnTypes(Result, attr, Request, Response);

            // Standard json formatting            
            try
            {
                SerializationUtils.SerializeObject(Result, out StringResult);
            }
            catch (Exception ex)
            {
                WriteErrorResponse(ex.Message, HttpContext.Current.IsDebuggingEnabled ? ex.StackTrace : null);
                return;
            }


            // Explicitly set the content type here
            Response.ContentType = ControlResources.STR_XmlContentType;

            Response.Write(StringResult);
            Response.End();
        }
        /// <summary>
        /// This method handles special return types from callback methods
        /// by examining the return type or the ResultFormat query string.
        /// 
        /// Checks are performed for:
        /// Stream, Bitmap, byte[] and raw string output
        /// </summary>
        /// <param name="Result"></param>
        /// <param name="callbackAttribute"></param>
        /// <param name="Request"></param>
        /// <param name="Response"></param>
        void HandleSpecialReturnTypes(object Result, CallbackMethodAttribute callbackAttribute, HttpRequest Request, HttpResponse Response)
        {
            string format = (Request.Params["ResultFormat"] ?? "").ToLower();

            if (!string.IsNullOrEmpty(callbackAttribute.ContentType))
                Response.ContentType = callbackAttribute.ContentType;


            // Stream data is just sent back RAW as is. Method code should set ContentType
            if (Result is Stream)
            {
                Stream stream = Result as Stream;
                FileUtils.CopyStream(stream, Response.OutputStream, 4092);
                stream.Close();

                Response.End();
            }
            else if (Result is byte[])
            {
                Response.BinaryWrite(Result as byte[]);
                Response.End();
            }
            else if (Result is Bitmap)
            {
                Bitmap bm = Result as Bitmap;
                ImageFormat imageFormat = ImageFormat.Png;

                // if no content type was explicitly specified use bitmap's internal format (loaded from disk or default)
                if (string.IsNullOrEmpty(callbackAttribute.ContentType))
                    Response.ContentType = UrlUtils.ImageFormatToContentType(bm.RawFormat);
                else
                    imageFormat = UrlUtils.ImageFormatFromContentType(callbackAttribute.ContentType);

                if (imageFormat == ImageFormat.Png)
                {
                    // pngs are special and require reloading
                    // or else they won't write to OutputStream
                    bm = new Bitmap(Result as Bitmap);
                    MemoryStream ms = new MemoryStream();
                    bm.Save(ms, imageFormat);
                    ms.WriteTo(Response.OutputStream);
                }
                else
                    bm.Save(Response.OutputStream, imageFormat);

                bm.Dispose();
                ((Bitmap)Result).Dispose();

                Response.End();
            }
            // Raw string result option eith via querystring or CallbackMethod Attribute
            else if ((format == "string" || callbackAttribute.ReturnAsRawString) && Result.GetType() == typeof(string))
            {
                if (!string.IsNullOrEmpty(callbackAttribute.ContentType))
                    Response.ContentType = callbackAttribute.ContentType;

                Response.Write(Result as string);
                Response.End();
            }
        }
        /// <summary>
        /// Executes the requested method.
        /// to the proper types for execution.
        /// </summary>
        /// <param name="Method"></param>
        /// <param name="methodParameters">An array of the string json parameters to </param>
        /// <param name="target">The object to call the method on</param>
        /// <param name="parameters">An array of json Strings that make up the parameters for the method call. This value can be null in which case parms are parsed out of GET QueryString or POST values</param>
        /// <param name="callbackMethodAttribute">An optional instance of an CallbackAttribute that is set by this method</param>
        /// <returns>the result of the method execution</returns>
        internal object ExecuteMethod(string method, object target, string[] parameters,
                                      CallbackMethodParameterType paramType,
                                      ref CallbackMethodAttribute callbackMethodAttribute)
        {
            HttpRequest  Request  = HttpContext.Current.Request;
            HttpResponse Response = HttpContext.Current.Response;

            object Result = null;

            // Stores parsed parameters (from string JSON or QUeryString Values)
            object[] adjustedParms = null;

            Type       PageType = target.GetType();
            MethodInfo MI       = PageType.GetMethod(method, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

            if (MI == null)
            {
                throw new InvalidOperationException();
            }

            object[] methods = MI.GetCustomAttributes(typeof(CallbackMethodAttribute), false);
            if (methods.Length < 1)
            {
                throw new InvalidOperationException();
            }

            if (callbackMethodAttribute != null)
            {
                callbackMethodAttribute = methods[0] as CallbackMethodAttribute;
            }

            // Check for supported HTTP Verbs
            if (callbackMethodAttribute.AllowedHttpVerbs != HttpVerbs.All &&
                !string.IsNullOrEmpty(Request.HttpMethod))
            {
                HttpVerbs val = HttpVerbs.None;
                Enum.TryParse <HttpVerbs>(Request.HttpMethod, out val);
                if (val == HttpVerbs.None || !callbackMethodAttribute.AllowedHttpVerbs.HasFlag(val))
                {
                    Response.StatusCode        = (int)HttpStatusCode.MethodNotAllowed;
                    Response.StatusDescription = string.Format("NotAllowedMethodExpectsVerb");
                    throw new UnauthorizedAccessException(Response.StatusDescription);
                }
            }

            ParameterInfo[] parms = MI.GetParameters();

            JSONSerializer serializer = new JSONSerializer();

            RouteData routeData = null;

            if (target is CallbackHandler)
            {
                routeData = ((CallbackHandler)target).RouteData;
            }

            int parmCounter = 0;

            adjustedParms = new object[parms.Length];
            foreach (ParameterInfo parameter in parms)
            {
                // Retrieve parameters out of QueryString or POST buffer
                if (parameters == null)
                {
                    // look for parameters in the route
                    if (routeData != null)
                    {
                        string parmString = routeData.Values[parameter.Name] as string;
                        adjustedParms[parmCounter] = ReflectionUtils.StringToTypedValue(parmString, parameter.ParameterType);
                    }
                    // GET parameter are parsed as plain string values - no JSON encoding
                    else if (HttpContext.Current.Request.HttpMethod == "GET")
                    {
                        // Look up the parameter by name
                        string parmString = Request.QueryString[parameter.Name];
                        adjustedParms[parmCounter] = ReflectionUtils.StringToTypedValue(parmString, parameter.ParameterType);
                    }
                    // POST parameters are treated as methodParameters that are JSON encoded
                    else
                    if (paramType == CallbackMethodParameterType.Json)
                    {
                        //string newVariable = methodParameters.GetValue(parmCounter) as string;
                        adjustedParms[parmCounter] = serializer.Deserialize(Request.Params["parm" + (parmCounter + 1).ToString()], parameter.ParameterType);
                    }
                    else
                    {
                        adjustedParms[parmCounter] = SerializationUtils.DeSerializeObject(
                            Request.Params["parm" + (parmCounter + 1).ToString()],
                            parameter.ParameterType);
                    }
                }
                else
                if (paramType == CallbackMethodParameterType.Json)
                {
                    adjustedParms[parmCounter] = serializer.Deserialize(parameters[parmCounter], parameter.ParameterType);
                }
                else
                {
                    adjustedParms[parmCounter] = SerializationUtils.DeSerializeObject(parameters[parmCounter], parameter.ParameterType);
                }

                parmCounter++;
            }

            Result = MI.Invoke(target, adjustedParms);

            return(Result);
        }
示例#8
0
        /// <summary>
        /// Generic method that handles processing a Callback request by routing to
        /// a method in a provided target object.
        ///
        /// </summary>
        /// <param name="target">The target object that is to be called. If null this is used</param>
        public void ProcessCallbackMethodCall(object target, string methodToCall)
        {
            if (target == null)
            {
                target = this;
            }

            HttpRequest  Request  = HttpContext.Current.Request;
            HttpResponse Response = HttpContext.Current.Response;

            Response.Charset = null;

            // check for Route Data method name
            if (target is CallbackHandler)
            {
                var routeData = ((CallbackHandler)target).RouteData;
                if (routeData != null)
                {
                    methodToCall = ((CallbackHandlerRouteHandler)routeData.RouteHandler).MethodName;
                }
            }

            CallbackMethodProcessorHelper helper = new CallbackMethodProcessorHelper(this);

            List <string> parameterList = null;

            string contentType = Request.ContentType.ToLower();

            // Allow for a single JSON object to be POSTed rather than POST variables
            if (contentType.StartsWith(ControlResources.STR_JavaScriptContentType) ||
                contentType.StartsWith(ControlResources.STR_JsonContentType))
            {
                if (string.IsNullOrEmpty(methodToCall))
                {
                    methodToCall = Request.Params["Method"];
                }

                if (string.IsNullOrEmpty(methodToCall))
                {
                    WriteErrorResponse("No method to call specified.", null);
                    return;
                }

                // Pass a Parameter List with our JSON encoded parameters
                parameterList = new List <string>();

                if (Request.ContentLength > 0L)
                {
                    // Pick up single unencoded JSON parameter
                    StreamReader sr         = new StreamReader(Request.InputStream);
                    string       singleParm = sr.ReadToEnd();
                    sr.Close();
                    sr.Dispose();

                    if (!string.IsNullOrEmpty(singleParm))
                    {
                        parameterList.Add(singleParm);
                    }
                }
            }
            // Post AjaxMethodCallback style interface
            else if (contentType.StartsWith(ControlResources.STR_UrlEncodedContentType) && Request.Params["CallbackMethod"] != null)
            {
                // Only pick up the method name - Parameters are parsed out of POST buffer during method calling
                methodToCall = Request.Params["CallbackMethod"];
            }
            else
            {
                JsonPMethod = Request.QueryString["jsonp"] ?? Request.QueryString["callback"];

                // Check for querystring method parameterList
                if (string.IsNullOrEmpty(methodToCall))
                {
                    methodToCall = Request.QueryString["Method"];
                }

                // No method - no can do
                if (string.IsNullOrEmpty(methodToCall))
                {
                    WriteErrorResponse("No method to call specified.", null);
                    return;
                }
            }

            // Explicitly set the content type here - set here so the method
            // can override it if it so desires
            Response.ContentType = ControlResources.STR_JsonContentType;

            object result                = null;
            string stringResult          = null;
            CallbackMethodAttribute attr = new CallbackMethodAttribute();

            try
            {
                if (parameterList != null)
                {
                    // use the supplied parameter list
                    result = helper.ExecuteMethod(methodToCall, target, parameterList.ToArray(),
                                                  CallbackMethodParameterType.Json, ref attr);
                }
                else
                {
                    // grab the info out of QueryString Values or POST buffer during parameter parsing
                    // for optimization
                    result = helper.ExecuteMethod(methodToCall, target, null,
                                                  CallbackMethodParameterType.Json, ref attr);
                }
            }
            catch (Exception ex)
            {
                Exception activeException = DebugUtils.GetInnerMostException(ex);
                WriteErrorResponse(activeException.Message,
                                   (HttpContext.Current.IsDebuggingEnabled ? ex.StackTrace : null));
                return;
            }

            // Special return type handling: Stream, Bitmap, byte[] and raw string results
            // are converted and returned directly
            HandleSpecialReturnTypes(result, attr, Request, Response);

            // Standard json formatting
            try
            {
                JSONSerializer Serializer = new JSONSerializer();
                Serializer.DateSerializationMode = JsonDateEncoding;

                // In debug mode show nicely formatted JSON
                // In release normal packed JSON is used
                if (HttpContext.Current.IsDebuggingEnabled)
                {
                    Serializer.FormatJsonOutput = true;
                }

                stringResult = Serializer.Serialize(result);
            }
            catch (Exception ex)
            {
                WriteErrorResponse(ex.Message, HttpContext.Current.IsDebuggingEnabled ? ex.StackTrace : null);
                return;
            }


            if (!string.IsNullOrEmpty(JsonPMethod))
            {
                stringResult = JsonPMethod + "( " + stringResult + " );";
            }

            Response.Write(stringResult);
            Response.End();
        }
        /// <summary>
        /// Generic method that handles processing a Callback request by routing to
        /// a method in a provided target object.
        /// 
        /// </summary>
        /// <param name="target">The target object that is to be called. If null this is used</param>
        public void ProcessCallbackMethodCall(object target, string methodToCall)
        {
            if (target == null)
                target = this;

            HttpRequest Request = HttpContext.Current.Request;
            HttpResponse Response = HttpContext.Current.Response;
            Response.Charset = null;

            // check for Route Data method name
            if (target is CallbackHandler)
            {
                var routeData = ((CallbackHandler)target).RouteData;
                if (routeData != null)
                    methodToCall = ((CallbackHandlerRouteHandler)routeData.RouteHandler).MethodName;
            }

            CallbackMethodProcessorHelper helper = new CallbackMethodProcessorHelper(this);

            List<string> parameterList = null;

            string contentType = Request.ContentType.ToLower();

            // Allow for a single JSON object to be POSTed rather than POST variables
            if (contentType.StartsWith(ControlResources.STR_JavaScriptContentType) ||
                contentType.StartsWith(ControlResources.STR_JsonContentType))
            {
                if (string.IsNullOrEmpty(methodToCall))
                    methodToCall = Request.Params["Method"];

                if (string.IsNullOrEmpty(methodToCall))
                {
                    WriteErrorResponse("No method to call specified.", null);
                    return;
                }

                // Pass a Parameter List with our JSON encoded parameters
                parameterList = new List<string>();

                if (Request.ContentLength > 0L)
                {
                    // Pick up single unencoded JSON parameter
                    StreamReader sr = new StreamReader(Request.InputStream);
                    string singleParm = sr.ReadToEnd();
                    sr.Close();
                    sr.Dispose();

                    if (!string.IsNullOrEmpty(singleParm))
                        parameterList.Add(singleParm);
                }
            }
            // Post AjaxMethodCallback style interface            
            else if (contentType.StartsWith(ControlResources.STR_UrlEncodedContentType) && Request.Params["CallbackMethod"] != null)
                // Only pick up the method name - Parameters are parsed out of POST buffer during method calling
                methodToCall = Request.Params["CallbackMethod"];
            else
            {
                JsonPMethod = Request.QueryString["jsonp"] ?? Request.QueryString["callback"];

                // Check for querystring method parameterList
                if (string.IsNullOrEmpty(methodToCall))
                    methodToCall = Request.QueryString["Method"];

                // No method - no can do
                if (string.IsNullOrEmpty(methodToCall))
                {
                    WriteErrorResponse("No method to call specified.", null);
                    return;
                }
            }

            // Explicitly set the content type here - set here so the method 
            // can override it if it so desires
            Response.ContentType = ControlResources.STR_JsonContentType;

            object result = null;
            string stringResult = null;
            CallbackMethodAttribute attr = new CallbackMethodAttribute();
            try
            {
                if (parameterList != null)
                    // use the supplied parameter list
                    result = helper.ExecuteMethod(methodToCall, target, parameterList.ToArray(),
                                        CallbackMethodParameterType.Json, ref attr);
                else
                    // grab the info out of QueryString Values or POST buffer during parameter parsing 
                    // for optimization
                    result = helper.ExecuteMethod(methodToCall, target, null,
                                                  CallbackMethodParameterType.Json, ref attr);
            }
            catch (Exception ex)
            {
                Exception activeException = DebugUtils.GetInnerMostException(ex);
                WriteErrorResponse(activeException.Message,
                                  (HttpContext.Current.IsDebuggingEnabled ? ex.StackTrace : null));
                return;
            }

            // Special return type handling: Stream, Bitmap, byte[] and raw string results
            // are converted and returned directly
            HandleSpecialReturnTypes(result, attr, Request, Response);

            // Standard json formatting            
            try
            {
                JSONSerializer Serializer = new JSONSerializer();
                Serializer.DateSerializationMode = JsonDateEncoding;

                // In debug mode show nicely formatted JSON 
                // In release normal packed JSON is used
                if (HttpContext.Current.IsDebuggingEnabled)
                    Serializer.FormatJsonOutput = true;

                stringResult = Serializer.Serialize(result);
            }
            catch (Exception ex)
            {
                WriteErrorResponse(ex.Message, HttpContext.Current.IsDebuggingEnabled ? ex.StackTrace : null);
                return;
            }


            if (!string.IsNullOrEmpty(JsonPMethod))
                stringResult = JsonPMethod + "( " + stringResult + " );";

            Response.Write(stringResult);
            Response.End();
        }