/// <summary> /// Returns a copy of this instance, setting its category and locale to the specified values. /// </summary> /// <param name="category">The category to set on the resulting instance.</param> /// <param name="locale">The locale to set on the resulting instance.</param> /// <returns>A <see cref="SageContext"/> copy of this instance, with its category and locale set to the /// specified <paramref name="category"/> and <paramref name="locale"/>.</returns> internal SageContext Copy(string category, string locale) { SageContext result = new SageContext(this); result.Category = category; result.Locale = locale; return result; }
internal static XmlNode ProcessSageBaseHrefElement(SageContext context, XmlNode node) { Contract.Requires<ArgumentNullException>(node != null); if (node.SelectSingleElement("ancestor::sage:literal", XmlNamespaces.Manager) != null) return node; XmlElement result = node.OwnerDocument.CreateElement("base", XmlNamespaces.XHtmlNamespace); result.SetAttribute("href", context.BaseHref); return result; }
internal static XmlNode ProcessSageUrlElement(SageContext context, XmlNode node) { Contract.Requires<ArgumentNullException>(node != null); if (node.SelectSingleElement("ancestor::sage:literal", XmlNamespaces.Manager) != null) return node; string linkHref = context.Url.GetUrl((XmlElement) node); if (!string.IsNullOrEmpty(linkHref)) { if (node.NodeType == XmlNodeType.Element) return node.OwnerDocument.CreateTextNode(linkHref); } return node; }
internal static string GetLinkFunction(SageContext context, params string[] arguments) { var linkArguments = new LinkArguments(arguments, true, "encode", "absolute"); var qualify = linkArguments.Switches["absolute"]; var result = context.Url.GetUrl(linkArguments.LinkName, linkArguments.QueryString, linkArguments.HashString, qualify); if (linkArguments.Switches["encode"] && !string.IsNullOrEmpty(result)) result = HttpUtility.UrlEncode(result); return result; }
internal static string GetSelfFunction(SageContext context, params string[] arguments) { var linkArguments = new LinkArguments(arguments, false, "encode", "absolute"); var currentUrl = linkArguments.Switches["absolute"] ? context.Url.RawUrl : context.Url.RawPathAndQuery; var paramQuery = new QueryString(parameterSeparators); if (currentUrl.Contains("?")) { var questionIndex = currentUrl.IndexOf("?", StringComparison.Ordinal); paramQuery.Parse(currentUrl.Substring(questionIndex + 1)); currentUrl = currentUrl.Substring(0, questionIndex); } paramQuery.Merge(linkArguments.QueryString); var result = string.Concat(currentUrl, paramQuery.ToString("?"), string.IsNullOrEmpty(linkArguments.HashString) ? string.Empty : string.Concat("#", linkArguments.HashString)); if (linkArguments.Switches["encode"] && !string.IsNullOrEmpty(result)) result = HttpUtility.UrlEncode(result); return result; }
/// <summary> /// Starts this instance. /// </summary> /// <param name="context">The context.</param> protected static void Start(SageContext context) { Project.IsStarted = true; }
/// <summary> /// Handles the Error event of the Application control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param> protected virtual void Application_Error(object sender, EventArgs e) { Exception exception = this.Server.GetLastError(); if (exception == null) return; if (exception is ThreadAbortException) return; log.Fatal(exception.Message, exception); StringBuilder html = new StringBuilder(); TextWriter writer = new StringWriter(html); SageContext context = new SageContext(this.Context); SageException sageException = SageHelpException.Create(exception); if (((SageHelpException) sageException).Problem.Type == ProblemType.Unknown) sageException = exception is SageHelpException ? (SageHelpException) exception : new SageException(exception); if (this.IsRequestAvailable) { sageException.Render(writer, context); } else { sageException.RenderWithoutContext(writer); } writer.Close(); writer.Dispose(); this.Response.ContentType = "text/html"; this.Response.Write(html.ToString()); this.Response.Cache.SetCacheability(HttpCacheability.NoCache); this.Response.Cache.SetNoStore(); this.Response.End(); }
internal static string IIf(SageContext context, params string[] arguments) { if (arguments.Length < 3) return string.Empty; string condition = context.textEvaluator.Process(arguments[0]); string result1 = arguments[1]; string result2 = arguments[2]; return !string.IsNullOrWhiteSpace(condition) ? result1 : result2; }
internal static string IsNull(SageContext context, params string[] arguments) { if (arguments.Length < 2) return string.Empty; string result1 = arguments[0]; string result2 = arguments[1]; return !string.IsNullOrWhiteSpace(result1) ? result1 : result2; }
internal static string GetSessionParam(SageContext context, params string[] arguments) { if (arguments.Length == 0) return string.Empty; return context.Session[arguments[0]] as string; }
internal static string GetVariable(SageContext context, params string[] arguments) { if (arguments.Length < 1) return string.Empty; string name = arguments[0]; string locale = arguments.Length < 2 ? null : arguments[1]; return context.GetProjectVariable(name, locale); }
internal static string GetRequestParam(SageContext context, params string[] arguments) { if (arguments.Length == 0) return string.Empty; return context.Request[arguments[0]]; }
/// <summary> /// Initializes a new instance of the <see cref="SageContext"/> class, using an existing context instance. /// </summary> /// <param name="context">An existing <see cref="SageContext"/> to use to initialize this instance.</param> /// <param name="pathMapper">The function to use for resolving relative paths.</param> /// <param name="config">The project configuration to use with this context instance.</param> public SageContext(SageContext context, ProjectConfiguration config = null, Func<string, string> pathMapper = null) : this(context, context.Category, config) { if (pathMapper != null) this.pathMapper = pathMapper; }
private static string GetContextProperty(SageContext context, string propName, string propKey) { const BindingFlags BindingFlags = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static; PropertyInfo property = context.GetType().GetProperty(propName, BindingFlags); if (property == null) { log.ErrorFormat( "Property name '{0}' is invalid. Please make sure the name matches a property of SageContext", propName); return null; } object value = property.GetValue(context, null); if (value != null) { if (!string.IsNullOrEmpty(propKey)) { if (value is NameValueCollection) return ((NameValueCollection) value)[propKey]; object subProperty = value.GetType().GetProperty(propKey, BindingFlags); if (subProperty != null) { return subProperty.ToString(); } log.ErrorFormat( "The context property '{0}' is not a NameValue collection and it doesn't have a property named '{1}'.", propName, propKey); return null; } return value.ToString(); } return null; }
/// <summary> /// Initializes the application using the specified project configuration instance. /// </summary> /// <param name="context">The context in which this method is being executed.</param> internal static void Initialize(SageContext context) { ViewEngines.Engines.Clear(); ViewEngines.Engines.Add(new XsltViewEngine()); ViewEngines.Engines.Add(new WebFormViewEngine()); Project.InitializeConfiguration(context); //// The routes need to be re-registered after the assemblies get updated Project.AssembliesUpdated += (sender, args) => Project.RegisterRoutes(); Project.RegisterRoutes(); var controller = Project.Configuration.Routing.DefaultController; var action = Project.Configuration.Routing.DefaultAction; var routeName = string.Format("{0}.{1}", controller, action); log.DebugFormat("Manually registering route '*' to {0}", routeName); RouteTable.Routes.MapRouteLowercase( routeName, "{*path}", new Dictionary<string, object> { { "controller", controller.Replace("Controller", string.Empty) }, { "action", action } }); projectIsReady = true; }
internal static XmlNode ProcessBaseHrefNode(SageContext context, XmlNode node) { if (node.SelectSingleElement("ancestor::sage:literal", XmlNamespaces.Manager) != null) return node; XmlElement result = node.OwnerDocument.CreateElement("base", XmlNamespaces.XHtmlNamespace); result.SetAttribute("href", context.BaseHref); return result; }
internal static SageContext InitializeConfiguration(SageContext context) { string projectConfigPathBinDir = Path.Combine(Project.AssemblyCodeBaseDirectory, ProjectConfiguration.ProjectConfigName); string projectConfigPathProjDir = Path.Combine(Project.AssemblyCodeBaseDirectory, "..\\" + ProjectConfiguration.ProjectConfigName); string projectConfigPath = projectConfigPathBinDir; if (File.Exists(projectConfigPathProjDir)) { projectConfigPath = projectConfigPathProjDir; } var projectConfig = ProjectConfiguration.Create(); if (!File.Exists(projectConfigPath)) { log.Warn("Project configuration file not found; configuration initialized with default values"); return new SageContext(context); } installOrder = new List<string>(); extensions = new OrderedDictionary<string, ExtensionInfo>(); if (File.Exists(projectConfigPath)) projectConfig.Parse(projectConfigPath); if (projectConfig.Locales.Count == 0) { var defaultLocale = new LocaleInfo(); projectConfig.Locales.Add(defaultLocale.Name, defaultLocale); } var result = projectConfig.ValidationResult; if (!result.Success) { initializationError = result.Exception; initializationProblemInfo = new ProblemInfo(ProblemType.ProjectSchemaValidationError, result.SourceFile); } else { configuration = projectConfig; // this will ensure the new context uses the just // created configuration immediately context = new SageContext(context); var extensionManager = new ExtensionManager(); try { extensionManager.Initialize(context); } catch (ProjectInitializationException ex) { initializationError = ex; initializationProblemInfo = new ProblemInfo(ex.Reason, ex.SourceFile); if (ex.Reason == ProblemType.MissingExtensionDependency) { initializationProblemInfo.InfoBlocks .Add("Dependencies", ex.Dependencies.ToDictionary(name => name)); } } if (initializationError == null) { var missingDependencies = projectConfig.Dependencies .Where(name => extensionManager.Count(ex => ex.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)) == 0) .ToList(); var extraDependencies = extensionManager .Where(extension => projectConfig.Dependencies.Count(name => name.Equals(extension.Name, StringComparison.InvariantCultureIgnoreCase)) == 0) .ToList(); if (missingDependencies.Count != 0) { string errorMessage = string.Format("Project is missing one or more dependencies ({0}) - installation cancelled.", string.Join(", ", missingDependencies)); initializationError = new ProjectInitializationException(errorMessage); initializationProblemInfo = new ProblemInfo(ProblemType.MissingDependency); initializationProblemInfo.InfoBlocks .Add("Dependencies", missingDependencies.ToDictionary(name => name)); } if (extraDependencies.Count != 0) { log.WarnFormat("There are additional, unreferenced extensions in the extensions directory: {0}", string.Join(",", extraDependencies)); } foreach (var name in projectConfig.Dependencies) { var extension = extensionManager.First(ex => ex.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)); installOrder.Add(extension.Config.Id); Project.RelevantAssemblies.AddRange(extension.Assemblies); projectConfig.RegisterExtension(extension.Config); extensions.Add(extension.Config.Id, extension); } // fire this event at the end rather than once for each extension var totalAssemblies = extensionManager.Sum(info => info.Assemblies.Count); if (totalAssemblies != 0) { if (Project.AssembliesUpdated != null) { log.DebugFormat("{0} extension assemblies loaded, triggering AssembliesUpdated event", totalAssemblies); Project.AssembliesUpdated(null, EventArgs.Empty); } } installOrder.Add(projectConfig.Id); projectConfig.RegisterRoutes(); context.LmCache.Put(ConfigWatchName, DateTime.Now, projectConfig.Files); } } return context; }
internal static XmlNode ProcessContextIfNode(SageContext context, XmlNode node) { if (node.SelectSingleElement("ancestor::sage:literal", XmlNamespaces.Manager) != null) return node; XmlElement element = (XmlElement) node; XmlDocumentFragment result = node.OwnerDocument.CreateDocumentFragment(); string expression = element.GetAttribute("expression"); string propName = element.GetAttribute("property"); string key = element.GetAttribute("key"); string equals = element.GetAttribute("equals"); string notEquals = element.GetAttribute("not-equals"); bool nodeValid = false; if (!string.IsNullOrWhiteSpace(expression)) { var text = context.textEvaluator.Process(expression); nodeValid = !string.IsNullOrWhiteSpace(text); } else { string propValue = SageContext.GetContextProperty(context, propName, key); if (notEquals != string.Empty) nodeValid = !propValue.Equals(notEquals, StringComparison.InvariantCultureIgnoreCase); else if (equals != string.Empty) nodeValid = propValue.Equals(equals, StringComparison.InvariantCultureIgnoreCase); } if (!nodeValid) return null; foreach (XmlNode child in node.SelectNodes("node()")) result.AppendChild(context.ProcessNode(child)); return result; }
/// <summary> /// Handles the BeginRequest event of the Application control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param> protected virtual void Application_BeginRequest(object sender, EventArgs e) { if (Thread.CurrentThread.Name == null) { Thread.CurrentThread.Name = Project.GenerateThreadId(); log.InfoFormat("Thread name set to {0}", Thread.CurrentThread.Name); } if (initializationError != null) { StringBuilder html = new StringBuilder(); using (TextWriter writer = new StringWriter(html)) { SageHelpException helpException = new SageHelpException(initializationProblemInfo, initializationError); helpException.Render(writer, new SageContext(this.Context)); } this.Response.Write(html.ToString()); this.Response.Cache.SetCacheability(HttpCacheability.NoCache); this.Response.Cache.SetNoStore(); this.Response.End(); } var context = new SageContext(this.Context); if (context.LmCache.Get(ConfigWatchName) == null) Project.InitializeConfiguration(context); if (!Project.IsStarted) { lock (lck) { if (!Project.IsStarted) { Project.Start(context); } } } if (this.Context != null) log.InfoFormat("Request {0} started.", HttpContext.Current.Request.Url); else log.InfoFormat("Request started (no context)"); }
/// <summary> /// Initializes a new instance of the <see cref="SageContext"/> class, using an existing context instance. /// </summary> /// <param name="context">An existing <see cref="SageContext"/> to use to initialize this instance.</param> /// <param name="categoryName">The name of the category to set on the new context.</param> /// <param name="config">The project configuration to use with this context instance.</param> public SageContext(SageContext context, string categoryName, ProjectConfiguration config = null) : this(context.HttpContext, config) { this.Category = categoryName; pathMapper = context.MapPath; }
/// <summary> /// Initializes a new instance of the <see cref="LastModifiedCache"/> class, using the specified /// <paramref name="context"/>. /// </summary> /// <param name="context">The current context under which this code is being executed.</param> internal LastModifiedCache(SageContext context) { Contract.Requires<ArgumentNullException>(context != null); this.context = context; }
internal static XmlNode ProcessContextSwitchNode(SageContext context, XmlNode switchNode) { if (switchNode.SelectSingleElement("ancestor::sage:literal", XmlNamespaces.Manager) != null) return switchNode; XmlElement switchElem = (XmlElement) switchNode; string propName = switchElem.GetAttribute("property"); string key = switchElem.GetAttribute("key"); if (string.IsNullOrEmpty(propName)) { log.ErrorFormat("The switch node in document '{0}' is missing the required property attribute", switchNode.OwnerDocument.BaseURI); return switchNode; } string propValue = SageContext.GetContextProperty(context, propName, key); int caseNum = 0; bool caseFound = false; XmlDocumentFragment result = switchNode.OwnerDocument.CreateDocumentFragment(); foreach (XmlElement caseNode in switchNode.SelectNodes("context:case", XmlNamespaces.Manager)) { string testValue = caseNode.GetAttribute("test"); if (string.IsNullOrEmpty(testValue)) { log.WarnFormat( "The case node with index {0} of switch node '{1}' in document '{2}' didn't specify a test condition.", caseNum, propName, switchNode.OwnerDocument.BaseURI); continue; } if (testValue.Equals(propValue, StringComparison.InvariantCultureIgnoreCase)) { foreach (XmlNode node in caseNode.SelectNodes("node()")) result.AppendChild(context.ProcessNode(node)); caseFound = true; break; } caseNum += 1; } if (!caseFound) { XmlNode defaultNode = switchNode.SelectSingleNode("context:default", XmlNamespaces.Manager); if (defaultNode != null) { foreach (XmlNode node in defaultNode.SelectNodes("node()")) result.AppendChild(context.ProcessNode(node)); } } return result; }
internal static string GetProjectLinkFunction(SageContext context, params string[] arguments) { var linkArguments = new LinkArguments(arguments, false, "encode", "absolute", "pretty"); var result = linkArguments.Switches["absolute"] ? context.Url.ApplicationRoot : context.Request.ApplicationPath; if (linkArguments.Switches["encode"] && !string.IsNullOrEmpty(result)) result = HttpUtility.UrlEncode(result); return result + (result.EndsWith("/") ? string.Empty : "/"); }
/// <summary> /// Renders the exception to the specified <paramref name="writer"/> /// </summary> /// <param name="writer">The writer to render the exception to.</param> /// <param name="context">The context under which this code is executing.</param> public virtual void Render(TextWriter writer, SageContext context) { Contract.Requires<ArgumentNullException>(context != null); Contract.Requires<ArgumentNullException>(writer != null); XmlDocument document = new XmlDocument(); XmlElement documentElement = document.AppendElement(this.ConvertToXml(this.Exception, document)); Exception inner = this.Exception.InnerException; while (inner != null) { documentElement.AppendChild(this.ConvertToXml(inner, document)); inner = inner.InnerException; } documentElement.AppendChild(context.ToXml(document)); documentElement.SetAttribute("date", DateTime.Now.ToString("dd-MM-yyyy")); documentElement.SetAttribute("time", DateTime.Now.ToString("hh:mm:ss")); XsltTransform processor = XsltTransform.Create(context, this.StylesheetPath); XmlWriter xmlwr = XmlWriter.Create(writer, processor.OutputSettings); processor.Transform(documentElement, xmlwr, context, this.GetTransformArguments(context)); }
internal static XmlNode ProcessHrefAttribute(SageContext context, XmlNode node) { Contract.Requires<ArgumentNullException>(node != null); if (node.SelectSingleElement("ancestor::sage:literal", XmlNamespaces.Manager) != null) return node; node.InnerText = context.ProcessText(node.InnerText); return node; }
/// <summary> /// Gets the XSLT arguments to use with the transform. /// </summary> /// <param name="context">The current context.</param> /// <returns>The XSLT arguments to use with this transform</returns> protected virtual Dictionary<string, object> GetTransformArguments(SageContext context) { Dictionary<string, object> arguments = new Dictionary<string, object>(); arguments.Add("developer", context.IsDeveloperRequest ? 1 : 0); return arguments; }
internal static XmlNode ProcessSageLinkElement(SageContext context, XmlNode node) { Contract.Requires<ArgumentNullException>(node != null); if (node.SelectSingleElement("ancestor::sage:literal", XmlNamespaces.Manager) != null) return node; XmlElement linkElem = (XmlElement) node; string linkName = context.ProcessText(linkElem.GetAttribute("ref")); bool rawString = linkElem.GetAttribute("raw").EqualsAnyOf("1", "yes", "true"); if (!string.IsNullOrEmpty(linkName) && rawString) { if (context.Url.Links.ContainsKey(linkName)) { linkElem.InnerText = context.Url.Links[linkName].Value; } return linkElem; } string linkHref = context.Url.GetUrl(linkElem); if (!string.IsNullOrEmpty(linkHref)) { linkElem.SetAttribute("href", linkHref); } foreach (XmlNode child in node.ChildNodes) { XmlNode processed = NodeEvaluator.GetNodeHandler(child)(context, child); if (processed != null) node.ReplaceChild(processed, child); else node.RemoveChild(child); } return linkElem; }
internal static Dictionary<string, string> GetVirtualDirectories(SageContext context) { Dictionary<string, string> virtualDirectories = new Dictionary<string, string>(); try { string serverRootPath = context.MapPath("/").ToLower().TrimEnd('\\'); using (DirectoryEntry iis = new DirectoryEntry("IIS://Localhost/w3svc")) { IEnumerable<DirectoryEntry> websites = iis.Children.Cast<DirectoryEntry>() .Where(c => c.SchemaClassName == "IIsWebServer"); foreach (DirectoryEntry website in websites) { using (website) { DirectoryEntry root = website.Children.Find("Root", "IIsWebVirtualDir"); string sitePath = root.Properties["path"].Value.ToString().ToLower().TrimEnd('\\'); if (sitePath == serverRootPath) { virtualDirectories = Project.GetVirtualDirectories(root, string.Empty); break; } } } } } catch (Exception ex) { log.ErrorFormat("Could not retrieve virtual directories in the current application's web server: {0}", ex.Message); } return virtualDirectories; }
/// <summary> /// Initializes a new instance of the <see cref="UrlGenerator"/> class, using the specified <paramref name="context"/>. /// </summary> /// <param name="context">The current <see cref="SageContext"/>.</param> public UrlGenerator(SageContext context) { this.context = context; }
internal static string ResolvePathVariable(SageContext context, string variable) { switch (variable.ToLower()) { case "apppath": return context.ApplicationPath; case "locale": return context.Locale; case "basehref": return context.BaseHref; case "category": return context.Category; case "assetpath": return context.Path.GetRelativeWebPath(context.Path.AssetPath); case "sharedassetpath": return context.Path.GetRelativeWebPath(context.Path.SharedAssetPath); case "modulepath": return context.Path.GetRelativeWebPath(context.Path.ModulePath); } return variable; }