/// <summary>
        /// Renders the macro output as a string
        /// </summary>
        /// <param name="macroAlias">The macro alias.</param>
        /// <param name="macroParams">The macro params.</param>
        /// <param name="currentControllerContext">The current controller context.</param>
        /// <param name="isForRichTextEditor">If the request is to render the contents in the back office rich text editor</param>
        /// <param name="resolveContent">The method to call in order to resolve the content to render.</param>
        /// <param name="resolveMember">The method to call in order to resolve the current member. If null, this parameter is ignored</param>
        /// <returns></returns>
        public string RenderMacroAsString(
            string macroAlias,
            IDictionary <string, string> macroParams,
            ControllerContext currentControllerContext,
            bool isForRichTextEditor,
            Func <Content> resolveContent, /* CurrentPage */
            Func <Member> resolveMember /* CurrentMember */)
        {
            // if we're rendering inside the rich text editor, bypass all caching and return the fresh result.
            if (isForRichTextEditor)
            {
                return(GetMacroStringOutput(
                           macroAlias,
                           RenderMacro(macroAlias, macroParams, currentControllerContext, true, resolveContent),
                           currentControllerContext));
            }

            // Macro text is cached in the ApplicationCache based on it's parameters, se we need to build that cache key...

            // get the macro model
            var macroModel = GetMacroModel(macroAlias);

            // get the content id to pass in to the macro cache key builder.
            // null indicates not to cache by page.
            HiveId?contentId = null;

            if (macroModel.Item1.CacheByPage)
            {
                if (resolveContent != null)
                {
                    contentId = resolveContent().Id;
                }
            }

            // get the member id to pass into the macro cache key builder.
            // null indicates not to cache by member.
            HiveId?memberId = null;

            if (macroModel.Item1.CachePersonalized)
            {
                if (resolveMember != null)
                {
                    memberId = resolveMember().Id;
                }
            }

            // build the cache key of the macro
            var macroCacheKey = GetMacroCacheKey(macroAlias, macroParams, contentId, memberId);

            // now generate the content for it.
            string macroContent       = null;
            string cachedMacroContent = null;

            cachedMacroContent = _applicationContext.FrameworkContext.ApplicationCache.GetOrCreate(macroCacheKey, () =>
            {
                // generate the content of the macro, since it's not in the cache.
                macroContent = GetMacroStringOutput(
                    macroAlias,
                    RenderMacro(macroAlias, macroParams, currentControllerContext, false, resolveContent),
                    currentControllerContext);

                // bail if cache period is zero.
                if (macroModel.Item1.CachePeriodSeconds <= 0)
                {
                    return(null);
                }

                // return the cache parameters
                var cacheParams = new HttpRuntimeCacheParameters <string>(macroContent);
                if (macroModel.Item2 != null && macroModel.Item2 is File)
                {
                    // add file dependency
                    cacheParams.Dependencies = new CacheDependency(macroModel.Item2.RootedPath);
                }
                cacheParams.SlidingExpiration = new TimeSpan(0, 0, 0, macroModel.Item1.CachePeriodSeconds);
                return(cacheParams);
            });

            // return either the cahed contnet or the generated content.
            return(cachedMacroContent ?? macroContent);
        }
