/// <summary> /// Gets the relative path of the template to use with the current file taking into account all the possible parameters/fields that control this setting /// </summary> /// <returns></returns> private static string GetCurrentTemplateFile(MarkdownFile md) { //Get the template name that is going to be used (Front Matter or configuration), if any. string templateName = md.TemplateName; if (string.IsNullOrEmpty(templateName) || templateName.ToLowerInvariant() == "none") { return(string.Empty); //Use the default basic HTML5 template } if (templateName.ToLowerInvariant() == "raw") { return("raw"); //Use raw contents, without any wrapping HTML tags } //The name (or sub-path) for the layout file (.html normaly) to be used string layoutName = md.Layout; if (string.IsNullOrEmpty(layoutName)) { return(string.Empty); //Use the default basic HTML5 template } //If both the template folder and the layout are established, then get the base folder for the templates //This base path for the templates parameter is only available through Web.config. NOT in the file Front Matter (we're skipping the file in the following call) string basePath = FieldValuesHelper.GetFieldValue("TemplatesBasePath", null, "~/Templates/"); return(VirtualPathUtility.AppendTrailingSlash(basePath) + VirtualPathUtility.AppendTrailingSlash(templateName) + layoutName); }
//Process the requests public void ProcessRequest(HttpContext ctx) { try { //Try to process the markdown file string filePath = ctx.Server.MapPath(ctx.Request.FilePath); MarkdownFile mdFile = new MarkdownFile(filePath); //If the feature is enabled and the user requests the original file, send the original file if (!string.IsNullOrEmpty(ctx.Request.QueryString["download"])) { if (Common.GetFieldValue("allowDownloading") == "1") { ctx.Response.ContentType = "text/markdown; charset=UTF-8"; ctx.Response.AppendHeader("content-disposition", "attachment; filename=" + mdFile.FileName); ctx.Response.Write(mdFile.Content); } else { throw new SecurityException("Download of markdown not allowed. Change configuration."); } } else { //Check if the File is published if (mdFile.IsPublished) { //Check if is a 404 page if (mdFile.HttpStatusCode != 200) { ctx.Response.StatusCode = mdFile.HttpStatusCode; } //Send the rendered HTML for the file ctx.Response.ContentType = "text/html"; ctx.Response.Write(mdFile.HTML); } else { throw new FileNotFoundException(); } } } catch (SecurityException) { //Access to file not allowed ctx.Response.StatusDescription = "Forbidden"; ctx.Response.StatusCode = 403; } catch (FileNotFoundException) { //Normally IIS will take care, but you can disconnect it ctx.Response.StatusDescription = "File not found"; ctx.Response.StatusCode = 404; } catch (Exception) { throw; } }
/// <summary> /// Renders the HTML from the markdown using the templates and parameters specified in web.config /// and processing the templates /// </summary> /// <param name="md">The markdown file information</param> /// <param name="raw">If true will force the raw template: only te content, without any extra HTML. /// This is useful for getting the pure, fully processed content of the file, without any extra HTML</param> /// <returns>The final HTML to return to the client</returns> public static string RenderMarkdownFile(MarkdownFile md) { //Get current template and layout HttpContext ctx = HttpContext.Current; string template = DEFAULT_TEMPLATE; //The default template for the final HTML string templateFile = GetCurrentTemplateFile(md); //Get the curent template layout path if (!string.IsNullOrEmpty(templateFile)) { //If the specified template is "raw" then just return the raw HTML without any wrapping HTML code //(no html, head or body tags). Useful to return special pages with raw content. if (templateFile == "raw") { template = "{{content}}"; } else { List <string> templateDependencies = new List <string>(); try { template = ReadTemplate(templateFile, ctx, templateDependencies); //Read, transform and cache template //Add template file's dependences as dependences for the Markdown file cache too md.AddFileDependencies(templateDependencies); } catch (FileNotFoundException) { throw new Exception("Current template file is not accessible! Check the TemplateName and Layout properties for the site or the current file"); } catch (Exception) { throw; } } } //Check if there're fragments in the layout and process them template = InjectFragments(template, md, ctx); //Process the template with DotLiquid for this file (the {{content}} placeholder is resolved in the MDFieldsResolver Template parser = Template.Parse(template); string tempContent = parser.Render(md.FieldsResolver); //The file contents get rendered into the template by the {{content}} placeholder CheckParserForSpecialErrors(parser.Errors); //Transform virtual paths tempContent = WebHelper.TransformVirtualPaths(tempContent); //HACK: remove possible delimiters to prevent the processing of HTML contents inside Markdown files (see MDFieldsResolver.cs) //Normal delimiters tempContent = tempContent.Replace(MDFieldsResolver.HTML_NO_PROCESSING_DELIMITER_BEGIN, string.Empty). Replace(MDFieldsResolver.HTML_NO_PROCESSING_DELIMITER_END, string.Empty); //Delimiters inside blocks (shouldn't be located there, but...) that get HTMLEncoded for that reason tempContent = tempContent.Replace(WebUtility.HtmlEncode(MDFieldsResolver.HTML_NO_PROCESSING_DELIMITER_BEGIN), string.Empty) .Replace(WebUtility.HtmlEncode(MDFieldsResolver.HTML_NO_PROCESSING_DELIMITER_END), string.Empty); //Return the final content return(tempContent); }
public static string RenderLiquidTags(string rawContent, MarkdownFile contextFile) { //Process the content tags (if any) with DotLiquid Template parser = Template.Parse(rawContent); string res = parser.Render(contextFile.FieldsResolver); //Check if a custom error has been raised CheckParserForSpecialErrors(parser.Errors); return(res); }
/// <summary> /// Returns the value, if any, for a specified field name. It takes the value from the FrontMatter only. /// If it's not present in the Front Matter, it returns the default value. /// </summary> /// <param name="name">The name of the field to retrieve</param> /// <param name="md">An optional Markdown file to check in its front matter</param> /// <param name="defValue">The default value to return if it's not present</param> /// <returns>Can return different types: null, boolean, string, array or date</returns> public static object GetFieldObjectFromFM(string name, MarkdownFile md, object defValue = null) { string res = GetFieldValueFromFM(name, md, ""); if (res == "") { return(defValue); } return(TypesHelper.TryToGuessAndConvertToTypeFromString(res)); }
//Process the requests public void ProcessRequest(HttpContext ctx) { try { //Try to process the markdown file string filePath = ctx.Server.MapPath(ctx.Request.FilePath); MarkdownFile mdFile = new MarkdownFile(filePath); //Check if the File is published if (mdFile.IsPublished) { //Check if is a special status code page (404, etc) if (mdFile.HttpStatusCode != 200) { ctx.Response.StatusCode = mdFile.HttpStatusCode; } //Send the rendered content for the file ctx.Response.ContentType = mdFile.MimeType; //text/html by default if (ctx.Request.Params["raw"] == "true") { ctx.Response.Write(mdFile.Content); } else { ctx.Response.Write(mdFile.FinalHTML); } } else { throw new FileNotFoundException(); } } catch (SecurityException) { //Access to file not allowed ctx.Response.StatusDescription = "Forbidden"; ctx.Response.StatusCode = 403; } catch (FileNotFoundException) { //Normally IIS will take care, but you can disconnect it ctx.Response.StatusDescription = "File not found"; ctx.Response.StatusCode = 404; } catch (Exception) { throw; } }
//Takes care of custom fields such as Front Matter Properties and custom default values in web.config private static string ProcessCustomFields(string template, MarkdownFile md, HttpContext ctx) { string[] names = TemplatingHelper.GetAllPlaceHolderNames(template); foreach (string name in names) { //Get current value for the field, from Front Matter or web.config string fldVal = Common.GetFieldValue(name, md); /* * There are two types of fields: * - Value fields: {name} -> Get a value from the properties of the file or from web.config -> Simply replace them * - File processing fields (FPF), ending in .md or .mdh. ej: {{myfile.md}} -> The file is read and it's contents transformed into HTML take the place of the placeholder * Useful for menus, and other independet parts in custom templates and parts of the same page. */ if (fldVal.EndsWith(".md") || fldVal.EndsWith(MarkdownFile.HTML_EXT)) { try { string fpfPath = ctx.Server.MapPath(fldVal); //The File-Processing Field path MarkdownFile mdFld = new MarkdownFile(fpfPath); fldVal = mdFld.RawHTML; //Use the raw HTML, not the processed HTML (this last one includes the template too) //Add the processed file to the dependencies of the currently processed content file, so that the file is invalidated when the FPF changes (if caching is enabled) md.Dependencies.Add(fpfPath); } catch (SecurityException) { fldVal = String.Format("Can't access file for {0}", TemplatingHelper.PLACEHOLDER_PREFIX + name + TemplatingHelper.PLACEHOLDER_SUFIX); } catch (FileNotFoundException) { fldVal = String.Format("File not found for {0}", TemplatingHelper.PLACEHOLDER_PREFIX + name + TemplatingHelper.PLACEHOLDER_SUFIX); } catch (Exception ex) { fldVal = String.Format("Error loading {0}: {1}", TemplatingHelper.PLACEHOLDER_PREFIX + name + TemplatingHelper.PLACEHOLDER_SUFIX, ex.Message); //This should only happen while testing, never in production, so I send the exception's message } } else if (fldVal.StartsWith("~/")) //If its a virtual path to a static file (for example a path to a CSS or JS file) { //Convert relative path to relative URL from the root (changes the "~/" for the root path //of the application. Needed if the current handler is running as a virtual app in IIS) fldVal = VirtualPathUtility.ToAbsolute(fldVal); //There's no need to transform any other virtual path because this is done (and cached) on every file the first time is retrieved and transformed } template = TemplatingHelper.ReplacePlaceHolder(template, name, fldVal); } return(template); }
public const string WEB_CONFIG_PARAM_PREFIX = "MIIS:"; //THe prefix to use to search for parameters in web.config /// <summary> /// Returns the value, if any, for a specified field name. It takes the value from the FrontMatter first, and if it's not there, tries to read it from the current Web.config. /// In web.config it first tries to read them prefixed with "MIIS_" to prevent collision with other products, and then without the prefix. /// If it's not present neither in the Front Matter nor the Web.config, returns the default value. /// </summary> /// <param name="name">The name of the field to retrieve</param> /// <param name="md">An optional Markdown file to check in its front matter</param> /// <param name="defValue">The default value to return if it's not present</param> /// <returns></returns> public static string GetFieldValue(string name, MarkdownFile md = null, string defValue = "") { if (md != null) //If there's a file, possibly with a Front Matter { //Retrieve from the front matter... string val = md.FrontMatter[name]; if (!string.IsNullOrEmpty(val)) { return(val); } } //Retrieve from Web.config using the app-specific prefix or without it if it's not present return(WebHelper.GetParamValue(WEB_CONFIG_PARAM_PREFIX + name, WebHelper.GetParamValue(name, defValue))); }
//Finds fragment placeholders in the template and insert their contents //Fragments are placeholders that start with an asterisk("*") to indicate that instead of finding the value we should //look for a file with the same name as the current one and with the indicated suffix in their name. //If two (.md and .mdh) files exist with that name, the one with the same extension as the current file gets precedence //They allow to insert "fragments" of the same resulting file in the template positions we want. //The placeholders that they contain will be later parsed and processed as normal fields in the file private static string InjectFragments(string layoutHtml, MarkdownFile md, HttpContext ctx) { string tempContent = layoutHtml; string[] fragments = TemplatingHelper.GetAllPlaceHolderNames(tempContent, phPrefix: FILE_FRAGMENT_PREFIX); foreach (string fragmentName in fragments) { string fragmentContent = string.Empty; //Default empty value string fragmentFileName = ctx.Server.MapPath(Path.GetFileNameWithoutExtension(md.FileName) + fragmentName.Substring(FILE_FRAGMENT_PREFIX.Length)); //Removing the "*" at the beginning //Test if a file the same file extension exists if (File.Exists(fragmentFileName + md.FileExt)) { fragmentFileName += md.FileExt; } else //Try with the other file extension (.md or .mdh depending of the current file's extension) { fragmentFileName += (md.FileExt == MarkdownFile.MARKDOWN_DEF_EXT) ? MarkdownFile.HTML_EXT : MarkdownFile.MARKDOWN_DEF_EXT; } //Try to read the file with fragment try { md.AddFileDependency(fragmentFileName); MarkdownFile mdFld = new MarkdownFile(fragmentFileName); //Render the file in the context of the parent file, no its own fragmentContent = RenderLiquidTags(mdFld.RawContent, md); //Render tags in raw content (Markdown or HTML) //If it's Markdown, convert to HTML before substitution if (md.FileExt == MarkdownFile.MARKDOWN_DEF_EXT) { fragmentContent = ConvertMarkdown2Html(fragmentContent, md.UseEmoji, md.EnabledMDExtensions); } } catch { //If something is wrong (normally the file does not exist) simply return an empty string //We don't want to force this kind of files to always exist fragmentContent = string.Empty; } //Replace the placeholder with the value tempContent = TemplatingHelper.ReplacePlaceHolder(tempContent, fragmentName, fragmentContent); } return(tempContent); }
public const string WEB_CONFIG_PARAM_PREFIX = "MIIS:"; //THe prefix to use to search for parameters in web.config public static string GetFieldValueFromFM(string name, MarkdownFile md, string defValue = "") { if (md != null) //If there's a file, possibly with a Front Matter { //Retrieve from the front matter... string val = md.FrontMatter[name]; if (!string.IsNullOrEmpty(val)) { return(val); } else { return(defValue); //Return defValue if field is not available } } else { return(defValue); //Return defValue if there's not MD file to process } }
//Finds fragment placeholders and insert their contents private static string ProcessFragments(string template, MarkdownFile md, HttpContext ctx) { string[] fragments = TemplatingHelper.GetAllPlaceHolderNames(template, phPrefix: FILE_FRAGMENT_PREFIX); foreach (string fragmentName in fragments) { string fragmentContent = string.Empty; //Default empty value string fragmentFileName = ctx.Server.MapPath(Path.GetFileNameWithoutExtension(md.FileName) + fragmentName.Substring(FILE_FRAGMENT_PREFIX.Length)); //Removing the "*" at the beggining //Test if a file the same file extension exists if (File.Exists(fragmentFileName + md.FileExt)) { fragmentFileName += md.FileExt; } else if (File.Exists(fragmentFileName + ".md")) //Try with .md extension { fragmentFileName += ".md"; } else { fragmentFileName += ".mdh"; //Try with .mdh } //Try to read the file with fragment try { md.Dependencies.Add(fragmentFileName); MarkdownFile mdFld = new MarkdownFile(fragmentFileName); fragmentContent = mdFld.RawHTML; } catch { //If something is wrong (normally the file does not exist) simply return an empty string //We don't want to force this kind of files to always exist fragmentContent = string.Empty; } //Replace the placeholder with the value template = TemplatingHelper.ReplacePlaceHolder(template, fragmentName, fragmentContent); } return(template); }
/// <summary> /// Gets the relative path of the template to use with the current file taking into account all the possible parameters/fields that control this setting /// </summary> /// <returns></returns> private static string GetCurrentTemplateFile(MarkdownFile md) { //Get the template name that is going to be used (Front Matter or configuration), if any. string templateName = Common.GetFieldValue("TemplateName", md); if (string.IsNullOrEmpty(templateName)) { return(string.Empty); //Use the default basic HTML5 template } //The name (or sub-path) for the layout file (.html normaly) to be used string layoutName = Common.GetFieldValue("Layout", md); if (string.IsNullOrEmpty(layoutName)) { return(string.Empty); //Use the default basic HTML5 template } //If both the template folder and the layout are established, then get the base folder for the templates //This base path for the templates parameter is only available through Web.config. NOT in the file Front Matter (we're skipping the file in the following call) string basePath = Common.GetFieldValue("TemplatesBasePath", defValue: "~/Templates/"); return(VirtualPathUtility.AppendTrailingSlash(basePath) + VirtualPathUtility.AppendTrailingSlash(templateName) + layoutName); }
private static string FILE_FRAGMENT_PREFIX = "*"; //How to identify fragments placeholders in content files #endregion #region Methods /// <summary> /// Renders the HTML from the markdown using the templates and parameters specified in web.config /// and processing the templates /// </summary> /// <param name="md">The markdown file information</param> /// <returns>The final HTML to return to the client</returns> public static string RenderMarkdown(MarkdownFile md) { HttpContext ctx = HttpContext.Current; string template = DEFAULT_TEMPLATE; //The default template for the final HTML string templateFile = GetCurrentTemplateFile(md); if (!string.IsNullOrEmpty(templateFile)) { List <string> templateDependencies = new List <string>(); template = ReadTemplate(templateFile, ctx, templateDependencies); //Read, transform and cache template //Add template file's dependences as dependences for the Markdown file cache too md.Dependencies.AddRange(templateDependencies); } //First process the "content" field with the main HTML content transformed from Markdown //This allows to use other fields inside the content itself, not only in the templates string finalContent = TemplatingHelper.ReplacePlaceHolder(template, "content", md.RawHTML); //Process fragments (other files inserted into the current one or template) finalContent = ProcessFragments(finalContent, md, ctx); //Process well-known fields one by one finalContent = TemplatingHelper.ReplacePlaceHolder(finalContent, "title", md.Title); finalContent = TemplatingHelper.ReplacePlaceHolder(finalContent, "filename", md.FileName); finalContent = TemplatingHelper.ReplacePlaceHolder(finalContent, "datecreated", md.DateCreated.ToString()); finalContent = TemplatingHelper.ReplacePlaceHolder(finalContent, "datemodified", md.DateLastModified.ToString()); finalContent = TemplatingHelper.ReplacePlaceHolder(finalContent, "isauthenticated", ctx.User.Identity.IsAuthenticated.ToString()); finalContent = TemplatingHelper.ReplacePlaceHolder(finalContent, "authtype", ctx.User.Identity.AuthenticationType); finalContent = TemplatingHelper.ReplacePlaceHolder(finalContent, "username", ctx.User.Identity.Name); //Process custom fields finalContent = ProcessCustomFields(finalContent, md, ctx); //Transfrom virtual paths finalContent = WebHelper.TransformVirtualPaths(finalContent); //Return the transformed file return(finalContent); }
//Registers all custom Front-Matter sources inside the assembly passed as a parameter private static void RegisterCustomFMSourcesInAssembly(Assembly assembly) { //Custom FM sources are obtained from classes in the FMSources namespace that implement the IFMSource interface var fmSources = from c in assembly.GetTypes() where c.IsClass && c.Namespace == CUSTOM_FMSOURCES_NAMESPACE && typeof(IFMSource).IsAssignableFrom(c) select c; //Register each FMSource globally using its factory method (GetFilterType) fmSources.ToList().ForEach(fmSourceClass => { IFMSource fms = (IFMSource)Activator.CreateInstance(fmSourceClass); //Register possible fields that will define different caches for the file if (fms is IQueryStringDependent) { MarkdownFile.AddCachingQueryStringFields( (fms as IQueryStringDependent).GetCachingQueryStringFields() ); } FieldValuesHelper.AddFrontMatterSource(fms.SourceName, fms.GetType()); }); }
//Constructor internal MDFieldsResolver(MarkdownFile mdFile) { _parentFile = mdFile; _mdProxy = new MIISFile(_parentFile); _ctx = HttpContext.Current; }
//Retrieves the value for the specified field or returns an empty string if it doesn't exist protected override object GetValue(string name) { object res = ""; //Default value (empty string) switch (name.ToLowerInvariant()) { //Check well Known fields first case INTERNAL_REFERENCE_TO_CURRENT_FILE: //This is intended to be used internally only, from custom tags or front-matter custom sources res = _mdProxy; break; case "content": //The final HTML content, WITHOUT the template and WITH liquid tags processed res = _parentFile.RawFinalHtml; //This is needed to avoid that the Markdown conversion messes up with the liquid tags (loops, conditionals...) break; case "title": res = _parentFile.Title; break; case "excerpt": case "description": case "summary": res = _parentFile.Excerpt; break; case "filename": res = _parentFile.FileName; break; case "filenamenoext": res = _parentFile.FileNameNoExt; break; case "fileext": res = _parentFile.FileExt; break; case "dir": res = _mdProxy.Dir; break; case "date": res = _parentFile.Date; break; case "datecreated": res = _parentFile.DateCreated; break; case "datemodified": res = _parentFile.DateLastModified; break; case "isauthenticated": res = _ctx.User.Identity.IsAuthenticated; break; case "authtype": res = _ctx.User.Identity.AuthenticationType; break; case "username": res = _ctx.User.Identity.Name; break; case "domain": res = _ctx.Request.Url.Authority; break; case "baseurl": res = $"{_ctx.Request.Url.Scheme}{System.Uri.SchemeDelimiter}{_ctx.Request.Url.Authority}"; break; case "clientip": res = WebHelper.GetIPAddress(); break; case "now": case "today": res = DateTime.Now; break; case "time": res = DateTime.Now.ToString("hh:mm:ss tt"); break; case "url": res = _ctx.Request.RawUrl; break; case "urlnoext": res = IOHelper.RemoveFileExtension(_ctx.Request.RawUrl); //Files processed by MIIS always have extension on disk //res = _ctx.Request.Path.Remove(_ctx.Request.Path.LastIndexOf(".")); break; case "templatename": res = _parentFile.TemplateName; break; case "layout": res = _parentFile.Layout; break; //Custom fields default: Exception exToBeRaised = null; //Possible exceptions raised by the next code //Check if the custom field has already been retrieved before bool isCached = InternalFileFieldCache.TryGetValue(name, out res); //If it's cached the value will be saved to res if (!isCached) //If it's not cached (has not been retrieved before) then retrieve it { res = string.Empty; //Default value /* * There are 4 types of custom fields: * - Value fields: {{name}} -> Get a value from the Front-Matter or from web.config -> Simply replace them (default assumption) * - File processing fields (FPF), {{name}} whose value ends in .md or .mdh. ej: myfile.md -> if available the file is read and it's contents transformed into HTML take the place of the placeholder * Useful for menus, and other independent parts in custom templates and parts of the same page. * - Custom Dinamic Field Sources, {{name}} value that start with !! and use a custom class to populate the field with an object. Ej: !!customSource param1 param2 * - Querystring or Form fields, retrieved from the current request */ //Try to get a typed value for the field var typedValue = FieldValuesHelper.GetFieldObject(name, _parentFile, null); //If we get a string already, then process it if (typedValue is string) { //If it's a string, process it for special fields ////////////////////////////// //Simple value fields (default value if present) ////////////////////////////// string resAsString = typedValue.ToString(); ////////////////////////////// //First, Custom Dinamic Field Sources that provide values from external assemblies ////////////////////////////// if (resAsString.StartsWith(FRONT_MATTER_SOURCES_PREFIX)) { //Get the name of the source and it's params splitting the string (the first element would be the name of the source, and the rest, the parameters, if any string[] srcelements = resAsString.Substring(FRONT_MATTER_SOURCES_PREFIX.Length).Trim().Split(new char[0], StringSplitOptions.RemoveEmptyEntries); if (srcelements.Length > 0) { try { res = FieldValuesHelper.GetFieldValueFromFMSource(srcelements[0], _mdProxy, srcelements.Skip(1).ToArray()); } catch (Exception ex) { //Throw the exception to be reflected in the exToBeRaised = ex; } } } ////////////////////////////// //Second, File Processing Fields, that inject the content of .md or .mdh processing their inner fields in their own context //This is for compatbility reasons with MIIS v1.x and 2.x ////////////////////////////// else if (resAsString.ToLowerInvariant().EndsWith(MarkdownFile.MARKDOWN_DEF_EXT) || resAsString.ToLowerInvariant().EndsWith(MarkdownFile.HTML_EXT)) { //This kind of fields can only be processed in the first level of liquid tags processing. //MustProcessSubFiles is false in the second level //If this is a second level (a FPF inside another FPF) will just return an empty string (won't be processed at all) if (_parentFile.MustProcessSubFiles) { try { string fpfPath = _ctx.Server.MapPath(resAsString); //The File-Processing Field path MarkdownFile insertedFile = new MarkdownFile(fpfPath, false); //No processing of FPF beyond this layer is allowed to prevent circular references //If the parent file is a Markdown file if (_parentFile.FileExt == MarkdownFile.MARKDOWN_DEF_EXT) { //HACK: Since {{field}} placeholders are processed BEFORE transforming into HTML //I need to wrap the injected HTML into a special tag to prevent further processing of the resulting HTML when converting //the main file contents to HTML. The reason is that mixed HTML is very tricky and can lead to unexpected results //This is a sloppy way to do it, but it's the only way to mark a section of markdown as "not processable" //See: https://github.com/lunet-io/markdig/blob/master/src/Markdig.Tests/Specs/CommonMark.md#html-blocks //Later we need to remove these delimiters in a sloppy way too :-( res = HTML_NO_PROCESSING_DELIMITER_BEGIN + insertedFile.ComponentHtml + HTML_NO_PROCESSING_DELIMITER_END; } else { //If the parent file is already an HTML file, there's no need for the previous hack res = insertedFile.ComponentHtml; //Use the final HTML (WITHOUT the template (except in components) and WITH the liquid tags processed in its own context) } //Add the processed file to the dependencies of the currently processed content file, //so that the file is invalidated when the FPF changes (if caching is enabled) //The FPF is already cached too if caching is enabled _parentFile.AddFileDependency(fpfPath); } catch (System.Security.SecurityException) { res = String.Format("Can't access file for {0}", TemplatingHelper.PLACEHOLDER_PREFIX + name + TemplatingHelper.PLACEHOLDER_SUFFIX); } catch (System.IO.FileNotFoundException) { res = String.Format("File not found for {0}", TemplatingHelper.PLACEHOLDER_PREFIX + name + TemplatingHelper.PLACEHOLDER_SUFFIX); } catch (Exception ex) { //This should only happen while testing, never in production, so I send the exception's message res = String.Format("Error loading {0}: {1}", TemplatingHelper.PLACEHOLDER_PREFIX + name + TemplatingHelper.PLACEHOLDER_SUFFIX, ex.Message); } } } ////////////////////////////// //Finally, if it's not a custom source, or a FPF, then is a normal raw string value ////////////////////////////// else { res = resAsString; } } else { //If we already got a typed value, then return it by default res = typedValue; //Check if it's null. If it is null, means it hasn't been found in he fields for the file or app, //so maybe the last chance is that it's a request param if (typedValue == null) { ////////////////////////////// //Try to determine the param value from the querystring or the form values ////////////////////////////// if (!string.IsNullOrWhiteSpace(_ctx.Request.Params[name])) { var paramVal = _ctx.Request.Params[name]; //Result (checks qs, form data, cookies and sv, in that order) if (!string.IsNullOrWhiteSpace(paramVal)) { res = paramVal; //A value has been found _parentFile.CachingEnabled = false; //Disable caching if a param is to be used } } } } //Cache the retrieved value InternalFileFieldCache[name] = res; //If there's been an exception, raise it to inform the renderer about it if (exToBeRaised != null) { throw exToBeRaised; } } //Get out of the switch construction break; } //Return retrieved value return(res); }
public MIISFile(MarkdownFile mdFile) { _md = mdFile; }