public override bool Render(IInternalContextAdapter context, TextWriter writer, INode node) { IEngineContext railsContext = EngineContextLocator.Instance.LocateCurrentContext(); IViewComponentRegistry registry = railsContext.Services.GetService<IViewComponentFactory>().Registry; IViewComponentDescriptorProvider viewDescProvider = railsContext.Services.GetService<IViewComponentDescriptorProvider>(); ICacheProvider cacheProvider = railsContext.Services.CacheProvider; INode compNameNode = node.GetChild(0); if (compNameNode == null) { String message = String.Format("You must specify the component name on the #{0} directive", Name); throw new ViewComponentException(message); } string componentName = compNameNode.FirstToken.Image; if (componentName == null) { String message = String.Format("Could not obtain component name from the #{0} directive", Name); throw new ViewComponentException(message); } if (componentName.StartsWith("$")) { String nodeContent = compNameNode.Literal.Trim('"', '\''); SimpleNode inlineNode = runtimeServices.Parse(new StringReader(nodeContent), context.CurrentTemplateName, false); inlineNode.Init(context, runtimeServices); componentName = (string) Evaluate(inlineNode, context); } IDictionary componentParams = CreateParameters(context, node); Type viewComptype = registry.GetViewComponent(componentName); ViewComponentDescriptor descriptor = null; CacheKey key = null; if (viewComptype != null) { descriptor = viewDescProvider.Collect(viewComptype); } bool isOutputtingToCache = false; ViewComponentCacheBag bag = null; if (descriptor != null && descriptor.IsCacheable) { key = descriptor.CacheKeyGenerator.Create(componentName, componentParams, railsContext); if (key != null) { ViewComponentCacheBag cachedContent = (ViewComponentCacheBag) cacheProvider.Get(key.ToString()); if (cachedContent != null) { // Restore entries foreach(KeyValuePair<string, object> pair in cachedContent.ContextEntries) { context[pair.Key] = pair.Value; } // Render from cache writer.Write(cachedContent.Content); return true; } isOutputtingToCache = true; bag = new ViewComponentCacheBag(); } } ViewComponent component = viewComponentFactory.Create(componentName); if (component == null) { throw new MonoRailException("ViewComponentFactory returned a null ViewComponent for " + componentName + ". " + "Please investigate the implementation: " + viewComponentFactory.GetType().FullName); } try { ASTDirective directiveNode = (ASTDirective) node; IViewRenderer renderer = (IViewRenderer) directiveNode.Directive; NVelocityViewContextAdapter contextAdapter = new NVelocityViewContextAdapter(componentName, node, viewEngine, renderer); contextAdapter.Context = isOutputtingToCache ? new CacheAwareContext(context, bag) : context; INode bodyNode = null; if (node.ChildrenCount > 0) { bodyNode = node.GetChild(node.ChildrenCount - 1); } TextWriter output = isOutputtingToCache ? bag.CacheWriter : writer; contextAdapter.BodyNode = bodyNode; contextAdapter.ComponentParams = componentParams; contextAdapter.TextWriter = output; component.Init(railsContext, contextAdapter); ProcessSubSections(component, contextAdapter); const string ViewComponentContextKey = "viewcomponent"; object previousComp = context[ViewComponentContextKey]; try { context[ViewComponentContextKey] = component; component.Render(); if (contextAdapter.ViewToRender != null) { RenderComponentView(context, contextAdapter.ViewToRender, output, contextAdapter); } if (isOutputtingToCache) { // Save output cacheProvider.Store(key.ToString(), bag); // Output to correct writer writer.Write(bag.Content); } } finally { if (previousComp != null) { context[ViewComponentContextKey] = previousComp; } else { context.Remove(ViewComponentContextKey); } } } finally { viewComponentFactory.Release(component); } return true; }
public CacheAwareContext(IInternalContextAdapter context, ViewComponentCacheBag bag) { this.context = context; this.bag = bag; }