1

To publish ECL Items we have placed a custom build TBB to add external binary to our file system.

On publishing ECL Items we're getting error as Cannot access a closed Stream.

Error:

The number of render failures has exceeded its specified failure limit of 0. Cannot access a closed Stream.

Component: Tridion.ContentManager.Publishing Errorcode: 854 User: NT AUTHORITY\SYSTEM

StackTrace Information Details: at System.IO.Stream.CopyTo(Stream destination) at System.IO.Stream.CopyTo(Stream destination) at ECLItems.Templating.PublishingECLItems.Transform(Engine engine, Package package) at Tridion.ContentManager.Templating.Assembly.AssemblyMediator.Transform(Engine engine, Template template, Package package) at Tridion.ContentManager.Templating.Assembly.CSharpSourceCodeMediator.RunTemplate(Engine engine, Package package, String templateUri, String className) at Tridion.Templating.CSharpTemplate.CSharpSourceTemplate.Transform(Engine __engine, Package __package) at Tridion.ContentManager.Templating.Assembly.CSharpSourceCodeMediator.Transform(Engine engine, Template template, Package package) at Tridion.ContentManager.Templating.Engine.ExecuteTemplate(Template template, Package package) at Tridion.ContentManager.Templating.Engine.InvokeTemplate(Package package, TemplateInvocation templateInvocation, Template template)
at Tridion.ContentManager.Templating.Compound.CompoundTemplateMediator.Transform(Engine engine, Template templateToTransform, Package package) at Tridion.ContentManager.Templating.Engine.ExecuteTemplate(Template template, Package package) at Tridion.ContentManager.Templating.Engine.InvokeTemplate(Package package, TemplateInvocation templateInvocation, Template template)
at Tridion.ContentManager.Templating.Engine.TransformPackage(Template template, Package package) at Tridion.ContentManager.Templating.Engine.TransformItem(Template template, IdentifiableObject itemToRender) at Tridion.ContentManager.Templating.TemplatingRenderer.Render(ResolvedItem resolvedItem, PublishInstruction instruction, PublicationTarget target, RenderedItem renderedItem, RenderContext renderContext) at Tridion.ContentManager.Publishing.Rendering.RenderEngine.Render(ResolvedItem resolvedItem, PublishInstruction instruction, PublicationTarget target, RenderContext context) at Tridion.ContentManager.Publishing.Handling.DefaultPublishTransactionHandler.RenderAndPackage(ResolvedItem resolvedItem, PublishInstruction instruction, PublicationTarget target, List1 processedItems, PublishTransaction publishTransaction, TransportPackage transportPackage) at Tridion.ContentManager.Publishing.Handling.DefaultPublishTransactionHandler.RenderAndPackage(ResolvedItem resolvedItem, PublishInstruction instruction, PublicationTarget target, List1 processedItems, PublishTransaction publishTransaction, TransportPackage transportPackage) at Tridion.ContentManager.Publishing.Handling.DefaultPublishTransactionHandler.HandlePublishRequest(PublishTransaction publishTransaction) at Tridion.ContentManager.Publishing.Handling.DefaultPublishTransactionHandler.ProcessPublishTransaction(PublishTransaction publishTransaction) at Tridion.ContentManager.Publishing.Publisher.QueueMessageHandler.HandleMessage()

TBB Logic :

IContentResult contentResult = eclItem.GetContent(null);
if (contentResult != null)
 {
    using (Stream stream = new MemoryStream())
    {
         contentResult.Stream.CopyTo(stream);
         _engine.PublishingContext.RenderedItem.AddBinary(stream, fileName, "ECL_Default", component, contentType);
    }
  }

ECL Provider : GetContent logic

  public IContentResult GetContent(IList<ITemplateAttribute> attributes)
        {
            string JsessionId = string.Empty;
            if (this.Info.url == null) return null;

            string url = Image.GetPhotoUrl(this.Info.url, out JsessionId);
            using (WebClient webClient = new WebClient())
            {
                webClient.Headers.Add(HttpRequestHeader.Cookie, "JSESSIONID=" + JsessionId);
                using (Stream stream = new MemoryStream(webClient.DownloadData(url)))
                {
                    return Provider.HostServices.CreateContentResult(stream, stream.Length, this.Info.MimeType);
                }
            }
        }

Though GetContent method successfully return IcontentResult,but however we're Unable to add IcontentResult.Stream to AddBinary method.

Update

When we use IContentResult stream directly in AddBinary method,getting similar error Cannot access a closed Stream.

Component: Tridion.ContentManager.Publishing Errorcode: 854 User: NT AUTHORITY\SYSTEM

StackTrace Information Details: at

System.IO.__Error.StreamIsClosed() at

System.IO.MemoryStream.set_Position(Int64 value) at

System.IO.Stream.set_Position(Int64 value) at

Tridion.ContentManager.Publishing.Rendering.Binary..ctor(Stream content, String filename, IdentifiableObject location, String variantId, Component relatedComponent, String mimeType,RenderInstruction renderInstruction) at

Tridion.ContentManager.Publishing.Rendering.RenderedItem.AddBinary(Stream content, String filename, String variantId, Component relatedComponent, String mimeType)

4

The error you are getting is a .NET error in the CopyTo() method, that tries to copy a closed stream. I'm wondering if it wouldn't be easier to use the IContentResult stream object directly inside your AddBinary call.

_engine.PublishingContext.RenderedItem.AddBinary(contentResult.Stream, fileName, "ECL_Default", component, contentType);

UPDATE

As you get the same issue when using the stream directly, this is caused by your using statement here

 using (Stream stream = new MemoryStream(webClient.DownloadData(url)))
 {
       return Provider.HostServices.CreateContentResult(stream, stream.Length, this.Info.MimeType);
 }

the 'using' will dispose the stream when you return the content result, so the stream is no longer accessible.

I think you can safely change this to

Stream stream = new MemoryStream(webClient.DownloadData(url);
return Provider.HostServices.CreateContentResult(stream, stream.Length, this.Info.MimeType);
  • When we use directly in AddBinary , getting same error as System.IO.__Error.StreamIsClosed() at System.IO.MemoryStream.set_Position(Int64 value) at System.IO.Stream.set_Position(Int64 value) at Tridion.ContentManager.Publishing.Rendering.Binary..ctor(Stream content, String filename, IdentifiableObject location, String variantId, Component relatedComponent, String mimeType, RenderInstruction renderInstruction) at Tridion.ContentManager.Publishing.Rendering.RenderedItem.AddBinary(Stream content, String filename, String variantId, Component relatedComponent, String mimeType) – USER1287 Feb 15 '18 at 13:39
  • see my update in the answer – Harald Hoffelinck Feb 15 '18 at 14:39
  • 3
    +1 for not copying to memory stream. ECL will stream the data through from the external content system to the Tridion publishing engine without keeping large binaries fully in memory - so you can as well take advantage of that. Unless of course you have problems with your server being too fast and using too little memory. :) – Lars Møllebjerg Feb 16 '18 at 6:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.