// gets a RestExtensionMethodInfo matching extensionAlias and methodName
        // by looking at the legacy configuration file
        // returns null if not found
        //
        static RestExtensionMethodInfo GetFromLegacyConfiguration(string extensionAlias, string methodName)
        {
            const string ExtensionXPath = "/RestExtensions/ext [@alias='{0}']";
            const string MethodXPath    = "./permission [@method='{0}']";

            var config = (Configuration.BaseRestSection)System.Configuration.ConfigurationManager.GetSection("BaseRestExtensions");

            if (config == null)
            {
                return(null);                // does not exist
            }
            // fixme - at the moment we reload the config file each time
            //   we have to support live edits of the config file for backward compatibility reason
            //   so if we want to cache, we'd also need to implement a watcher on the config file...

            var doc = new XmlDocument();

            doc.Load(IOHelper.MapPath(SystemFiles.RestextensionsConfig));

            var eNode = doc.SelectSingleNode(string.Format(ExtensionXPath, extensionAlias));

            if (eNode == null)
            {
                return(null);                // does not exist
            }
            var mNode = eNode.SelectSingleNode(string.Format(MethodXPath, methodName));

            if (mNode == null)
            {
                return(null);                // does not exist
            }
            string assemblyName = eNode.Attributes["assembly"].Value;
            var    assembly     = Assembly.Load(assemblyName);

            string typeName = eNode.Attributes["type"].Value;
            Type   type     = assembly.GetType(typeName);

            if (type == null)
            {
                return(null);                // does not exist
            }
            var method = type.GetMethod(methodName);

            if (method == null)
            {
                return(null);                // does not exist
            }
            var allowAll  = GetAttribute(mNode, "allowAll");
            var returnXml = GetAttribute(mNode, "returnXml");

            var info = new RestExtensionMethodInfo(allowAll != null && allowAll.ToLower() == "true",
                                                   GetAttribute(mNode, "allowGroup"), GetAttribute(mNode, "allowType"), GetAttribute(mNode, "allowMember"),
                                                   returnXml == null || returnXml.ToLower() != "false",
                                                   method);

            return(info);
        }
        // gets a RestExtensionMethodInfo matching extensionAlias and methodName
        // by looking for the attributes
        // returns null if not found
        //
        static RestExtensionMethodInfo GetFromAttribute(string extensionAlias, string methodName)
        {
            // here we can cache because any change would trigger an app restart

            string cacheKey = extensionAlias + "." + methodName;

            lock (_cache)
            {
                // if it's in the cache, return
                if (_cache.ContainsKey(cacheKey))
                {
                    return(_cache[cacheKey]);
                }
            }

            // find an extension with that alias, then find a method with that name,
            // which has been properly marked with the attribute, and use the attribute
            // properties to setup a RestExtensionMethodInfo
            //
            // note: the extension may be implemented by more than one class

            var extensions = PluginManager.Current.ResolveRestExtensions()
                             .Where(type => type.GetCustomAttribute <RestExtensionAttribute>(false).Alias == extensionAlias);

            RestExtensionMethodInfo info = null;

            foreach (var extension in extensions) // foreach classes with extension alias
            {
                var method = extension.GetMethod(methodName);
                if (method == null)
                {
                    continue;                 // not implementing the method = ignore
                }
                var attribute = method.GetCustomAttributes(typeof(RestExtensionMethodAttribute), false).Cast <RestExtensionMethodAttribute>().SingleOrDefault();
                if (attribute == null)
                {
                    continue;                    // method has not attribute = ignore
                }
                // got it!
                info = new RestExtensionMethodInfo(attribute.AllowAll,
                                                   attribute.AllowGroup, attribute.AllowType, attribute.AllowMember,
                                                   attribute.ReturnXml,
                                                   method);

                // cache
                lock (_cache)
                {
                    _cache[cacheKey] = info;
                }

                // got it, no need to look any further
                break;
            }

            return(info);
        }
