Try Now
More in this section
Blogs RSS feed

Sitefinity Streaming API: Common tasks

by Dilyan Rusev
This is a part of the blog post series that explain the new streaming API for Sitefinity 3.7 SP3. You can view the TOC in the first blog post.

I described why Streaming API was needed in Sitefinity, and then I covered on the new API and the changes that were necessary to support it. Now, I am going to show you how to use it.

 Creating a content with data available for streaming

Creating the item (IContent) is done via the manager. However, we don't set the IContent.Content property manually. We, instead, use the Sreaming API to retrieve an upload stream (overriding any previous content that was there) and "upload" our content. Here is a short example:

// let us say we want to upload a file from App_Data
var data = File.OpenRead(HttpContext.Current.Server.MapPath("~/App_Data/someFile.bin"));
// retrieve the default provider
ContentManager manager = new ContentManager();
// craete an IContent as you would normally do
var content = (IStreamableContent)manager.CreateContent("text/html");
// the content must be retrievable by ID for streaming to work
// so we save it first and then get it back into transaction
content = (IStreamableContent)manager.GetContent(content.ID);
// retrieve an upload stream. Be sure to check if the streaming provider is null.       
if (manager.StreamingProvider != null && content != null)
    // don't forget to call dispose, as otherwize the data may be corrupted
    // to be save, wrap in using statement
    using (var contentStream = manager.StreamingProvider.GetUploadStream(content))
        // optimize chunk size by passing the active provider as last argument
        StreamHelper.CopyStream(data, contentStream, false, manager.Provider);
        // we could manually set the the chunk size, of course
        // StreamHelper.CopyStream(data, contentStream, false, 1024L);
// finally, we save. Note, that, the binary content is already saved to database
// this call should not be necessary

For the example to work, it is assumed that you have reference to Telerik.Cms.Engine.dll and you have at least System, System.IO, Telerik.Cms.Engine and Telerik.Cms.Engine.Streaming namespaces included with the using statement.

Getting the binary content of an uploaded content

This will work only if the content has been uploaded with an UploadStream

// for this example, we will assume that
// content is IStreamableContent and manager is ContentManager
// here is another way to retrieve the streaming provider
// this will be the streaming provider used initially to upload the content
if (content.StreamingProvider != null)
    // assuming we want to save the data to a file
    using (var fileStream = File.OpenWrite(@"C:\somefile.dat"))
    using (var contentStream = content.StreamingProvider.GetDownloadStream(content))
        // we will use the default buffer (chunk) size, which is 1MB
        StreamHelper.CopyStream(contentStream, fileStream, false);

Deleting the binary data for an uploaded IContent

// for this example, we will assume that
// content is IStreamableContent and manager is ContentManager
// and yet another way to retrieve the streaming provider
ContentProviderBase provider;
if (ContentManager.Providers.TryGetValue(content.ProviderName, out provider))
    IStreamingContentProvider streamingProvider;
    if (!string.IsNullOrEmpty(content.StreamingProviderName) &&
        .TryGetValue(content.StreamingProviderName, out streamingProvider))
        // do the actual deletion
        // this will delete the binary content only and not the IContent itself.
        // deleting the IContent will delete its binary data as well, by calling
        // this same method. Since it is virtual, this is the place you will want to
        // do your deletion logic if you do your custom streaming provider

Updating the binary content with streaming

There is no update in the strict sense of the word. You would exactly the same thing as with creating - retrieve an upload stream and write your binary data. The upload stream doesn't support seeking, so you won't be able to set the Position either. You can't have an upload and download stream at the same time, as well, since data is flushed once a chunk/buffer is discarded. This is made so because the goal of streaming is to keep as little of the actual data in memory as possible.

Put in an example, here is what you would to to "update" via streaming:

// content is assumed to be IStreamableContent and manager is assumed to be ContentManager
if (manager.StreamingProvider != null)
    // Getting the upload stream itself will delete the existing content,
    // even if you don't write anything
    using (var data = File.OpenRead(@"C:\example.file"))
    using (var uploadStream = manager.StreamingProvider.GetUploadStream(content))
        StreamHelper.CopyStream(data, uploadStream, false);

Loading the whole binary data in memory

Although this defeats the idea of streaming, you can do this if you know beforehand that the binary data is small.

// for this example, we will assume that
// content is IContent and manager is ContentManager
// this is another way to do streaming
IStreamingContentProvider streamingProvider;
if (StreamHelper.IsStreamingCapable(content, true, out streamingProvider))
    using (var source = streamingProvider.GetDownloadStream((IStreamableContent)content))
        // don't load in memory unless you have a good reason to do so
        // ReadToEnd will read any Stream in memory
        byte[] binaryDataInMemory = StreamHelper.ReadToEnd(source, false);
        // do something with the binary Data               

Upload via streaming in Images & Documents

// for this example, you will need a reference to Telerik.Libraries.dll. It is assumed you have
// using for Telerik.Libraries. libManager is an instance of LibraryManager and ILibrary is an
// instance of the library you want to upload to
// retrieve a source stream to upload
using (var source = File.OpenRead(@"C:\example.file"))
    // use the familiar UploadFile in LibraryManager
    var uploadedContent =  // it will return an instance of the created IContent item
        // first argument is the source stream. It should support setting the Position property.
        // file name
        // file extension
        // mime type
        // library to upload the file to


Even though I use StreamHelper to copy and read streams, it is not necessary. You can read/write to streams manually if you want to, but I do not recommend it. For one, it will save you time, and it is optimized.

 In my next blog post, I will explain the corner cases in which the binary data is loaded in memory even when streaming is used.

Leave a comment