Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Jon Dunfee 199 posts 468 karma points
    Jan 18, 2014 @ 17:14
    Jon Dunfee
    0

    RenderMacro for a Lucene Index

    In short, I've tapped into the GatheringNodeData event on a Lucene indexer to massage the contents of the index. I have that all working but I can't seem to successfully render macros inside my content strings.  Here's my helper method:

    public static string GetContent(string content, int pageId = 0)
    {
        var regexMacro = new Regex(@"<\?UMBRACO_MACRO[^>]+>");
        return regexMacro.Replace(content, delegate(Match m)
            {
                var macroContent = umbraco.library.RenderMacroContent(m.Value, pageId);
                if (regexMacro.IsMatch(macroContent))
                {
                    macroContent = GetContent(macroContent, pageId);
                }
                return macroContent;
            });
    }
    

    I can't get any macro to render I get a null exception.  As a test, I replaced all contents of my cshtml macro script with just "test", but I still receive the following:

    "<!-- Error generating macroContent: 'System.NullReferenceException: Object reference not set to an instance of an object.\r\n   at umbraco.page..ctor(XmlNode node)\r\n   at umbraco.library.RenderMacroContent(String Text, Int32 PageId)' -->"

    The comment on the RenderMacroContent method states, "This only works properly with xslt macros. Python and .ascx based macros will not render properly, as viewstate is not included.".  Anyone have an idea I can attempt to get these pages to render with all its content so I can index them to my liking?

  • Jon Dunfee 199 posts 468 karma points
    Jan 19, 2014 @ 19:08
    Jon Dunfee
    0

    Here's my 2nd attempt: 

    public static string GetContent(string content, int pageId = 0)
    {
        var regexMacro =newRegex(@"<\?UMBRACO_MACRO[^>]+>");
        return regexMacro.Replace(content, delegate(Match m)
            {
                var aliasMatch = Regex.Match(m.Value, "alias=.([^\"']+).", RegexOptions.IgnoreCase);
                if (!aliasMatch.Success) return string.Empty; // macro must be screwed up to not have an alias
    
                var macro = umbraco.macro.GetMacro(aliasMatch.Groups[1].Value);
                var attribs = new Hashtable();
                macro.Model.Properties.ForEach(p =>
                    {
                        var pMatch = Regex.Match(m.Value, string.Format("{0}=\"([^\"]+)\"", p.Key),
                                                 RegexOptions.IgnoreCase);
                        attribs.Add(p.Key, (pMatch.Success) ? pMatch.Groups[1].Value : string.Empty);
                    });
                macro.UpdateMacroModel(attribs);
                var macroContentControl = macro.renderMacro(attribs, pageId);
                var page = new Page();
                page.Controls.Add(macroContentControl);
                var sw = new StringWriter();
                using (var htw = new HtmlTextWriter(sw))
                {
                    page.RenderControl(htw);
                }
                var macroContent = sw.ToString();
    
                // Check to see if the macro content has another macro to render
                if (regexMacro.IsMatch(macroContent))
                {
                    macroContent = GetContent(macroContent, pageId);
                }
                return macroContent;
            });
    }
    

    I received an error about not having an HttpContext so I created a dummy one in the GatheringNodeData event like so:

    // mock up a context if necessary
    if (HttpContext.Current == null)
    {
        HttpContext.Current = new HttpContext(
            new HttpRequest("", "http://mydomain.com", ""),
            new HttpResponse(new StringWriter()))
            {
                User = new GenericPrincipal(
                    new GenericIdentity("admin"),
                    new string[0]
                    )
            };
    }
    

    This didn't work either, so I gave up and manually gather the content based on the macro parameters. I only have two macros I use in the editor, so this is what I ended up with:

    public static string GetContent(string content, int pageId = 0)
    {
        var regexMacro =newRegex(@"<\?UMBRACO_MACRO[^>]+>");
        return regexMacro.Replace(content, delegate(Match m)
            {
                var aliasMatch = Regex.Match(m.Value, "alias=.([^\"']+).", RegexOptions.IgnoreCase);
                if (!aliasMatch.Success) return string.Empty; // macro must be screwed up to not have an alias
    
                var macro = umbraco.macro.GetMacro(aliasMatch.Groups[1].Value);
    
                var cs = SearchService.Instance.ContentService;
                var sb = new StringBuilder();
                switch (macro.Alias)
                {
                    case "GuideForms":
                        macro.Model.Properties.ForEach(p =>
                            {
                                var val = Regex.Match(m.Value,
                                                      string.Format("{0}=.([^\"']+).", p.Key),
                                                      RegexOptions.IgnoreCase);
                                if (val.Success && !string.IsNullOrWhiteSpace(val.Groups[1].Value))
                                {
                                    if (p.Key.StartsWith("formPick", StringComparison.InvariantCultureIgnoreCase))
                                    {
                                        var form = new DynamicNode(val.Groups[1].Value);
                                        var formName = (form.HasValue("formName"))
                                                           ? form.GetPropertyValue("formName")
                                                           : form.Name;
                                        sb.AppendFormat("{0} {1} ", form.GetPropertyValue("formID"),
                                                        formName);
                                    }
                                }
                                if (p.Key.StartsWith("formInfo"))
                                {
                                    var info = Regex.Match(m.Value,
                                                           string.Format("{0}=.([^\"']+).", p.Key),
                                                           RegexOptions.IgnoreCase);
                                    if (info.Success && string.IsNullOrWhiteSpace(info.Groups[1].Value))
                                    {
                                        sb.AppendFormat("{0} ", info.Groups[1].Value);
                                    }
                                }
                            });
                        break;
                    case "GuideNote":
                        var nid = Regex.Match(m.Value, "nodeId=.([^\"']+).", RegexOptions.IgnoreCase);
                        if (nid.Success && !string.IsNullOrWhiteSpace(nid.Groups[1].Value))
                        {
                            var note = new DynamicNode(nid.Groups[1].Value);
                            sb.AppendFormat("{0} ", note.GetPropertyValue("content"));
    
                        }
                        break;
                }
                var macroContent = sb.ToString();
    
                // Check to see if the macro content has another macro to render
                if (regexMacro.IsMatch(macroContent))
                {
                    macroContent = GetContent(macroContent, pageId);
                }
                return macroContent;
            });
    }
    

    If someone has a solution to either of the first two that would be great! This gets the job done at least.  Thought I'd post it for someone else travelling down this path or correct me if there's a simpler path.

Please Sign in or register to post replies

Write your reply to:

Draft