示例#3
0
        // gets a RestExtensionMethodInfo matching extensionAlias and methodName
        // by looking for the attributes
        // returns null if not found
        //
        static RestExtensionMethodInfo GetFromAttribute(string extensionAlias, string methodName)
        {
            // here we can cache because any change would trigger an app restart

            string cacheKey = extensionAlias + "." + methodName;

            lock (_cache)
            {
                // if it's in the cache, return
                if (_cache.ContainsKey(cacheKey))
                {
                    return(_cache[cacheKey]);
                }
            }

            // find an extension with that alias, then find a method with that name,
            // which has been properly marked with the attribute, and use the attribute
            // properties to setup a RestExtensionMethodInfo

            var extensions = PluginManager.Current.ResolveRestExtensions();
            var extension  = extensions
                             .SingleOrDefault(type => type.GetCustomAttribute <RestExtensionAttribute>(false).Alias == extensionAlias);

            RestExtensionMethodInfo info = null;

            if (extension != null)
            {
                var method = extension.GetMethod(methodName);
                if (method != null)
                {
                    var attribute = method.GetCustomAttributes(typeof(RestExtensionMethodAttribute), false).Cast <RestExtensionMethodAttribute>().SingleOrDefault();
                    if (attribute != null)
                    {
                        info = new RestExtensionMethodInfo(attribute.AllowAll,
                                                           attribute.AllowGroup, attribute.AllowType, attribute.AllowMember,
                                                           attribute.ReturnXml,
                                                           method);

                        // looks good, cache
                        lock (_cache)
                        {
                            _cache[cacheKey] = info;
                        }
                    }
                }
            }

            return(info);
        }
        // gets a RestExtensionMethodInfo matching extensionAlias and methodName
        // by looking at the configuration file
        // returns null if not found
        //
        static RestExtensionMethodInfo GetFromConfiguration(string extensionAlias, string methodName)
        {
            var config = (Configuration.BaseRestSection)System.Configuration.ConfigurationManager.GetSection("BaseRestExtensions");

            if (config == null)
            {
                return(null);                // does not exist
            }
            Configuration.ExtensionElement configExtension = config.Items[extensionAlias];
            if (configExtension == null)
            {
                return(null);                // does not exist
            }
            Configuration.MethodElement configMethod = configExtension[methodName];
            if (configMethod == null)
            {
                return(null);                // does not exist
            }
            MethodInfo method;

            try
            {
                var parts = configExtension.Type.Split(',');
                if (parts.Length > 2)
                {
                    throw new Exception(string.Format("Failed to load extension '{0}', invalid type."));
                }

                var assembly = parts.Length == 1 ? Assembly.GetExecutingAssembly() : Assembly.Load(parts[1]);
                var type     = assembly.GetType(parts[0]);
                method = type.GetMethod(methodName);
            }
            catch (Exception e)
            {
                throw new Exception(string.Format("Failed to load extension '{0}', see inner exception.", configExtension.Type), e);
            }

            if (method == null)
            {
                return(null);                // does not exist
            }
            var info = new RestExtensionMethodInfo(configMethod.AllowAll,
                                                   configMethod.AllowGroup, configMethod.AllowType, configMethod.AllowMember,
                                                   configMethod.ReturnXml,
                                                   method);

            return(info);
        }
        // gets a RestExtensionMethodInfo matching extensionAlias and methodName
        // by looking for the attributes
        // returns null if not found
        //
        static RestExtensionMethodInfo GetFromAttribute(string extensionAlias, string methodName, int paramsCount)
        {
            // here we can cache because any change would trigger an app restart

            var cacheKey = string.Format("{0}.{1}[{2}]", extensionAlias, methodName, paramsCount);

            lock (Cache)
            {
                // if it's in the cache, return
                if (Cache.ContainsKey(cacheKey))
                {
                    return(Cache[cacheKey]);
                }
            }

            // find an extension with that alias, then find a method with that name,
            // which has been properly marked with the attribute, and use the attribute
            // properties to setup a RestExtensionMethodInfo
            //
            // note: the extension may be implemented by more than one class

            var extensions = PluginManager.Current.ResolveRestExtensions()
                             .Where(type => type.GetCustomAttribute <RestExtensionAttribute>(false).Alias == extensionAlias);

            RestExtensionMethodInfo info = null;

            foreach (var extension in extensions) // foreach classes with extension alias
            {
                var methods = extension.GetMethods()
                              .Where(m => m.Name == methodName)
                              .Where(m => m.GetParameters().Count() == paramsCount)
                              .ToArray();

                if (methods.Length == 0)
                {
                    continue;                      // not implementing the method = ignore
                }
                if (methods.Length > 1)
                {
                    throw new Exception(string.Format("Method \"{0}\" has many overloads with same number of parameters.", methodName));
                }

                var method = methods[0];
                if (!method.IsPublic || !method.IsStatic)
                {
                    throw new Exception(string.Format("Method \"{0}\" has to be public and static.", methodName));
                }

                var attribute = method.GetCustomAttributes(typeof(RestExtensionMethodAttribute), false).Cast <RestExtensionMethodAttribute>().SingleOrDefault();
                if (attribute == null)
                {
                    continue;                    // method has not attribute = ignore
                }
                // got it!
                info = new RestExtensionMethodInfo(attribute.AllowAll,
                                                   attribute.AllowGroup, attribute.AllowType, attribute.AllowMember,
                                                   attribute.ReturnXml,
                                                   method);

                // cache
                lock (Cache)
                {
                    Cache[cacheKey] = info;
                }

                // got it, no need to look any further
                break;
            }

            return(info);
        }
        // gets a RestExtensionMethodInfo matching extensionAlias and methodName
        // by looking for the legacy attributes
        // returns null if not found
        //
        static RestExtensionMethodInfo GetFromLegacyAttribute(string extensionAlias, string methodName)
        {
            // here we can cache because any change would trigger an app restart anyway

            var cacheKey = extensionAlias + "." + methodName;

            lock (Cache)
            {
                // if it's in the cache, return
                if (Cache.ContainsKey(cacheKey))
                {
                    return(Cache[cacheKey]);
                }
            }

            // find an extension with that alias, then find a method with that name,
            // which has been properly marked with the attribute, and use the attribute
            // properties to setup a RestExtensionMethodInfo

            // note: add #pragma - yes it's obsolete but we still want to support it for the time being

            var extensions = PluginManager.Current.ResolveLegacyRestExtensions()
#pragma warning disable 612,618
                             .Where(type => type.GetCustomAttribute <global::umbraco.presentation.umbracobase.RestExtension>(false).GetAlias() == extensionAlias);

#pragma warning restore 612,618

            RestExtensionMethodInfo info = null;

            foreach (var extension in extensions) // foreach classes with extension alias
            {
                var method = extension.GetMethod(methodName);
                if (method == null)
                {
                    continue;                 // not implementing the method = ignore
                }
#pragma warning disable 612,618
                var attribute = method.GetCustomAttributes(typeof(global::umbraco.presentation.umbracobase.RestExtensionMethod), false).Cast <global::umbraco.presentation.umbracobase.RestExtensionMethod>().SingleOrDefault();
#pragma warning restore 612,618
                if (attribute == null)
                {
                    continue;                    // method has not attribute = ignore
                }
                // got it!
                info = new RestExtensionMethodInfo(attribute.GetAllowAll(),
                                                   attribute.GetAllowGroup(), attribute.GetAllowType(), attribute.GetAllowMember(),
                                                   attribute.returnXml,
                                                   method);

                // cache
                lock (Cache)
                {
                    Cache[cacheKey] = info;
                }

                // got it, no need to look any further
                break;
            }

            return(info);
        }
        // gets a RestExtensionMethodInfo matching extensionAlias and methodName
        // by looking at the configuration file
        // returns null if not found
        //
        static RestExtensionMethodInfo GetFromConfiguration(string extensionAlias, string methodName, int paramsCount)
        {
            var config = Core.Configuration.UmbracoSettings.For <Configuration.BaseRestSection>();

            var configExtension = config.Items[extensionAlias];

            if (configExtension == null)
            {
                return(null);                // does not exist
            }
            var configMethod = configExtension[methodName];

            if (configMethod == null)
            {
                return(null);                // does not exist
            }
            MethodInfo method = null;

            try
            {
                var parts = configExtension.Type.Split(',');
                if (parts.Length > 2)
                {
                    throw new Exception(string.Format("Failed to load extension '{0}', invalid type.", configExtension.Type));
                }

                var assembly = parts.Length == 1 ? Assembly.GetExecutingAssembly() : Assembly.Load(parts[1]);
                var type     = assembly.GetType(parts[0]);

                if (type == null)
                {
                    throw new Exception(string.Format("Could not get type \"{0}\".", parts[0]));
                }

                var methods = type.GetMethods()
                              .Where(m => m.Name == methodName)
                              .Where(m => m.GetParameters().Count() == paramsCount)
                              .ToArray();

                if (methods.Length > 1)
                {
                    throw new Exception(string.Format("Method \"{0}\" has many overloads with same number of parameters.", methodName));
                }

                if (methods.Length > 0)
                {
                    method = methods[0];
                    if (!method.IsPublic || !method.IsStatic)
                    {
                        throw new Exception(string.Format("Method \"{0}\" has to be public and static.", methodName));
                    }
                }
            }
            catch (Exception e)
            {
                throw new Exception(string.Format("Failed to load extension '{0}', see inner exception.", configExtension.Type), e);
            }

            if (method == null)
            {
                return(null);                // does not exist
            }
            var info = new RestExtensionMethodInfo(configMethod.AllowAll,
                                                   configMethod.AllowGroup, configMethod.AllowType, configMethod.AllowMember,
                                                   configMethod.ReturnXml,
                                                   method);

            return(info);
        }
		// gets a RestExtensionMethodInfo matching extensionAlias and methodName
		// by looking at the legacy configuration file
		// returns null if not found
		//
		static RestExtensionMethodInfo GetFromLegacyConfiguration(string extensionAlias, string methodName)
		{
			const string extensionXPath = "/RestExtensions/ext [@alias='{0}']";
			const string methodXPath = "./permission [@method='{0}']";

			var config = (Configuration.BaseRestSection)System.Configuration.ConfigurationManager.GetSection("BaseRestExtensions");

			if (config == null)
				return null; // does not exist

			// note - at the moment we reload the config file each time
			//   we have to support live edits of the config file for backward compatibility reason
			//   so if we want to cache, we'd also need to implement a watcher on the config file...

			var doc = new XmlDocument();
			doc.Load(IOHelper.MapPath(SystemFiles.RestextensionsConfig));

			var eNode = doc.SelectSingleNode(string.Format(extensionXPath, extensionAlias));

			if (eNode == null)
				return null; // does not exist

			var mNode = eNode.SelectSingleNode(string.Format(methodXPath, methodName));

			if (mNode == null)
				return null; // does not exist

		    var attributes = eNode.Attributes;
		    if (attributes == null)
		        return null; // has no attributes

			var assemblyName = attributes["assembly"].Value;
			var assembly = Assembly.Load(assemblyName);

			var typeName = attributes["type"].Value;
			var type = assembly.GetType(typeName);

			if (type == null)
				return null; // does not exist

			var method = type.GetMethod(methodName);

			if (method == null)
				return null; // does not exist

			var allowAll = GetAttribute(mNode, "allowAll");
			var returnXml = GetAttribute(mNode, "returnXml");

			var info = new RestExtensionMethodInfo(allowAll != null && allowAll.ToLower() == "true",
				GetAttribute(mNode, "allowGroup"), GetAttribute(mNode, "allowType"), GetAttribute(mNode, "allowMember"),
				returnXml == null || returnXml.ToLower() != "false",
				method);

			return info;
		}
		// gets a RestExtensionMethodInfo matching extensionAlias and methodName
		// by looking for the attributes
		// returns null if not found
		//
		static RestExtensionMethodInfo GetFromAttribute(string extensionAlias, string methodName, int paramsCount)
		{
			// here we can cache because any change would trigger an app restart

		    var cacheKey = string.Format("{0}.{1}[{2}]", extensionAlias, methodName, paramsCount);
			lock (Cache)
			{
				// if it's in the cache, return
				if (Cache.ContainsKey(cacheKey))
					return Cache[cacheKey];
			}

			// find an extension with that alias, then find a method with that name,
			// which has been properly marked with the attribute, and use the attribute
			// properties to setup a RestExtensionMethodInfo
            //
            // note: the extension may be implemented by more than one class

			var extensions = PluginManager.Current.ResolveRestExtensions()
                .Where(type => type.GetCustomAttribute<RestExtensionAttribute>(false).Alias == extensionAlias);

			RestExtensionMethodInfo info = null;

            foreach (var extension in extensions) // foreach classes with extension alias
            {
                var methods = extension.GetMethods()
                                  .Where(m => m.Name == methodName)
                                  .Where(m => m.GetParameters().Count() == paramsCount)
                                  .ToArray();

                if (methods.Length == 0) continue; // not implementing the method = ignore

                if (methods.Length > 1)
                    throw new Exception(string.Format("Method \"{0}\" has many overloads with same number of parameters.", methodName));

                var method = methods[0];
                if (!method.IsPublic || !method.IsStatic)
                    throw new Exception(string.Format("Method \"{0}\" has to be public and static.", methodName));

                var attribute = method.GetCustomAttributes(typeof(RestExtensionMethodAttribute), false).Cast<RestExtensionMethodAttribute>().SingleOrDefault();
                if (attribute == null) continue; // method has not attribute = ignore

                // got it!
                info = new RestExtensionMethodInfo(attribute.AllowAll,
                                                   attribute.AllowGroup, attribute.AllowType, attribute.AllowMember,
                                                   attribute.ReturnXml,
                                                   method);

                // cache
                lock (Cache)
                {
                    Cache[cacheKey] = info;
                }

                // got it, no need to look any further
                break;
            }

			return info;
		}
		// gets a RestExtensionMethodInfo matching extensionAlias and methodName
		// by looking for the legacy attributes
		// returns null if not found
		//
		static RestExtensionMethodInfo GetFromLegacyAttribute(string extensionAlias, string methodName)
		{
			// here we can cache because any change would trigger an app restart anyway

			var cacheKey = extensionAlias + "." + methodName;
			lock (Cache)
			{
				// if it's in the cache, return
				if (Cache.ContainsKey(cacheKey))
					return Cache[cacheKey];
			}

			// find an extension with that alias, then find a method with that name,
			// which has been properly marked with the attribute, and use the attribute
			// properties to setup a RestExtensionMethodInfo

            // note: add #pragma - yes it's obsolete but we still want to support it for the time being

			var extensions = PluginManager.Current.ResolveLegacyRestExtensions()
#pragma warning disable 612,618
				.Where(type => type.GetCustomAttribute<global::umbraco.presentation.umbracobase.RestExtension>(false).GetAlias() == extensionAlias);
#pragma warning restore 612,618

			RestExtensionMethodInfo info = null;

            foreach (var extension in extensions) // foreach classes with extension alias
			{
				var method = extension.GetMethod(methodName);
                if (method == null) continue; // not implementing the method = ignore

#pragma warning disable 612,618
			    var attribute = method.GetCustomAttributes(typeof(global::umbraco.presentation.umbracobase.RestExtensionMethod), false).Cast<global::umbraco.presentation.umbracobase.RestExtensionMethod>().SingleOrDefault();
#pragma warning restore 612,618
                if (attribute == null) continue; // method has not attribute = ignore

                // got it!
			    info = new RestExtensionMethodInfo(attribute.GetAllowAll(),
			                                       attribute.GetAllowGroup(), attribute.GetAllowType(), attribute.GetAllowMember(),
			                                       attribute.returnXml,
			                                       method);

			    // cache
			    lock (Cache)
			    {
			        Cache[cacheKey] = info;
			    }
            
                // got it, no need to look any further
                break;
            }

			return info;
		}
		// gets a RestExtensionMethodInfo matching extensionAlias and methodName
		// by looking at the configuration file
		// returns null if not found
		//
		static RestExtensionMethodInfo GetFromConfiguration(string extensionAlias, string methodName, int paramsCount)
		{
		    var config = Core.Configuration.UmbracoSettings.For<Configuration.BaseRestSection>();

			var configExtension = config.Items[extensionAlias];
			if (configExtension == null)
				return null; // does not exist

			var configMethod = configExtension[methodName];
			if (configMethod == null)
				return null; // does not exist

			MethodInfo method = null;
			try
			{
				var parts = configExtension.Type.Split(',');
				if (parts.Length > 2)
                    throw new Exception(string.Format("Failed to load extension '{0}', invalid type.", configExtension.Type));

				var assembly = parts.Length == 1 ? Assembly.GetExecutingAssembly() : Assembly.Load(parts[1]);
				var type = assembly.GetType(parts[0]);

			    if (type == null)
			        throw new Exception(string.Format("Could not get type \"{0}\".", parts[0]));
                
                var methods = type.GetMethods()
			                      .Where(m => m.Name == methodName)
			                      .Where(m => m.GetParameters().Count() == paramsCount)
                                  .ToArray();

			    if (methods.Length > 1)
			        throw new Exception(string.Format("Method \"{0}\" has many overloads with same number of parameters.", methodName));

                if (methods.Length > 0)
                {
                    method = methods[0];
                    if (!method.IsPublic || !method.IsStatic)
                        throw new Exception(string.Format("Method \"{0}\" has to be public and static.", methodName));
                }
			}
			catch (Exception e)
			{
				throw new Exception(string.Format("Failed to load extension '{0}', see inner exception.", configExtension.Type), e);
			}

			if (method == null)
				return null; // does not exist

			var info = new RestExtensionMethodInfo(configMethod.AllowAll,
				configMethod.AllowGroup, configMethod.AllowType, configMethod.AllowMember,
				configMethod.ReturnXml,
				method);

			return info;
		}
