From ea8ff709c2fde5fa659a3bccb7a528f7e0497fa2 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 20 Sep 2012 14:37:23 -0200 Subject: [PATCH] further refactor base/rest service into Umbraco.Web --- src/Umbraco.Tests/PluginManagerTests.cs | 18 +- src/Umbraco.Web.UI/Web.config | 8 +- .../web.Template.NILSJO.Debug.config | 2 +- src/Umbraco.Web/BaseRest/BaseRestHandler.cs | 122 +++++++ src/Umbraco.Web/BaseRest/MemberRest.cs | 160 ++++++++ .../BaseRest/RestExtensionAttribute.cs | 18 + .../BaseRest/RestExtensionMethodAttribute.cs | 23 ++ .../BaseRest/RestExtensionMethodInfo.cs | 344 ++++++++++++++++++ src/Umbraco.Web/BaseRestHandler.cs | 218 ----------- src/Umbraco.Web/PluginManagerExtensions.cs | 16 +- src/Umbraco.Web/Umbraco.Web.csproj | 6 +- src/Umbraco.Web/UmbracoModule.cs | 4 +- .../WebServices/FolderBrowserService.cs | 6 +- .../umbracobase/attributes/RestExtension.cs | 1 + .../attributes/RestExtensionMethod.cs | 1 + .../umbracobase/restExtension.cs | 1 + 16 files changed, 712 insertions(+), 236 deletions(-) create mode 100644 src/Umbraco.Web/BaseRest/BaseRestHandler.cs create mode 100644 src/Umbraco.Web/BaseRest/MemberRest.cs create mode 100644 src/Umbraco.Web/BaseRest/RestExtensionAttribute.cs create mode 100644 src/Umbraco.Web/BaseRest/RestExtensionMethodAttribute.cs create mode 100644 src/Umbraco.Web/BaseRest/RestExtensionMethodInfo.cs delete mode 100644 src/Umbraco.Web/BaseRestHandler.cs diff --git a/src/Umbraco.Tests/PluginManagerTests.cs b/src/Umbraco.Tests/PluginManagerTests.cs index 6fe4525cf0..4bc0485bc9 100644 --- a/src/Umbraco.Tests/PluginManagerTests.cs +++ b/src/Umbraco.Tests/PluginManagerTests.cs @@ -11,7 +11,6 @@ using umbraco.MacroEngines.Iron; using umbraco.businesslogic; using umbraco.cms.businesslogic; using umbraco.editorControls; -using umbraco.presentation.umbracobase; using umbraco.uicontrols; using umbraco.cms; @@ -128,6 +127,13 @@ namespace Umbraco.Tests Assert.AreEqual(2, types.Count()); } + [Test] + public void Resolves_LegacyRestExtensions() + { + var types = PluginManager.Current.ResolveLegacyRestExtensions(); + Assert.AreEqual(1, types.Count()); + } + [Test] public void Resolves_XsltExtensions() { @@ -141,12 +147,18 @@ namespace Umbraco.Tests } - [RestExtension("Blah")] - public class MyRestExtension + [umbraco.presentation.umbracobase.RestExtension("Blah")] + public class MyLegacyRestExtension { } + [Umbraco.Web.BaseRest.RestExtension("Blah")] + public class MyRestExtesion + { + + } + public interface IFindMe { diff --git a/src/Umbraco.Web.UI/Web.config b/src/Umbraco.Web.UI/Web.config index aa7e19c746..29683c3913 100644 --- a/src/Umbraco.Web.UI/Web.config +++ b/src/Umbraco.Web.UI/Web.config @@ -33,12 +33,12 @@ - - + + - - + + diff --git a/src/Umbraco.Web.UI/web.Template.NILSJO.Debug.config b/src/Umbraco.Web.UI/web.Template.NILSJO.Debug.config index a54f05ac1e..93d55e4563 100644 --- a/src/Umbraco.Web.UI/web.Template.NILSJO.Debug.config +++ b/src/Umbraco.Web.UI/web.Template.NILSJO.Debug.config @@ -19,7 +19,7 @@ + value="4.10.0"/> diff --git a/src/Umbraco.Web/BaseRest/BaseRestHandler.cs b/src/Umbraco.Web/BaseRest/BaseRestHandler.cs new file mode 100644 index 0000000000..d3e6dc6a89 --- /dev/null +++ b/src/Umbraco.Web/BaseRest/BaseRestHandler.cs @@ -0,0 +1,122 @@ +using System; +using System.Web; +using System.Web.SessionState; +using System.Reflection; +using System.Xml; +using System.IO; +using System.Linq; + +namespace Umbraco.Web.BaseRest +{ + internal class BaseRestHandler : IHttpHandler, IRequiresSessionState + { + static string _baseUrl; + + static BaseRestHandler() + { + _baseUrl = UriUtility.ToAbsolute(Umbraco.Core.IO.SystemDirectories.Base).ToLower(); + if (!_baseUrl.EndsWith("/")) + _baseUrl += "/"; + } + + public bool IsReusable + { + get { return true; } + } + + /// + /// Returns a value indicating whether a specified Uri should be routed to the BaseRestHandler. + /// + /// The specified Uri. + /// A value indicating whether the specified Uri should be routed to the BaseRestHandler. + public static bool IsBaseRestRequest(Uri uri) + { + return Umbraco.Core.Configuration.UmbracoSettings.EnableBaseRestHandler + && uri.AbsolutePath.ToLowerInvariant().StartsWith(_baseUrl); + } + + 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")); + if (url.ToLower().Contains("?")) + url = url.Substring(0, url.IndexOf("?")); + var urlParts = url.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + + // by default, return xml content + context.Response.ContentType = "text/xml"; + + // ensure that we have a valid request ie /base/library/method/[parameter].aspx + if (urlParts.Length < 2) + { + context.Response.Write("Invalid request, missing parts."); + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + return; + } + + string extensionAlias = urlParts[0]; + string methodName = urlParts[1]; + + var method = RestExtensionMethodInfo.GetMethod(extensionAlias, methodName); + + if (!method.Exists) + { + context.Response.StatusCode = 500; + context.Response.StatusDescription = "Internal Server Error"; + context.Response.Output.Write("Extension or method not found."); + } + else if (!method.CanBeInvokedByCurrentMember) + { + context.Response.StatusCode = 500; + context.Response.StatusDescription = "Internal Server Error"; + context.Response.Output.Write("Permission denied."); + } + else + { + if (!method.ReturnXml) + context.Response.ContentType = "text/html"; + + TrySetCulture(); + + string result = method.Invoke(urlParts.Skip(2).ToArray()); + if (result.Length >= 7 && result.Substring(0, 7) == "") + { + context.Response.StatusCode = 500; + context.Response.StatusDescription = "Internal Server Error"; + } + context.Response.Output.Write(result); + } + + context.Response.End(); + } + + #region from baseHttpModule.cs + + // fixme - is this ok? + + private static void TrySetCulture() + { + string domain = HttpContext.Current.Request.Url.Host; // host only + if (TrySetCulture(domain)) return; + + domain = HttpContext.Current.Request.Url.Authority; // host with port + if (TrySetCulture(domain)) return; + } + + private static bool TrySetCulture(string domain) + { + var uDomain = global::umbraco.cms.businesslogic.web.Domain.GetDomain(domain); + if (uDomain == null) return false; + System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(uDomain.Language.CultureAlias); + return true; + } + + #endregion + } +} diff --git a/src/Umbraco.Web/BaseRest/MemberRest.cs b/src/Umbraco.Web/BaseRest/MemberRest.cs new file mode 100644 index 0000000000..07f41504c4 --- /dev/null +++ b/src/Umbraco.Web/BaseRest/MemberRest.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.XPath; + +using umbraco.cms.businesslogic; +using umbraco.cms.businesslogic.member; +using umbraco.cms.businesslogic.property; + +namespace Umbraco.Web.BaseRest +{ + public class MemberRest + { + public static int GetCurrentMemberId() + { + return Member.CurrentMemberId(); + } + + public static Member GetCurrentMember() + { + return Member.GetCurrentMember(); + } + + public static int Login(string login, string password) + { + Member m = Member.GetMemberFromLoginNameAndPassword(login, password); + var id = GetCurrentMemberId(); + if (id == 0) + { + if (m == null) + { + return 0; + } + else + { + Member.AddMemberToCache(m); + return m.Id; + } + } + else + { + return id; + } + } + + [Obsolete("Use Login(login, password).", false)] + public static int login(string loginname, string password) + { + return Login(loginname, password); + } + + public static int Logout() + { + var currentId = GetCurrentMemberId(); + if (currentId > 0) + { + Member.RemoveMemberFromCache(currentId); + Member.ClearMemberFromClient(currentId); + return currentId; + } + else + { + return 0; + } + } + + [Obsolete("Use Logout().", false)] + public static int logout(int NodeId) + { + return Logout(); + } + + [Obsolete("Use Logout().", false)] + public static int logout() + { + return Logout(); + } + + public static XPathNodeIterator Data() + { + var m = GetCurrentMember(); + if (m != null) + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(m.ToXml(doc, false).OuterXml); + XPathNavigator nav = doc.CreateNavigator(); + return nav.Select("/node"); + } + else + { + return null; + } + } + + [Obsolete("Use Data().", false)] + public static XPathNodeIterator data() + { + return Data(); + } + + [Obsolete("Use GetCurrentMemberId().", false)] + public static int id() + { + return GetCurrentMemberId(); + } + + public static string SetProperty(string alias, object value) + { + string ret = "False"; + + try + { + var m = GetCurrentMember(); + + if (m != null) + { + var prop = m.getProperty(alias); + + if (m.ContentType != null && MemberType.GetByAlias(m.ContentType.Alias).MemberCanEdit(prop.PropertyType)) + { + + if (prop.PropertyType.ValidationRegExp.Trim() != "") + { + Regex regex = new Regex(m.getProperty(alias).PropertyType.ValidationRegExp); + + if (regex.IsMatch(value.ToString())) + { + prop.Value = value; + ret = "True"; + m.XmlGenerate(new XmlDocument()); + } + } + else + { + prop.Value = value; + ret = "True"; + m.XmlGenerate(new XmlDocument()); + } + + } + } + } + catch (Exception e) + { + ret = e.Message; + } + + return ret; + } + + [Obsolete("Use SetProperty(alias, value).", false)] + public static string setProperty(string alias, object value) + { + return SetProperty(alias, value); + } + } +} diff --git a/src/Umbraco.Web/BaseRest/RestExtensionAttribute.cs b/src/Umbraco.Web/BaseRest/RestExtensionAttribute.cs new file mode 100644 index 0000000000..fa840388bb --- /dev/null +++ b/src/Umbraco.Web/BaseRest/RestExtensionAttribute.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Umbraco.Web.BaseRest +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] + public class RestExtensionAttribute : Attribute + { + public string Alias { get; private set; } + + public RestExtensionAttribute(string alias) + { + this.Alias = alias; + } + } +} diff --git a/src/Umbraco.Web/BaseRest/RestExtensionMethodAttribute.cs b/src/Umbraco.Web/BaseRest/RestExtensionMethodAttribute.cs new file mode 100644 index 0000000000..7d21c08d58 --- /dev/null +++ b/src/Umbraco.Web/BaseRest/RestExtensionMethodAttribute.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Umbraco.Web.BaseRest +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class RestExtensionMethodAttribute : Attribute + { + public bool AllowAll { get; set; } + public string AllowGroup { get; set; } + public string AllowType { get; set; } + public string AllowMember { get; set; } + public bool ReturnXml { get; set; } + + public RestExtensionMethodAttribute() + { + this.AllowAll = true; + this.ReturnXml = true; + } + } +} diff --git a/src/Umbraco.Web/BaseRest/RestExtensionMethodInfo.cs b/src/Umbraco.Web/BaseRest/RestExtensionMethodInfo.cs new file mode 100644 index 0000000000..934d0e5732 --- /dev/null +++ b/src/Umbraco.Web/BaseRest/RestExtensionMethodInfo.cs @@ -0,0 +1,344 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Reflection; +using System.Xml; +using System.IO; + +using Umbraco.Core; +using Umbraco.Core.IO; +using umbraco.cms.businesslogic.member; + +namespace Umbraco.Web.BaseRest +{ + class RestExtensionMethodInfo + { + #region Utilities + + static char[] Split = new char[] { ',' }; + + static string[] SplitString(string s) + { + if (string.IsNullOrWhiteSpace(s)) + return new string[] { }; + else + return s.ToLower().Split(Split, StringSplitOptions.RemoveEmptyEntries); + } + + static string GetAttribute(XmlNode node, string name) + { + var attribute = node.Attributes[name]; + return attribute == null ? null : attribute.Value; + } + + #endregion + + private RestExtensionMethodInfo() + { + this.Exists = false; + } + + private RestExtensionMethodInfo(bool allowAll, string allowGroup, string allowType, string allowMember, bool returnXml, MethodInfo method) + { + this.Exists = true; + _allowAll = allowAll; + _allowGroups = SplitString(allowGroup); + _allowTypes = SplitString(allowType); + _allowMembers = SplitString(allowMember); + this.ReturnXml = returnXml; + _method = method; + } + + static RestExtensionMethodInfo MissingMethod = new RestExtensionMethodInfo(); + static Dictionary _cache = new Dictionary(); + + bool _allowAll; + string[] _allowGroups; + string[] _allowTypes; + string[] _allowMembers; + MethodInfo _method; + + public bool Exists { get; private set; } + public bool ReturnXml { get; private set; } + + #region Discovery + + public static RestExtensionMethodInfo GetMethod(string extensionAlias, string methodName) + { + return GetFromConfiguration(extensionAlias, methodName) + ?? GetFromAttribute(extensionAlias, methodName) + ?? GetFromLegacyAttribute(extensionAlias, methodName) + ?? MissingMethod; + } + + static RestExtensionMethodInfo GetFromConfiguration(string extensionAlias, string methodName) + { + const string ExtensionXPath = "/RestExtensions/ext [@alias='{0}']"; + const string MethodXPath = "./permission [@method='{0}']"; + + // fixme + // because we reload the config file each time we can't really have a cache here + // or we'd need to set 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; + string assemblyPath = IOHelper.MapPath(string.Format("{0}/{1}.dll", SystemDirectories.Bin, assemblyName.TrimStart('/'))); + Assembly assembly = Assembly.LoadFrom(assemblyPath); + + string typeName = eNode.Attributes["type"].Value; + Type type = assembly.GetType(typeName); + + 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; + } + + static RestExtensionMethodInfo GetFromLegacyAttribute(string extensionAlias, string methodName) + { + // here we can cache because any change would trigger an app restart + + string cacheKey = extensionAlias + "." + methodName; + lock (_cache) + { + if (_cache.ContainsKey(cacheKey)) + return _cache[cacheKey]; + } + + var extensions = PluginManager.Current.ResolveLegacyRestExtensions(); + var extension = extensions + .SingleOrDefault(type => type.GetCustomAttribute(false).GetAlias() == extensionAlias); + + RestExtensionMethodInfo info = null; + + if (extension != null) + { + var method = extension.GetMethod(methodName); + if (method != null) + { + var attribute = method.GetCustomAttributes(typeof(global::umbraco.presentation.umbracobase.RestExtensionMethod), false).Cast().SingleOrDefault(); + if (attribute != null) + { + info = new RestExtensionMethodInfo(attribute.GetAllowAll(), + attribute.GetAllowGroup(), attribute.GetAllowType(), attribute.GetAllowMember(), + attribute.returnXml, + method); + } + } + } + + lock (_cache) + { + _cache[cacheKey] = info; + } + + return info; + } + + 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 (_cache.ContainsKey(cacheKey)) + return _cache[cacheKey]; + } + + var extensions = PluginManager.Current.ResolveRestExtensions(); + var extension = extensions + .SingleOrDefault(type => type.GetCustomAttribute(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().SingleOrDefault(); + if (attribute != null) + { + info = new RestExtensionMethodInfo(attribute.AllowAll, + attribute.AllowGroup, attribute.AllowType, attribute.AllowMember, + attribute.ReturnXml, + method); + } + } + } + + lock (_cache) + { + _cache[cacheKey] = info; + } + + return info; + } + + #endregion + + #region Invoke + + public bool CanBeInvokedByCurrentMember + { + get + { + if (_allowAll) + return true; + + var member = Member.GetCurrentMember(); + + if (member == null) + return false; + + bool allowed = false; + + if (_allowGroups.Length > 0) + { + // fixme - are these equivalent? + //var groups = member.Groups.Values.Cast().Select(group => group.Text); + var groups = System.Web.Security.Roles.GetRolesForUser(member.LoginName); + allowed = groups.Select(s => s.ToLower()).Intersect(_allowGroups).Any(); + } + + if (!allowed && _allowTypes.Length > 0) + { + allowed = _allowTypes.Contains(member.ContentType.Alias); + } + + if (!allowed && _allowMembers.Length > 0) + { + allowed = _allowMembers.Contains(member.Id.ToString()); + } + + return allowed; + } + } + + public string Invoke(string[] parameters) + { + try + { + if (!_method.IsPublic || !_method.IsStatic) + { + // ensure that method is static public + return "Method has to be public and static"; + } + else + { + // ensure we have the right number of parameters + if (_method.GetParameters().Length != parameters.Length) + { + return "Not Enough parameters in url"; + } + else + { + // invoke + + // fixme - what is the point? + //Create an instance of the type we need to invoke the method from. + //**Object obj = Activator.CreateInstance(myExtension.type); + + object response; + + if (_method.GetParameters().Length == 0) + { + //response = myMethod.method.Invoke(obj, BindingFlags.Public | BindingFlags.Instance, bBinder, null, System.Globalization.CultureInfo.CurrentCulture); + response = _method.Invoke(null /*obj*/, null); // invoke with null as parameters as there are none + } + + else + { + object[] methodParams = new object[parameters.Length]; + + int i = 0; + + foreach (ParameterInfo pInfo in _method.GetParameters()) + { + Type myType = Type.GetType(pInfo.ParameterType.ToString()); + methodParams[(i)] = Convert.ChangeType(parameters[i], myType); + i++; + } + + //Invoke with methodParams + //response = myMethod.method.Invoke(obj, BindingFlags.Public | BindingFlags.Instance, bBinder, methodParams, System.Globalization.CultureInfo.CurrentCulture); + response = _method.Invoke(/*obj*/null, methodParams); + } + + /*TODO - SOMETHING ALITTLE BETTER THEN ONLY CHECK FOR XPATHNODEITERATOR OR ELSE do ToString() */ + if (response != null) + { + switch (_method.ReturnType.ToString()) + { + case "System.Xml.XPath.XPathNodeIterator": + return ((System.Xml.XPath.XPathNodeIterator)response).Current.OuterXml; + case "System.Xml.Linq.XDocument": + return response.ToString(); + case "System.Xml.XmlDocument": + XmlDocument xmlDoc = (XmlDocument)response; + StringWriter sw = new StringWriter(); + XmlTextWriter xw = new XmlTextWriter(sw); + xmlDoc.WriteTo(xw); + return sw.ToString(); + default: + string strResponse = ((string)response.ToString()); + + if (this.ReturnXml) + { + // do a quick "is this html?" check... if it is add CDATA... + if (strResponse.Contains("<") || strResponse.Contains(">")) + strResponse = ""; + return "" + strResponse + ""; + } + else + { + //HttpContext.Current.Response.ContentType = "text/html"; + return strResponse; + } + } + } + else + { + if (this.ReturnXml) + return "Null value returned"; + else + return string.Empty; + } + } + } + } + + catch (Exception ex) + { + //Overall exception handling... + return ""; + } + } + + #endregion + } +} diff --git a/src/Umbraco.Web/BaseRestHandler.cs b/src/Umbraco.Web/BaseRestHandler.cs deleted file mode 100644 index 9f2b3323cd..0000000000 --- a/src/Umbraco.Web/BaseRestHandler.cs +++ /dev/null @@ -1,218 +0,0 @@ -using System; -using System.Web; -using System.Web.SessionState; -using System.Reflection; -using System.Xml; -using System.IO; - -namespace Umbraco.Web -{ - internal class BaseRestHandler : IHttpHandler, IRequiresSessionState - { - const int ParametersOffset = 2; - static string _baseUrl; - - static BaseRestHandler() - { - _baseUrl = UriUtility.ToAbsolute(Umbraco.Core.IO.SystemDirectories.Base).ToLower(); - if (!_baseUrl.EndsWith("/")) - _baseUrl += "/"; - } - - public bool IsReusable - { - get { return true; } - } - - /// - /// Returns a value indicating whether a specified Uri should be routed to the BaseRestHandler. - /// - /// The specified Uri. - /// A value indicating whether the specified Uri should be routed to the BaseRestHandler. - public static bool IsBaseRestRequest(Uri uri) - { - return Umbraco.Core.Configuration.UmbracoSettings.EnableBaseRestHandler - && uri.AbsolutePath.ToLowerInvariant().StartsWith(_baseUrl); - } - - 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")); - if (url.ToLower().Contains("?")) - url = url.Substring(0, url.IndexOf("?")); - var urlParts = url.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - - // always return xml content - context.Response.ContentType = "text/xml"; - - // ensure that we have a valid request ie /base/library/method/[parameter].aspx - if (urlParts.Length < ParametersOffset) - { - context.Response.Write("Invalid request, missing parts."); - context.Response.StatusCode = 400; - context.Response.StatusDescription = "Bad Request"; - context.Response.End(); - return; - } - - // fixme - what follows comes straight from baseHttpModule.cs - - string extensionAlias = urlParts[0]; - string methodName = urlParts[1]; - - var myExtension = new global::umbraco.presentation.umbracobase.restExtension(extensionAlias, methodName); - - if (myExtension.isAllowed) - { - TrySetCulture(); - - string response = invokeMethod(myExtension, urlParts); - if (response.Length >= 7 && response.Substring(0, 7) == "") - { - context.Response.StatusCode = 500; - context.Response.StatusDescription = "Internal Server Error"; - } - context.Response.Output.Write(response); - } - else - { - context.Response.StatusCode = 500; - context.Response.StatusDescription = "Internal Server Error"; - context.Response.Output.Write("Extension not found or permission denied."); - } - - context.Response.End(); - } - - #region from baseHttpModule.cs - - // fixme - these methods have *not* been cleaned up, just partially fixed... - - string invokeMethod(global::umbraco.presentation.umbracobase.restExtension myExtension, string[] urlParts) - { - try - { - //So method is either not found or not valid... this should probably be moved... - if (!myExtension.method.IsPublic || !myExtension.method.IsStatic) - return "Method has to be public and static"; - else //And if it is lets continue trying to invoke it... - { - //lets check if we have parameters enough in the url.. - if (myExtension.method.GetParameters().Length > (urlParts.Length - ParametersOffset)) //Too few - return "Not Enough parameters in url"; - else - { - - //We have enough parameters... lets invoke.. - //Create an instance of the type we need to invoke the method from. - //**Object obj = Activator.CreateInstance(myExtension.type); - Object response; - - //umbracoBase.baseBinder bBinder = new baseBinder(); - - if (myExtension.method.GetParameters().Length == 0) - { - //response = myMethod.method.Invoke(obj, BindingFlags.Public | BindingFlags.Instance, bBinder, null, System.Globalization.CultureInfo.CurrentCulture); - response = myExtension.method.Invoke(null /*obj*/, null); //Invoke with null as parameters as there are none - } - - else - { - //We only need the parts of the url above the number 4 so we'll - //recast those to objects and add them to the object[] - - //Getting the right lenght.. 4 is the magic number dum di dum.. - object[] methodParams = new object[urlParts.Length - ParametersOffset]; - - int i = 0; - - foreach (ParameterInfo pInfo in myExtension.method.GetParameters()) - { - Type myType = Type.GetType(pInfo.ParameterType.ToString()); - methodParams[(i)] = Convert.ChangeType(urlParts[i + ParametersOffset], myType); - i++; - } - - //Invoke with methodParams - //response = myMethod.method.Invoke(obj, BindingFlags.Public | BindingFlags.Instance, bBinder, methodParams, System.Globalization.CultureInfo.CurrentCulture); - response = myExtension.method.Invoke(/*obj*/null, methodParams); - } - - /*TODO - SOMETHING ALITTLE BETTER THEN ONLY CHECK FOR XPATHNODEITERATOR OR ELSE do ToString() */ - if (response != null) - { - switch (myExtension.method.ReturnType.ToString()) - { - case "System.Xml.XPath.XPathNodeIterator": - return ((System.Xml.XPath.XPathNodeIterator)response).Current.OuterXml; - case "System.Xml.Linq.XDocument": - return response.ToString(); - case "System.Xml.XmlDocument": - XmlDocument xmlDoc = (XmlDocument)response; - StringWriter sw = new StringWriter(); - XmlTextWriter xw = new XmlTextWriter(sw); - xmlDoc.WriteTo(xw); - return sw.ToString(); - default: - string strResponse = ((string)response.ToString()); - - if (myExtension.returnXML) - { - //do a quick "is this html?" check... if it is add CDATA... - if (strResponse.Contains("<") || strResponse.Contains(">")) - strResponse = ""; - return "" + strResponse + ""; - } - else - { - HttpContext.Current.Response.ContentType = "text/html"; - return strResponse; - } - } - } - else - { - if (myExtension.returnXML) - return "Null value returned"; - else - return string.Empty; - } - - - - } - } - } - - catch (Exception ex) - { - //Overall exception handling... - return ""; - } - } - - private static void TrySetCulture() - { - string domain = HttpContext.Current.Request.Url.Host; //Host only - if (TrySetCulture(domain)) return; - - domain = HttpContext.Current.Request.Url.Authority; //Host with port - if (TrySetCulture(domain)) return; - } - - private static bool TrySetCulture(string domain) - { - var uDomain = global::umbraco.cms.businesslogic.web.Domain.GetDomain(domain); - if (uDomain == null) return false; - System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(uDomain.Language.CultureAlias); - return true; - } - - #endregion - } -} diff --git a/src/Umbraco.Web/PluginManagerExtensions.cs b/src/Umbraco.Web/PluginManagerExtensions.cs index 13db38e9d2..5ff0e9f81d 100644 --- a/src/Umbraco.Web/PluginManagerExtensions.cs +++ b/src/Umbraco.Web/PluginManagerExtensions.cs @@ -6,8 +6,6 @@ using Umbraco.Core; using Umbraco.Web.Routing; using umbraco; using umbraco.interfaces; -using umbraco.presentation.umbracobase; - namespace Umbraco.Web { @@ -27,13 +25,23 @@ namespace Umbraco.Web } /// - /// Returns all classes attributed with RestExtension attribute + /// Returns all classes attributed with legacy RestExtension attribute + /// + /// + /// + internal static IEnumerable ResolveLegacyRestExtensions(this PluginManager resolver) + { + return resolver.ResolveAttributedTypes(); + } + + /// + /// Returns all classes attributed with RestExtensionAttribute attribute /// /// /// internal static IEnumerable ResolveRestExtensions(this PluginManager resolver) { - return resolver.ResolveAttributedTypes(); + return resolver.ResolveAttributedTypes(); } /// diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 9f9411fed2..2dd5bdb20d 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -240,7 +240,11 @@ Properties\SolutionInfo.cs - + + + + + diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index 4798931c16..d5b400e3bd 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -67,9 +67,9 @@ namespace Umbraco.Web umbracoContext.RoutingContext = routingContext; // remap to handler if it is a base rest request - if (BaseRestHandler.IsBaseRestRequest(umbracoContext.RequestUrl)) + if (BaseRest.BaseRestHandler.IsBaseRestRequest(umbracoContext.RequestUrl)) { - httpContext.RemapHandler(new BaseRestHandler()); + httpContext.RemapHandler(new BaseRest.BaseRestHandler()); } else diff --git a/src/Umbraco.Web/WebServices/FolderBrowserService.cs b/src/Umbraco.Web/WebServices/FolderBrowserService.cs index 82684d7b1e..02132356f0 100644 --- a/src/Umbraco.Web/WebServices/FolderBrowserService.cs +++ b/src/Umbraco.Web/WebServices/FolderBrowserService.cs @@ -11,14 +11,14 @@ using umbraco.BusinessLogic; using umbraco.IO; using umbraco.cms.businesslogic.Tags; using umbraco.cms.businesslogic.media; -using umbraco.presentation.umbracobase; +using Umbraco.Web.BaseRest; namespace Umbraco.Web.WebServices { [RestExtension("FolderBrowserService")] public class FolderBrowserService { - [RestExtensionMethod(returnXml = false)] + [RestExtensionMethod(ReturnXml = false)] public static string GetChildren(int parentId) { var parentMedia = new global::umbraco.cms.businesslogic.media.Media(parentId); @@ -64,7 +64,7 @@ namespace Umbraco.Web.WebServices return new JavaScriptSerializer().Serialize(data); } - [RestExtensionMethod(returnXml = false)] + [RestExtensionMethod(ReturnXml = false)] public static string Delete(string nodeIds) { var nodeIdParts = nodeIds.Split(','); diff --git a/src/Umbraco.Web/umbraco.presentation/umbracobase/attributes/RestExtension.cs b/src/Umbraco.Web/umbraco.presentation/umbracobase/attributes/RestExtension.cs index f9839fb588..202fa76a40 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbracobase/attributes/RestExtension.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbracobase/attributes/RestExtension.cs @@ -5,6 +5,7 @@ using System.Web; namespace umbraco.presentation.umbracobase { + [Obsolete("Use Umbraco.Web.BaseRest.RestExtensionAttribute")] [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)] public class RestExtension : System.Attribute { diff --git a/src/Umbraco.Web/umbraco.presentation/umbracobase/attributes/RestExtensionMethod.cs b/src/Umbraco.Web/umbraco.presentation/umbracobase/attributes/RestExtensionMethod.cs index 4836fc7a78..f11c5d644b 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbracobase/attributes/RestExtensionMethod.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbracobase/attributes/RestExtensionMethod.cs @@ -5,6 +5,7 @@ using System.Web; namespace umbraco.presentation.umbracobase { + [Obsolete("Use Umbraco.Web.BaseRest.RestExtensionMethodAttribute")] [System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple = false)] public class RestExtensionMethod : System.Attribute { diff --git a/src/Umbraco.Web/umbraco.presentation/umbracobase/restExtension.cs b/src/Umbraco.Web/umbraco.presentation/umbracobase/restExtension.cs index d7ee34bebc..dbeab6cf53 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbracobase/restExtension.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbracobase/restExtension.cs @@ -10,6 +10,7 @@ using umbraco.IO; namespace umbraco.presentation.umbracobase { + [Obsolete] public class restExtension { private Type _type;