Exemple #2
0
        /// <summary>
        /// Performs the action rendering
        /// </summary>
        /// <param name="macroAlias"></param>
        /// <param name="currentControllerContext"></param>
        /// <param name="isForRichTextEditor">If the request is to render the contents in the back office rich text editor</param>
        /// <param name="resolveContent">callback to get the 'Content' model</param>
        /// <param name="macroParams"></param>
        /// <returns></returns>
        /// <remarks>
        ///
        /// We need to check if this is for the rich text editor, in which case, we need to bypass any caching
        /// so that it renders out the correct content,
        /// Then if its not for the RTE, we need to check our cache to see if its in there, if so then we'll just
        /// return it, otherwise we will add the cached item with a dependency on our cache 'File' path.
        ///
        /// </remarks>
        public ActionResult RenderMacro(
            string macroAlias,
            IDictionary <string, string> macroParams,
            ControllerContext currentControllerContext,
            bool isForRichTextEditor,
            Func <Content> resolveContent)
        {
            ActionResult macroResult = null;

            if (!isForRichTextEditor)
            {
                //if its not for rich text....

                try
                {
                    var output = _applicationContext.FrameworkContext
                                 .ApplicationCache.GetOrCreate("umb-macro-" + macroAlias + macroParams.GetHashCode(),
                                                               () =>
                    {
                        var macroModel = GetMacroModel(macroAlias);

                        //set the macroResult to the local variable
                        macroResult = GetMacroResult(macroAlias, () => macroModel.Item1, resolveContent, macroParams, currentControllerContext);
                        //if it is null, it means that there was no content item
                        if (macroResult == null)
                        {
                            return(null);
                        }

                        //check if the macro should be cached at all
                        if (!macroModel.Item1.CacheByPage)
                        {
                            //By returning null, this will not be added to the cache and a null value returned
                            return(null);
                        }
                        //TODO: Check caching by member!

                        //return our caching parameters
                        //TODO: We might not want a 'normal' cache dependency at some point, need to determine a way to specify cache dependencies or create a custom one based on the 'File' object or something
                        var cacheParams = new HttpRuntimeCacheParameters <ActionResult>(macroResult)
                        {
                            Dependencies      = new CacheDependency(macroModel.Item2.RootedPath),
                            SlidingExpiration = new TimeSpan(0, 0, 0, macroModel.Item1.CachePeriodSeconds)
                        };
                        return(cacheParams);
                    });

                    //if this is null, it means:
                    // - there was no current node, or it didn't get cached because the macro definition said to not cache it.
                    //then we can check if our local 'macroResult' variable was set, if so it means:
                    // - there was a current node and it simply wasn't cached because of the macro definition.
                    if (output != null)
                    {
                        return((ActionResult)output);
                    }
                    if (macroResult != null)
                    {
                        return(macroResult);
                    }
                    //return null because there must be no 'currentNode'
                    return(null);
                }
                catch (ApplicationException ex)
                {
                    //if there's an exception, display a friendly message and log the error
                    var txt   = "Macro.RenderingFailed.Message".Localize(this, new { Error = ex.Message, MacroName = macroAlias });
                    var title = "Macro.RenderingFailed.Title".Localize();
                    LogHelper.Error <MacroRenderer>(txt, ex);
                    return(MacroError(txt, title));
                }
            }
            else
            {
                try
                {
                    //if it is for rich text...
                    var macroModel = GetMacroModel(macroAlias);

                    return(!macroModel.Item1.RenderContentInEditor
                        ? NoRichTextRenderMode(macroAlias)
                        : GetMacroResult(macroAlias, () => macroModel.Item1, resolveContent, macroParams, currentControllerContext));
                }
                catch (ApplicationException ex)
                {
                    //if there's an exception, display a friendly message and log the error
                    var txt   = "Macro.RenderingFailed.Message".Localize(this, new { Error = ex.Message, MacroName = macroAlias });
                    var title = "Macro.RenderingFailed.Title".Localize();
                    LogHelper.Error <MacroRenderer>(txt, ex);
                    return(MacroError(txt, title));
                }
            }
        }
        /// <summary>
        /// Performs the action rendering
        /// </summary>
        /// <param name="macroAlias"></param>
        /// <param name="currentControllerContext"></param>
        /// <param name="isForRichTextEditor">If the request is to render the contents in the back office rich text editor</param>
        /// <param name="resolveContent">callback to get the 'Content' model</param>
        /// <param name="macroParams"></param>
        /// <returns></returns>
        /// <remarks>
        /// 
        /// We need to check if this is for the rich text editor, in which case, we need to bypass any caching
        /// so that it renders out the correct content,
        /// Then if its not for the RTE, we need to check our cache to see if its in there, if so then we'll just 
        /// return it, otherwise we will add the cached item with a dependency on our cache 'File' path.
        /// 
        /// </remarks>
        public ActionResult RenderMacro(
            string macroAlias,
            IDictionary<string, string> macroParams,
            ControllerContext currentControllerContext,
            bool isForRichTextEditor,
            Func<Content> resolveContent)
        {           

            ActionResult macroResult = null;

            if (!isForRichTextEditor)
            {
                //if its not for rich text....

                try
                {
                    var output = _applicationContext.FrameworkContext
                                .ApplicationCache.GetOrCreate("umb-macro-" + macroAlias + macroParams.GetHashCode(),
                                                              () =>
                                                              {
                                                                  var macroModel = GetMacroModel(macroAlias);

                                                                  //set the macroResult to the local variable
                                                                  macroResult = GetMacroResult(macroAlias, () => macroModel.Item1, resolveContent, macroParams, currentControllerContext);
                                                                  //if it is null, it means that there was no content item
                                                                  if (macroResult == null)
                                                                      return null;

                                                                  //check if the macro should be cached at all
                                                                  if (!macroModel.Item1.CacheByPage)
                                                                  {
                                                                      //By returning null, this will not be added to the cache and a null value returned
                                                                      return null;
                                                                  }
                                                                  //TODO: Check caching by member!

                                                                  //return our caching parameters
                                                                  //TODO: We might not want a 'normal' cache dependency at some point, need to determine a way to specify cache dependencies or create a custom one based on the 'File' object or something
                                                                  var cacheParams = new HttpRuntimeCacheParameters<ActionResult>(macroResult)
                                                                      {
                                                                          Dependencies = new CacheDependency(macroModel.Item2.RootedPath),
                                                                          SlidingExpiration = new TimeSpan(0, 0, 0, macroModel.Item1.CachePeriodSeconds)
                                                                      };
                                                                  return cacheParams;
                                                              });

                    //if this is null, it means:
                    // - there was no current node, or it didn't get cached because the macro definition said to not cache it.
                    //then we can check if our local 'macroResult' variable was set, if so it means:
                    // - there was a current node and it simply wasn't cached because of the macro definition.
                    if (output != null)
                        return (ActionResult)output;
                    if (macroResult != null)
                        return macroResult;
                    //return null because there must be no 'currentNode'
                    return null;

                }
                catch (ApplicationException ex)
                {
                    //if there's an exception, display a friendly message and log the error
                    var txt = "Macro.RenderingFailed.Message".Localize(this, new { Error = ex.Message, MacroName = macroAlias });
                    var title = "Macro.RenderingFailed.Title".Localize();
                    LogHelper.Error<MacroRenderer>(txt, ex);
                    return MacroError(txt, title);
                }

                
            }
            else
            {
                try
                {
                    //if it is for rich text...
                    var macroModel = GetMacroModel(macroAlias);

                    return !macroModel.Item1.RenderContentInEditor
                        ? NoRichTextRenderMode(macroAlias)
                        : GetMacroResult(macroAlias, () => macroModel.Item1, resolveContent, macroParams, currentControllerContext);
                }
                catch (ApplicationException ex)
                {
                    //if there's an exception, display a friendly message and log the error
                    var txt = "Macro.RenderingFailed.Message".Localize(this, new { Error = ex.Message, MacroName = macroAlias });
                    var title = "Macro.RenderingFailed.Title".Localize();
                    LogHelper.Error<MacroRenderer>(txt, ex);
                    return MacroError(txt, title);
                }
            }

        }
        /// <summary>
        /// Renders the macro output as a string
        /// </summary>
        /// <param name="macroAlias">The macro alias.</param>
        /// <param name="macroParams">The macro params.</param>
        /// <param name="currentControllerContext">The current controller context.</param>
        /// <param name="isForRichTextEditor">If the request is to render the contents in the back office rich text editor</param>
        /// <param name="resolveContent">The method to call in order to resolve the content to render.</param>
        /// <param name="resolveMember">The method to call in order to resolve the current member. If null, this parameter is ignored</param>
        /// <returns></returns>
        public string RenderMacroAsString(
            string macroAlias,
            IDictionary<string, string> macroParams,
            ControllerContext currentControllerContext,
            bool isForRichTextEditor,
            Func<Content> resolveContent, /* CurrentPage */
            Func<Member> resolveMember /* CurrentMember */)
        {

            // if we're rendering inside the rich text editor, bypass all caching and return the fresh result.
            if (isForRichTextEditor)
            {
                return GetMacroStringOutput(
                    macroAlias,
                    RenderMacro(macroAlias, macroParams, currentControllerContext, true, resolveContent),
                    currentControllerContext);
            }

            // Macro text is cached in the ApplicationCache based on it's parameters, se we need to build that cache key...

            // get the macro model
            var macroModel = GetMacroModel(macroAlias);

            // get the content id to pass in to the macro cache key builder.
            // null indicates not to cache by page.
            HiveId? contentId = null;
            if (macroModel.Item1.CacheByPage)
            {
                if (resolveContent != null)
                    contentId = resolveContent().Id;
            }

            // get the member id to pass into the macro cache key builder.
            // null indicates not to cache by member.
            HiveId? memberId = null;
            if (macroModel.Item1.CachePersonalized)
            {
                if (resolveMember != null)
                    memberId = resolveMember().Id;
            }

            // build the cache key of the macro
            var macroCacheKey = GetMacroCacheKey(macroAlias, macroParams, contentId, memberId);

            // now generate the content for it.
            string macroContent = null;
            string cachedMacroContent = null;

            cachedMacroContent = _applicationContext.FrameworkContext.ApplicationCache.GetOrCreate(macroCacheKey, () =>
            {
                // generate the content of the macro, since it's not in the cache.
                macroContent = GetMacroStringOutput(
                    macroAlias,
                    RenderMacro(macroAlias, macroParams, currentControllerContext, false, resolveContent),
                    currentControllerContext);

                // bail if cache period is zero.
                if (macroModel.Item1.CachePeriodSeconds <= 0) return null;

                // return the cache parameters
                var cacheParams = new HttpRuntimeCacheParameters<string>(macroContent);
                if (macroModel.Item2 != null && macroModel.Item2 is File)
                {
                    // add file dependency
                    cacheParams.Dependencies = new CacheDependency(macroModel.Item2.RootedPath);
                }
                cacheParams.SlidingExpiration = new TimeSpan(0, 0, 0, macroModel.Item1.CachePeriodSeconds);
                return cacheParams;
            });

            // return either the cahed contnet or the generated content.
            return cachedMacroContent ?? macroContent;
        }