January 2009 - Posts
In my last post, I showed how to turn on Amazon S3 support in Sitefinity. In this post, I will show how to create a simple video site using the video library support that is bundled with 3.6 release. It is often required that you want to add a streaming video content to your site, either it could be a product demonstration or a getting started tutorial. Using third party video provider is one way to get the job done but sometimes it requires a lot of manual work, thus headache for managing them as the library grows bigger. 3.6 release breaks you free from all these and provides an easy way for creating , uploading and managing video content.
Now, uploading video content and publishing them requires a few easy steps. You can either decide to store / stream it from your hosting server or from Amazon S3, typically which can be divided into following.
- Configure the data provider
- Create a video library
- Upload videos
- Create a page and add the video content control onto it.
- Publish it.
Sitefinity uses RadMediaPlayer (comes as part of Telerik Rad controls suit), a cool Silverlight media player made on top of the basic MediaPlayer with out of the box features that can get you on the groove right away. As I mentioned already, Sitefinity is a combination of content, modules and pages. Modules can have their own data providers, own handlers, whereas each page can control its content presentation by using the revolutionary control designer.
Coming back, to start creating our simple video site first we need to create a module (which is a video library). We can either choose to use the default data provider "Libraries" or we can define our own custom provider. To define one by ourselves we must ensure the following
- Create an entry under <cmsEngine> that looks like "<add name=Libraries..." or like the one described in Amazon S3 post.
- Add related meta fields under <metaFields> that are same as the default ones with only prefix = name, you have given to the data provider
<add key="Libraries.Description" valueType="ShortText" visible="True" searchable="True" sortable="True" defaultValue="" />
This converters to the following where name = "MyLib". Similar goes for the rest.
<add key="MyLib.Description" valueType="ShortText" visible="True" searchable="True" sortable="True" defaultValue="" />
- Map it with "Libraries" module under libraries.genericContentproviders
<libraries defaultGenericProvider="Libraries">
<genericContentProviders>
<add providerName="MyLib" publicationDateField="Publication_Date" />
.........
.........
- Under cmsEngine.providers.add (where name="MyLib/Libraries") there is a key called applicatinName, which is set to "/Libraries" but we can set it to "/MyOwnApplciation" to ensure that it does not mess data up with the default one.
For multiple data providers you will see a dropdown in the library create wizard, to upload under the specific one, we just need to select and start uploading.
So, once we have created a video library it will automatically take us to the upload view and once it is done, we can see the preview right away. Next, we just need to drag and drop the video control onto the page. To further customize it, we can play around with designer that is tied with it (click on the "edit" link) we can set things like the max width for the thumbnail or video player and tweak labels and meta datas as we go.
We have already seen how to set up multiple data providers and select specific libraries from designer. Moreover, we can set custom provider from advance mode of the content control. This applies to all Sitefinity content controls like Events, Blogs, etc that implements the same generic content base class.
Finally, if all are set, we will see a video page like the one shown just below. While we are uploading video, each will have a thumbnail generated from the video itself that will be shown in the list view. Each items in list view is tied with a detail view (similar to video sites), where you can play the video, leave comments and bookmark it in your favorite social networking site.
We have already seen in my previous post that we can set the urlRewriteFormat in the data provider declaration. For local libraries , when urlRewriteFormat="~/{LibraryName}/[Name].sflb.ashx" the video detail permalink will be http://<hostname>/<applicationPath>/<pagename>/MyLib/ButterFly.aspx, that means the video content control (detail view) will have the same mirror URL terminating with "*.aspx". So, if you change the URL format in library data provider it will reflect in the content control as well.
So far, that's all for the simple video site. Let us know, how you like to shape it for you and what features you really want to add in it. You can grab a free community edition and of course any feedback will really make us feel better.
Hope that helps
Here at Telerik, Sitefinity team is preparing for the 3.6 release next week. 3.6 comes with lot of core level enhancements and cool new features. Of which , I can't but mention one feature that will make most ISV vendors who want the power of CMS but want to let go their pain of managing large content. As, the title suggests its external storage support via Amazon S3. The data plan for hosting and transferring data to/from S3 server is pretty cheap these days in return to world class service with almost zero downtime that it offers which of course makes the most of your money. If you are not familiar with Sitefinity to add it is a product by Telerik that comes with full content management features along with blogs, news, events, list and few other pre-made modules with easy setup and management via unique control designer.
In this post, I will show how to turn on S3 support in Sitefinity 3.6 that comes out of the box.In Sitefinity, files are kept in Library. Every file which can be audio, video, document or anything else is stored as Library entries, which are consumed by modules for example images in blog post. These library entries are dependant on data providers which can be extended from internal to cloud. S3 support is just a plugin to that extensibility.
Now, to configure S3 support let's start with a simple example. I want to create a personal blog and I want all the images and attachments go to Amazon S3 server. To do so , we need to ensure the following
- Turn on the S3 data provider in web.config (that comes with the installation)
- Add your S3 API and secret key to the specific place holder.
- Create your blog module
- Drag and drop your module over a page.
- Publish it
- Use Admin or Live writer to do your post with Images and attachments.
Steps 3- 6 are pretty basic and are beyond the scope of this post. I will deeply encourage you to grab a community version from the project's download page(link provided at the end) and see the step by step documentation that comes right with it.
To start setting up, first we need to navigate to the cmsEngine node. If amazon block is there then un-comment it and remove the default "Libraries" data provider or less add the following data provider.
<add name="Libraries" urlRewriteFormat="~/{LibraryName}/[Name].s3lb"
thumbnailExtension=".tmb"
urlDateTimeFormat="yy-MM-dd" urlWhitespaceChar="_" visible="False"
defaultMetaField="Name" applicationName="/Libraries" allowVersioning="True"
allowLocalization="False"
localizationProviderName="" allowWorkflow="False"
securityProviderName="" versioningProviderName=""
connectionStringName="GenericContentConnection"
type="Telerik.Libraries.Data.AmazonProvider, Telerik.Libraries.Data"
tagEditorTemplate="~/Sitefinity/Admin/ControlTemplates/Libraries/BatchTagsEditor.ascx"/>
Now, inside the data provider you can do plenty of tweaks like, modify the URL format , turn on/off localization, have multiple providers of same type (with different name) and map it from admin, etc. The most important thing for libraries or any other module is the urlRewriteFormat. You can set up any format and the detail (permalink) url will generate accordingly. Here, [Name] = name of the file but you can change it to any meta fields that the module supports or add any constants you want.
The amazon data provider is different in two ways from local one
- It has different content extension(.s3lb).
- Separate data provider dedicated to communicate with S3. Default type = Telerik.Libraries.Data.DefaultProvider
As, we are pretty much done with the first step. Next, we have to put the right API and secret access key that we have purchased from Amazon. All the transfers will be made against the key associated to a user's account. Under the telerik node we have a section called storageSetting which looks like
<storageSetting defaultProvider="Amazon">
<providers>
<add name="Amazon"
type="Telerik.Libraries.AmazonStorage.AmazonStorageProvider, Telerik.Libraries"
downloadUrlPrefix="http://s3.amazonaws.com"
accessKey="YOUR ACCESS KEY"
secretAccessKey="YOUR SECRECT KEY"
bucketName="Sitefinity" />
</providers>
</storageSetting>
Just Fill in the gaps and you are through. In Sitefinity module is the heart of every content and a page can contain 1..N modules but each module can have its own specific settings like data provider, URL format, etc. As we have finished setting up the data provider and associated configuration to talk with S3 server. we can now play the way we like. We can create gallery with image library or setup a download list for providing documents and pdfs. Even we can setup a video site(which I will cover in later post) easily. But for now , let's create a blog, write a post, add some images and text and publish it.
The above is the snap of edit mode of the blog page along with the post that I have done using Live Writer. Now, to be more sure (we haven't done any wrong) if you monitor using firebug Net tab your list will look like the pasted
Down in the bottom there are two request for images posted by Live Writer which are directly forwarded to S3 server (302->200). Thus, the whole load goes to Amazon and gives you peaceful night sleep.
This is basically shortly all for now, I will cover more things from Sitefinity like creating video site , working with Sitefinity designers to configure your site without touching any of the html code and more that is interesting in my future posts.
Till then, you can get a free copy from http://www.sitefinity.com/product/community-edition.aspx (you need to create an account if you haven't. You can use it for other Telerik products and to log any issues as well.
Hope that helps
In this post, I will show how to cook an LINQToTwitter library with LinqExtender. My target is to create it easily and over existing twitter API. I used Yedda Twitter library. Yedda library basically returns response in XML/JSON/RSS/ATOM format depending on the option provided. I used XML format and serialized it to objects.
Now, with our LINQToTwitter we will be able to get public/user/friend's timeline, sort them via date, screen name. Finally, we will be able to update our status. Twitter response format for status looks like
<statuses>
<status>
....
....
<user>
....
....
</user>
</status>
</statuses>
For this, I have created a class named Twit that maps to the status and a class name User that is used as an auto property in Twit. These two classes contain some Xml Serialization attributes by which response is serialized to respective properties.
We have our Twitter API in place, the next step is to make them LINQ-able. Prior to the latest release to make an object queryable, it is required to inherit from QueryObjectBase. Using this approach the feed back I got from users that they need to try LINQ in their existing data objects, which is already inherited from a base class and they need to change a lot for using the abstract approach. The new release just solves that with a blank IQueryObject interface, which makes it more easier to port LINQ into existing data object in no time.
Building LINQ providers with LinqExtender requires few easy steps. First, Create or convert an object to be queryable by implementing IQueryObject interface. With our Twit object it looks like
Here, note that I added UniqueIdentifier attribute on top of Id property that makes the object trackable during add, update or delete. Every object should have property that distinguishes entities from each other and should be marked Unique. There is another attribute called Ignore. If we want properties not to be processed by the toolkit we can just put the attribute on top. Once, it is done next we have to create query provider that will be used for making LINQ queries. Let's name it TwitterContext and it needs to inherit Query<Twit> and override few methods depending on support that the library is going to provide.
Now, as I said earlier that we will be doing some queries by timeline and update our status. While adding new items we need to override Query<Twit>.AddItem where we will add object to repository and update any property that we need to get and finally return true/ false depending on the execution status.
Inside Query<Twit>.AddItem it looks like (Partially).
string username = (string)Bucket.Instance.For.Item(QueryItems.USERNAME).Value;
string password = (string)Bucket.Instance.For.Item(QueryItems.PASSWORD).Value;
Validate(username, password);
string statusText = (string)Bucket.Instance.For.Item("Text").Value;
string source = (string)Bucket.Instance.For.Item("Source").Value;
Twitter twitter = new Twitter();
if (string.IsNullOrEmpty(source))
{
twitter.Source = source;
}
string response = twitter.Update(username, password, statusText, Twitter.OutputFormatType.XML);
Twit twit = XmlToObject<Twit>.Deserialize(response);
Type twitType = twit.GetType();
Bucket.Instance.For.EachItem
.Process(delegate(BucketItem item)
{
item.Value = twitType.GetProperty(item.Name).GetValue(twit, null);
});
The code is pretty simple as we can see that we are getting the required values from bucket object , setting them into Twitter API, updating the result object (Twit) and finally returning TRUE that will tell LinqExtender to update it's collection. For any FALSE or exception toolkit will remove the partial object. There are other methods that we can override like UpdateItem, RemoveItem, GetItem. Due to the API constraint we will skip them now. But you can check them out at the project documentation or in the provided OpenLinqToSql ORM.
Next, we need to override the Query<Twit>.Process which will be handling the LINQ queries we make.
protected override void Process(LinqExtender.Interface.IModify<Twit> items)
{
string response = string.Empty;
Twitter twitter = new Twitter();
/// general select statement with no where clause.
if (!Bucket.Instance.IsDirty)
{
response = twitter.GetPublicTimeline(Twitter.OutputFormatType.XML);
}
else
{
string username = (string)Bucket.Instance.For.Item(QueryItems.USERNAME).Value;
string password = (string)Bucket.Instance.For.Item(QueryItems.PASSWORD).Value;
object obj = (Timeline)Bucket.Instance.For.Item(QueryItems.TIMELINE).Value;
if (obj == null)
{
throw new Exception("Must provide a valid timeline");
}
Timeline timeline = (Timeline) obj;
if (timeline == Timeline.Friends)
{
Validate(username, password);
response = twitter.GetFriendsTimeline(username, password, Twitter.OutputFormatType.XML);
}
else if (timeline == Timeline.User)
{
response = twitter.GetUserTimeline(username, password, Twitter.OutputFormatType.XML);
}
}
Twits twits = XmlToObject<Twits>.Deserialize(response);
/// do some extra in-memory stuff which are not supported by API
IList<Twit> list = GetList(twits);
items.AddRange(list, true);
}
Here, we can see that Bucket.Instance.IsDirty is used for public timelines. When Bucket.Instance.IsDirty = false, we can be sure that no where clause is used and as such we can decide to handle the way we want. IModify<T>.AddRange with true tells the toolkit to do in-memory sort when orderby is used. There is another way to do sort (natural sort) by which we can pass in the sort data to source (if supported) and in that case we can either pass false or use the other overload of AddRange or even add items one by one.
This is our simple LINQToTwitter library so far. To start let's do some queries. First, I want to get my friend's timeline sorted by last updated date.
TwitterContext context = new TwitterConext();
var query = from twit in context
where twit.Username == "myuser"
&& twit.Password == "mypass"
&& twit.Timeline == Timeline.Friends
orderby twit.LastUpdated descending
select twit;
foreach (var t in query)
{
/// do something useful.
}
I also want to update my status. To do so, the following needs to be done.
Twit twitObject = new Twit()
{
Username = USERNAME,
Password = PASSWORD,
Text = "Happy new year to all"
};
context.Add(twitObject);
context.SubmitChanges();
if (!string.IsNullOrEmpty(twitObject.Id))
{
/// do something
}
There are few other queries that can be made. You can download the source here. I have shown here very few of the options in LinqExtender, to know more check out the word document at project's release page. Also, check the OpenLinqToSql ORM that is made on it and comes out of the box.
Enjoy!!
Updated on Feb 24th 2009 with LinqExtender 2.0

More Posts