示例#12
0
        public void ProcessRequest(HttpContext context)
        {
            string url = context.Request.RawUrl;

            // sanitize and split the url
            url = url.Substring(BaseUrl.Length);
            if (url.ToLower().Contains(".aspx"))
            {
                url = url.Substring(0, url.IndexOf(".aspx", StringComparison.OrdinalIgnoreCase));
            }
            if (url.ToLower().Contains("?"))
            {
                url = url.Substring(0, url.IndexOf("?", StringComparison.OrdinalIgnoreCase));
            }
            var urlParts = url.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);

            // by default, return xml content
            context.Response.ContentType = "text/xml";

            // ensure that we have a valid request ie /base/library/method/[parameters].aspx
            if (urlParts.Length < 2)
            {
                context.Response.Write("<error>Invalid request, missing parts.</error>");
                context.Response.StatusCode        = 400;
                context.Response.StatusDescription = "Bad Request";
                context.Response.End();
                return;
            }

            var extensionAlias = urlParts[0];
            var methodName     = urlParts[1];
            var paramsCount    = urlParts.Length - 2;

            var method = RestExtensionMethodInfo.GetMethod(extensionAlias, methodName, paramsCount);

            if (!method.Exists)
            {
                context.Response.StatusCode        = 500;
                context.Response.StatusDescription = "Internal Server Error";
                context.Response.Output.Write("<error>Extension or method not found.</error>");
            }
            else if (!method.CanBeInvokedByCurrentMember)
            {
                context.Response.StatusCode        = 500;
                context.Response.StatusDescription = "Internal Server Error";
                context.Response.Output.Write("<error>Permission denied.</error>");
            }
            else
            {
                if (!method.ReturnXml)
                {
                    context.Response.ContentType = "text/html";
                }

                TrySetCulture();

                var result = method.Invoke(urlParts.Skip(2).ToArray());
                if (result.Length >= 7 && result.Substring(0, 7) == "<error>")
                {
                    context.Response.StatusCode        = 500;
                    context.Response.StatusDescription = "Internal Server Error";
                }
                context.Response.Output.Write(result);
            }

            context.Response.End();
        }
		// gets a RestExtensionMethodInfo matching extensionAlias and methodName
		// by looking for the attributes
		// returns null if not found
		//
		static RestExtensionMethodInfo GetFromAttribute(string extensionAlias, string methodName)
		{
			// here we can cache because any change would trigger an app restart

			string cacheKey = extensionAlias + "." + methodName;
			lock (_cache)
			{
				// if it's in the cache, return
				if (_cache.ContainsKey(cacheKey))
					return _cache[cacheKey];
			}

			// find an extension with that alias, then find a method with that name,
			// which has been properly marked with the attribute, and use the attribute
			// properties to setup a RestExtensionMethodInfo
            //
            // note: the extension may be implemented by more than one class

			var extensions = PluginManager.Current.ResolveRestExtensions()
                .Where(type => type.GetCustomAttribute<RestExtensionAttribute>(false).Alias == extensionAlias);

			RestExtensionMethodInfo info = null;

            foreach (var extension in extensions) // foreach classes with extension alias
            {
                var method = extension.GetMethod(methodName);
                if (method == null) continue; // not implementing the method = ignore

                var attribute = method.GetCustomAttributes(typeof(RestExtensionMethodAttribute), false).Cast<RestExtensionMethodAttribute>().SingleOrDefault();
                if (attribute == null) continue; // method has not attribute = ignore

                // got it!
                info = new RestExtensionMethodInfo(attribute.AllowAll,
                                                   attribute.AllowGroup, attribute.AllowType, attribute.AllowMember,
                                                   attribute.ReturnXml,
                                                   method);

                // cache
                lock (_cache)
                {
                    _cache[cacheKey] = info;
                }

                // got it, no need to look any further
                break;
            }

			return info;
		}
		// gets a RestExtensionMethodInfo matching extensionAlias and methodName
		// by looking at the configuration file
		// returns null if not found
		//
		static RestExtensionMethodInfo GetFromConfiguration(string extensionAlias, string methodName)
		{
			var config = (Configuration.BaseRestSection)System.Configuration.ConfigurationManager.GetSection("BaseRestExtensions");

			if (config == null)
				return null; // does not exist

			Configuration.ExtensionElement configExtension = config.Items[extensionAlias];
			if (configExtension == null)
				return null; // does not exist

			Configuration.MethodElement configMethod = configExtension[methodName];
			if (configMethod == null)
				return null; // does not exist

			MethodInfo method;
			try
			{
				var parts = configExtension.Type.Split(',');
				if (parts.Length > 2)
					throw new Exception(string.Format("Failed to load extension '{0}', invalid type."));

				var assembly = parts.Length == 1 ? Assembly.GetExecutingAssembly() : Assembly.Load(parts[1]);
				var type = assembly.GetType(parts[0]);
				method = type.GetMethod(methodName);
			}
			catch (Exception e)
			{
				throw new Exception(string.Format("Failed to load extension '{0}', see inner exception.", configExtension.Type), e);
			}

			if (method == null)
				return null; // does not exist

			var info = new RestExtensionMethodInfo(configMethod.AllowAll,
				configMethod.AllowGroup, configMethod.AllowType, configMethod.AllowMember,
				configMethod.ReturnXml,
				method);

			return info;
		}
		// gets a RestExtensionMethodInfo matching extensionAlias and methodName
		// by looking for the attributes
		// returns null if not found
		//
		static RestExtensionMethodInfo GetFromAttribute(string extensionAlias, string methodName)
		{
			// here we can cache because any change would trigger an app restart

			string cacheKey = extensionAlias + "." + methodName;
			lock (_cache)
			{
				// if it's in the cache, return
				if (_cache.ContainsKey(cacheKey))
					return _cache[cacheKey];
			}

			// find an extension with that alias, then find a method with that name,
			// which has been properly marked with the attribute, and use the attribute
			// properties to setup a RestExtensionMethodInfo

			var extensions = PluginManager.Current.ResolveRestExtensions();
			var extension = extensions
				.SingleOrDefault(type => type.GetCustomAttribute<RestExtensionAttribute>(false).Alias == extensionAlias);

			RestExtensionMethodInfo info = null;

			if (extension != null)
			{
				var method = extension.GetMethod(methodName);
				if (method != null)
				{
					var attribute = method.GetCustomAttributes(typeof(RestExtensionMethodAttribute), false).Cast<RestExtensionMethodAttribute>().SingleOrDefault();
					if (attribute != null)
					{
						info = new RestExtensionMethodInfo(attribute.AllowAll,
							attribute.AllowGroup, attribute.AllowType, attribute.AllowMember,
							attribute.ReturnXml,
							method);

						// looks good, cache
						lock (_cache)
						{
							_cache[cacheKey] = info;
						}
					}
				}
			}

			return info;
		}