The boom in social networking era contributed towards very high volume of data that’s constantly changing and moving. Processing such huge data in real time was a big challenge and LinkedIn engineers thus started a pet project to meet the requirements of high volume distributed messaging system that can process trillions of data over several clusters. This is how Kafka was born.

Kafka was built with speed and scalability in mind. It mainly resolves issues with streaming and queueing of high volume data. The key design principle behind Kafka is that it should have simple messaging API for the pub-sub (publisher-subscriber) of the data, with high throughput. Further, it is at present the most durable, low latency and secured messaging system around.

I was looking forward to use it in one of my projects that was built using .Net. Though I could have used Java as a platform too, but I came across confluent Kafka client that made me change my mind. While trying to implement I found some articles outdated and obsolete. I figured out finally the steps after some struggle. This is why I decided to blog in this article on how to setup your environment in windows operating system. For the sake of this article to be less confusing, I would assume that the root of all installation is under C:\Apache. In my case the drive is different.

Kickstart Kafka in 7 steps

Step 1:
Download JSDK and install using default options. I installed it such that my JRE folder is C:\Program Files\Java\jre1.8.0_121.

Step 2: Download and Install Zookeeper
Download latest stable release of Zookeeper. You need to download the compressed file and extract using WinRAR or any other tool you prefer at C:\Apache. After extraction you should see C:\Apache\zookeeper-3.4.10 if you downloaded 3.4.10.

Step 3: Download and Install Kafka
Download latest stable release of Kafka. Extract the compressed files at C:\Apache, such that the Kafka folder is like C:\Apache\kafka_2.12-0.10.2.0

Step 4: Configuring environment

  • Create following environment variables with given values
  • JAVA_HOME = C:\Program Files\Java\jre1.8.0_121
  • _JAVA_OPTIONS = -Xmx512M -Xms512M
  • ZOOKEEPER_HOME = D:\Apache\zookeeper-3.4.10
  • Find and edit environment variable “Path” and add the following locations separated by semi-colon.
  • %JAVA_HOME%\bin; %ZOOKEEPER_HOME%\bin

Create a sub-folder "Logs" under "C:\Apache" folder, which will be used by Kafka and Zookeeper to maintain its logs and indexes. Within "Logs" sub-folder create two empty folders "kafka" and "zookeeper". We will use these folders in the next step to configure Kafka and Zookeeper configuration.

Step 5: Configuring Kafka Properties

  • Server.properties
        log.dirs = C:/Apache/Logs/kafka
  • zookeeper.properties
        dataDir = C:/Apache/Logs/zookeeper

Step 6: Running Kafka Server
In this section all the commands shown below assumes that your current directory in command window is C:\Apache\kafka_2.12-0.10.2.0\ prior to executing any command. You can use Shift+Right-Click within C:\Apache\kafka_2.12-0.10.2.0\ folder in windows explorer and select “Open command window here” to open command window with selected path or use cd command after opening the command prompt window to set your current folder.

Open a command window and execute the following command line
.\bin\windows\zkserver .\config\server.properties

Since Kafka uses Zookeeper, it should be stated before Kafka. If all went fine, you should see the following window with Zookeeper listening at port 2181.

Now start Kafka by opening another command window with same current directory and executing the command ".\bin\windows\kafka-server-start.bat .\config\server.properties". If successful, Kafka would start and bind at port 9092.

Create Topic: Open another command window and change directory to bin\windows sub folder. Execute the following command to create a topic for Kafka.
kafka-topics.bat --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test

You can list the topics created by issuing the command - kafka-topics.bat --list --zookeeper localhost:2181

Test Producer: In a new command window, execute the following command kafka-console-producer.bat --broker-list localhost:9092 --topic test

Test Consumer: Open another command window and change directory to the bin\windows sub folder. Execute the following command to create a topic for Kafka.
kafka-console-consumer.bat --bootstrap-server localhost:9092 --topic test --from-beginning

Step 7: Using Confluent Kafka .NET Open Visual Studio and create a new console App Projects with name SimpleProducer and SimpleConsumer. Then select “Manage NuGet Packages for Solution…” from tools/NuGet Package Manager menu. Install Confluent.Kafka for your solution for both the projects.

Now add the following code and references to Producer and Consumer applications respectively.

Producer Code:

Consumer Code:

Test your console EXE’s: Rebuild and run the Producer and Consumer EXE’s from their respective bin/debug folders. If everything has gone fine, you can play with producer and consumer by typing any text in producer and see it appear in the consumer.

For further reference and learning about Kafka use following links

Enjoy!!

 
  Posted in:  .Net Big-Data



WCF Kick Start

In this article I would be describing the simplest form of WCF (Windows Communication Foundation) project which would get you started with the WCF concepts and best practices. The purpose is to minimise the confusion from code and configuration and explain the idea along with the best practice. I would also provide description and links to help you move to a more advanced WCF topics as and when required.

For the sake of kick start I would be using basicHttpBinding for the service and consumer, which does not require any kind of authentication when accessing the service. It is kind of open to all.

Below is an overall image of the solution, projects and project files that I have used to demonstrate the simplest form of WCF implementation.

solution

The solution contains a project WcfServiceOne which defines types for contracts exposed by the service. The person class is the data contract, MyService is the service and IMyService is an interface acting as a service contract. This project acts as an API for the services.

The ServiceOneHost is the service exposed to the client. It references the project WcfServiceOne which the actual implementation of the Service as an API. Though, I could have had the service implementation written in the same project, I preferred following the best practices, by implementing the Service and Service API (contracts and its implementation) in a separate project. One advantage of doing this is that, you have decoupled service and Service API, which simplifies using the API in a non-WCF environment by directly referencing it. The web.config file in this project contains the binding information for the service which I will be explaining later in this article.

The ServiceOneConsumer is a simple ASP.Net web application consuming the service exposed by ServiceOneHost. The web.config in this web application contains the binding information defined by the host.

WcfServiceOne

WcfServiceOne project contains:

  • Data Contract - Person.cs
  • Service Contract - IMyService.cs
  • Service Implementation - IMyService.cs
Also notice that the project references System.ServiceModel and System.Runtime.Serialization which are required to assign attributes like ServiceContract, OperationContract, DataContract and DataMember.

Person.cs

using System.Runtime.Serialization;

 

namespace WcfServiceOne

{

    [DataContract]

    publicclassPerson

    {

        [DataMember]

        publicstring FullName { get; set; }

 

        [DataMember]

        publicstring Gender { get; set; }

    }

}

IMyService.cs

using System.ServiceModel;

 

namespace WcfServiceOne

{

    [ServiceContract]

    publicinterfaceIMyService

    {

        [OperationContract]

        string Callme(Person p);

    }

}

MyService

namespace WcfServiceOne

{

    publicclassMyService : IMyService

    {

        publicstring Callme(Person p)

        {

            return"Hello " + p.FullName + "  " + " you are a " + p.Gender;

        }

    }

}

ServiceOneHost

Add a reference to WcfServiceOne and then right click on the project. Select "Add New Item" from the context menu and select "WCF Service" templates. Name the new file ServiceOneHost.svc. The template would also create the code files for you in the App_Code folder. You can delete it, the code file is not required. Open the ServiceOneHost.svc and change the line to:

<% @ ServiceHost Language ="C#" Debug ="true" Service ="WcfServiceOne.MyService" %>

 

Now open the web.config file in this project and add the following block at the last within the closing of configuration tag.

  < system.serviceModel >

    < behaviors >

      < serviceBehaviors >

        < behavior name ="ServiceOneHostBehavior">

          < serviceMetadata httpGetEnabled ="true"/>

          < serviceDebug includeExceptionDetailInFaults ="false"/>

        </ behavior >

      </ serviceBehaviors >

    </ behaviors >

    < services >

      < service behaviorConfiguration ="ServiceOneHostBehavior"name="WcfServiceOne.MyService">

        < endpoint address =""binding="basicHttpBinding"contract="WcfServiceOne.IMyService">

          < identity >

            < dns value ="localhost"/>

          </ identity >

        </ endpoint >

        < endpoint address ="mex"binding="mexHttpBinding"contract="IMetadataExchange"/>

      </ service >

    </ services >

  </ system.serviceModel >

system.servicemodeltag defines how the consumer is going to connect to the service exposed here. When you add a "WCF service" to the project using template, it responds with adding the above system.servicemodel in the web.config, except the following two lines.

      < service behaviorConfiguration ="ServiceOneHostBehavior"name="WcfServiceOne.MyService">

        < endpoint address =""binding="basicHttpBinding"contract="WcfServiceOne.IMyService">

Change the name, contract and binding information as shown above. The wsHttpBinding is used to provide more secured communication using certificate. Visit The pattern and practices for WCF security at Codeplex for further guidance on how to implement wsHttpBinding using certificates.

ServiceOneConsumer

Before you proceed with consumer, you need to generate a proxy for the service and define how it connects, in the web.config file. To generate the proxy and the configuration block we would use svcutil. Open the Visual studio command prompt from Visual Studio Tools and use the following command to generate the proxy and configuration.

svcutil http://localhost/ServiceOneHost/ServiceOneHost.svc /Language:C# /out:ServiceHostProxy.cs /config:ServiceHost.config

This will create a ServiceHostProxy.cs and ServiceHost.config. Open the ServiceHost.config and copy the block. Now open the web.config file and paste the block at the end before the closing tag of configuration. The endpoint address might differ depending your host and consumer address URL.

    < system.serviceModel >

        < bindings >

            < basicHttpBinding >

                < binding name ="BasicHttpBinding_IMyService"closeTimeout="00:01:00"

                        openTimeout ="00:01:00"receiveTimeout="00:10:00"

                        sendTimeout ="00:01:00"allowCookies="false"

                        bypassProxyOnLocal ="false"

                        hostNameComparisonMode ="StrongWildcard"

                        maxBufferSize ="65536"maxBufferPoolSize="524288"

                        maxReceivedMessageSize ="65536"

                        messageEncoding ="Text"textEncoding="utf-8"

                        transferMode ="Buffered"

                        useDefaultWebProxy ="true">

                    < readerQuotas maxDepth ="32"maxStringContentLength="8192"

                                 maxArrayLength ="16384"

                                 maxBytesPerRead ="4096"

                                 maxNameTableCharCount ="16384"/>

                    < security mode ="None">

                        < transport clientCredentialType ="None"proxyCredentialType="None"

                           realm =""/>

                        < message clientCredentialType ="UserName"algorithmSuite="Default"/>

                    </ security >

                </ binding >

            </ basicHttpBinding >

        </ bindings >

        < client >

            < endpoint address ="http://localhost/ServiceOneHost/ServiceOneHost.svc"

               binding ="basicHttpBinding"bindingConfiguration="BasicHttpBinding_IMyService"

               contract ="IMyService"name="BasicHttpBinding_IMyService"/>

        </ client >

    </ system.serviceModel >

Default.aspx

Now add the following UI in the home page of your consumer site. In this case it is Default.aspx.

< table style =" width: 400px;"cellspacing="0"cellpadding="0">

    <tr>

        <tdstyle="width:100px; vertical-align:top; text-align:left;">

            Your Name

        </td>

        <tdstyle="width:10px; vertical-align:top; text-align:left;">

            :

        </td>

        <tdstyle="width:290px; vertical-align:top; text-align:left;">

            <asp:TextBoxID="txtName"runat="server"Width="200"></asp:TextBox>

        </td>

    </tr>

    <tr>

        <tdstyle="vertical-align:top; text-align:left;">

            Gender

        </td>

        <tdstyle="vertical-align:top; text-align:left;">

            :

        </td>

        <tdstyle="vertical-align:top; text-align:left;">

            <asp:DropDownListID="ddlGender"runat="server">

                <asp:ListItemSelected="True"Text="Male"Value="male"/>

                <asp:ListItemText="Female"Value="female"/>

            </asp:DropDownList>

            <asp:ButtonID="btnSubmit"runat="server"Text="Submit"

                onclick="btnSubmit_Click"/>

        </td>

    </tr>

    <tr>

        <tdcolspan="3">

            <br/>

            <asp:LabelID="lblResult"runat="server"Text=""Font-Bold="true"
                    Font-Size="Large"></asp:Label>

        </td>

    </tr>

</ table >

Default.aspx.cs - Code Behind

using System;

using WcfServiceOne;

 

public partial class _Default : System.Web.UI.Page

{

    protectedvoid Page_Load(object sender, EventArgs e)

    {

        txtName.Text = "Manish Kumar Singh";

    }

    protectedvoid btnSubmit_Click(object sender, EventArgs e)

    {

        var p = newPerson {FullName = txtName.Text, Gender = ddlGender.SelectedValue};

 

        var proxy = newMyServiceClient();

        lblResult.Text = proxy.Callme(p);

    }

}

That's it. Now run the consumer site and give it a try.

Enjoy!
Manish


 
  Posted in:  .Net



In this section I would like to demonstrate how to compile a .NET code on the fly. The code has been written in C#. It contains a class "InlineParser" which does the main job. It mainly, defines the class, does in-memory compilation and exposes a method for the execution of an inner method defined in the class. It also supports a choice of language whether C# or VB.NET for compilation.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.CSharp; using Microsoft.VisualBasic; using System.CodeDom.Compiler; using System.Reflection; using System.Xml.Linq; namespace com.eforceglobal.crux.bre { internal class InlineParser { string expression = string.Empty; string functionArguments = string.Empty; string language = "CSharp"; XDocument paramList = null; object objBase = null; public InlineParser(string expr, string functionArgs, XDocument parameters, string lang) { expression = expr; functionArguments = functionArgs; paramList = parameters; language = lang; } public bool init() { if (language.ToLower().Equals("csharp")) return InitCSharp(); else return InitVB(); } internal bool InitCSharp() { // Compile the expression in a class on the fly CSharpCodeProvider cp = new CSharpCodeProvider( new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } }); //ICodeCompiler ic = cp.CreateCompiler(); CompilerParameters cparam = new CompilerParameters(); cparam.GenerateInMemory = true; cparam.GenerateExecutable = false; // Reference Assembly cparam.ReferencedAssemblies.Add("system.dll"); cparam.ReferencedAssemblies.Add("mscorlib.dll"); cparam.ReferencedAssemblies.Add("System.Core.dll"); cparam.ReferencedAssemblies.Add("System.Xml.dll"); cparam.ReferencedAssemblies.Add("System.Xml.Linq.dll"); // Write your code StringBuilder sb = new StringBuilder(); sb.Append("using System;\n"); sb.Append("using System.Collections;\n"); sb.Append("using System.Collections.Generic;\n"); sb.Append("using System.Text;\n"); sb.Append("using System.Text.RegularExpressions;\n"); sb.Append("using System.Reflection;\n"); sb.Append("using System.Linq;\n"); sb.Append("using System.Xml.Linq;\n"); sb.Append("namespace com.eforceglobal.crux.bre {\n"); sb.Append("public class EvalClass {\n"); sb.Append("public EvalClass(){}\n"); sb.Append("public object Evaluate(\n"); sb.Append(functionArguments).Append(" ) {\n"); sb.Append(expression).Append("\n"); sb.Append("}\n}\n}"); string code = sb.ToString(); CompilerResults cres = cp.CompileAssemblyFromSource(cparam, code); // Compilation Unsuccessfull StringBuilder errors = new StringBuilder(); foreach (CompilerError cerr in cres.Errors) errors.Append(cerr.ErrorText); if (cres.Errors.Count > 0) throw new Exception(errors.ToString()); // Compilation Successfull if (cres.Errors.Count == 0 && cres.CompiledAssembly != null) { Type ClsObj = cres.CompiledAssembly.GetType("com.eforceglobal.crux.bre.EvalClass"); try { if (ClsObj != null) { objBase = Activator.CreateInstance(ClsObj); } } catch (Exception ex) { throw; } return true; } else return false; } internal bool InitVB() { // Compile the expression in a class on the fly VBCodeProvider vb = new VBCodeProvider( new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } }); //ICodeCompiler ic = cp.CreateCompiler(); CompilerParameters cparam = new CompilerParameters(); cparam.GenerateInMemory = true; cparam.GenerateExecutable = false; // Reference Assembly cparam.ReferencedAssemblies.Add("system.dll"); cparam.ReferencedAssemblies.Add("mscorlib.dll"); cparam.ReferencedAssemblies.Add("System.Core.dll"); cparam.ReferencedAssemblies.Add("System.Xml.dll"); cparam.ReferencedAssemblies.Add("System.Xml.Linq.dll"); // Write your code StringBuilder sb = new StringBuilder(); sb.Append("Imports System\n"); sb.Append("Imports System.Collections\n"); sb.Append("Imports System.Collections.Generic\n"); sb.Append("Imports System.Text\n"); sb.Append("Imports System.Text.RegularExpressions\n"); sb.Append("Imports System.Reflection\n"); sb.Append("Imports System.Linq\n"); sb.Append("Imports System.Xml.Linq\n"); sb.Append("Namespace com.eforceglobal.crux.bre \n"); sb.Append("Public Class EvalClass \n"); sb.Append("Public Function Evaluate ( "); sb.Append(functionArguments).Append(" ) As Object\n"); sb.Append(expression).Append("\n"); sb.Append("End Function\n"); sb.Append("End Class\n"); sb.Append("End Namespace"); string code = sb.ToString(); CompilerResults cres = vb.CompileAssemblyFromSource(cparam, code); // Compilation Unsuccessfull StringBuilder errors = new StringBuilder(); foreach (CompilerError cerr in cres.Errors) errors.Append(cerr.ErrorText); if (cres.Errors.Count > 0) throw new Exception(errors.ToString()); // Compilation Successfull if (cres.Errors.Count == 0 && cres.CompiledAssembly != null) { Type ClsObj = cres.CompiledAssembly.GetType("com.eforceglobal.crux.bre.EvalClass"); try { if (ClsObj != null) { objBase = Activator.CreateInstance(ClsObj); } } catch (Exception ex) { throw; } return true; } else return false; } public string Evaluate() { string result = string.Empty; Type type = objBase.GetType(); MethodInfo mInfo = type.GetMethod("Evaluate"); if (mInfo != null) { ParameterInfo[] pInfo = mInfo.GetParameters(); object[] arguments = null; if (pInfo != null) arguments = new object[pInfo.Length]; if (pInfo != null) { foreach (ParameterInfo p in pInfo) if (paramList.Element("arguments").Elements(p.Name) != null) { arguments[p.Position] = (paramList.Element("arguments") .Elements(p.Name).Single().Value); } if (pInfo.Length != arguments.Length) throw new ArgumentException("Insufficient parameters."); } result = mInfo.Invoke(objBase, arguments).ToString(); } return result; } } }
Notice that the class name of the class to be compiled is "EvalClass" and the inner method of the class is "Evaluate". Calling the "Evaluate()" method requires you to execute the following lines of code.
var parser = new InlineParser(subExpression, funcArgs, Arguments.Document, lang); parser.init(); retString = parser.Evaluate();
Enjoy!!
Manish

 
  Posted in:  .Net



Introduction

Microsoft Surface Touch TableI was hearing about Microsoft Surface far last few months, but did not get much information. Recently, I saw a post "PDC 2008" by Robert Levy and Brad Carpenter having a video session demonstrating the capabilities of Microsoft Session. The demonstrate the unique attributes of Microsoft Surface computing, with a dive into vision-based object recognition and core controls like ScatterView, and how the Surface SDK aligns with the multi-touch developer roadmap for Windows 7 and WPF. The software giant has built a new touch screen computer — a coffee table that will change the world. Forget the keyboard and mouse, the next generation of computer interfaces will be NUI (Natural User Interface) which uses natural motions, hand gesture and real world physical objects. The surface is capable of object recognition, object/finger orientation recognition and tracking, and is multi-touch and is multi-user. Users can interact with the machine by touching or dragging their fingertips and objects such as paintbrushes across the screen, or by placing and moving placed objects. This paradigm of interaction with computers is known as a natural user interface (NUI). Surface has been optimized to respond to 52 touches at a time.

Microsoft Surface applications can be written in Windows Presentation Foundation (WPF) and .Net language like C# or VB.Net. It is nicely integrated with Visual Studio 2008 following the same pattern of programming paradigms the .Net developers are used to. However it has custom WPF controls to allow programming for the unique interface of Surface. Developers already proficient in WPF can utilize the SDK to write Surface apps.

Object RecognitionMulti User Application

Microsoft Surface SDK 1.0

Right now, Microsoft Surface SDK is not available for public. It has been distributed only to some of the Microsoft partners. I am eagerly waiting to get my hands on the SDK once it is launched. Since, I have already worked with SilverLight and WPF, I think, it would be quite easy to pick Microsoft Surface. This is true for every developer worked on WPF and used XAML. However, there is a small catch ... Working for surface would require more creativity and unlearning the GUI which we are used to. The new interface requires us to think about the UI from entirely a new perspective ... a 360 degree multi-touch perspective.

I am sure the developers deep in love with .NET programming and having high respect for Microsoft Technologies, would be very excited after seeing the video session of PDC 2008. The features demonstrated, and the ease of programming together with seamless process of learning would make you sit up staright on your seat, open Google to find out whether you can get hold of Microsoft Surface SDK. Hmm! As you might be thinking after watching the video, whether you need the touch screen device which costs $10K-15K, to practice Microsoft Surface? The answer is No! Microsoft has a simulator for Surface which would allow you to deploy and play around with your surface code. Unfortunately, that too is not available to public right now. So you might have to wait a little more, until of course you are working for the company included in the Microsoft's Partner list, currently allowed to download and use Microsoft Surface SDK and Simulator.

It Is Not Just Another Glorified And Hyped Touch Screen Computer

Many had a wrong impression about Microsoft Surface thinking it to be another glorified and hyped touch screen computer. The touch screen computers enable users to do away with keyboard and mouse. They can navigate the menu by touching various options to reach a logical end of viewing data or printing. And there ends the comparison. Microsoft Surface device also known as Microsoft Tabletop can do many more things, which you might think are not possible!

The three main components that differentiates it from a regular Touch-Screen device, Direct interaction, Multi-Touch Contact and Object Recognition.

 Object Recognition
  • Multi-touch contact: User need not use only one finger to manage digital data. If user dips five fingers in five different colors in the on screen paint palette and draws five lines with five fingers, you get five lines with five colors . . .
  • Direct interaction: Facility to manage digital information with hand gestures and touch instead on mouse and keyboard.
  • Object Recognition: This technology allows non-digital objects to be used as input devices. This means that the input source does not necessarily have to be digital in form.

This Is The Future

Companies are putting in millions of dollar in research for NUI. There is a nice video "TED: Sixth Sense" from Pattie Maes' lab at MIT, spearheaded by Pranav Mistry. It's a wearable device with a projector that paves the way for profound interaction with our environment. It demonstrates a device which responds to natural gestures of hand which is read by a camera. The UI is developed and projected using a small projector fitted in the same device. If you guys have seen movies like "Minority Report", see these technologies nearing to the imaginations.

The NUI immensely increases interaction with digital contents in a more simplified manner. One does not need to practice with mouse. It won't be a single user interface anymore. Two users can open two different menus at the same time .... (Right now your application would open one menu at a time). A 360 degree interaction, with each person using the same application independently. Surely, we need to think and see the UI very differently now and you are bound only by your imaginations.

So friend's start unlearning the GUI you are accustomed to, and buckle your seat belts for the next gen -- NUI.

Manish


 
  Posted in:  .Net Thoughts



Introduction

Rich media advertisement is a buzz word today. Organizations are spending a huge amount to move out from a traditional banner advertisement approach, booklets and television to a more effective tactics where they can reach out to a wider mass through internet. Rich media advertisement forms a basis of wider coverage at less cost together with a wonderful user experience.

Macromedia Flash, already provides a state-of-art solution for it. However, it is mostly tied to its proprietary engine for shock wave and interaction. Flash are further, required to be embedded as a compiled unit. Besides all, it requires you to learn Flash an extra skill.

Something I like about silverlight is that it supports XAML based platform with language support for programming. EXtensible Application Markup Language (XAML) which is pronounced as Zamel, is used to define your canvas and storyboard, which are easy to manipulate at runtime using languages like C# or VB.Net. These are further deployed as a compressed unit rather than a compiled unit. This is no doubt a step further than what Flash has achieved. One drawback, however, is, adoption among wide number of serious users. I don't see it as a big drawback as long as Microsoft is serious about this product.

Silverlight Kickstart

My silverlight development environment includes VS2008 with SP1, Framework 3.5, Silverlight SDK and Microsoft Expression Encoder. I would not get into these details for the scope of this article. You may refer to Getting Started article for Silverlight, to setup your development environment. Further, if you donot want to get into the intrecacies of XAML, then you might also require Microsoft Expression Blend.

WMV for streaming Video with Silverlight

Silverlight supports WMV format for videos. Using Microsoft Expression Encoder these WMV files can be encoded to have markers on their timelines. These markers can be used by siliverlight for interaction. The markers are simply names given to a time in the video's timeline. Silverlight raises MarkerReached event (if registered) when a marker is reached while playing the video. This forms the basis of interaction between silverlight and streaming videos. There is a nice video tutorial explaining, how to add a marker using Microsoft Expression Encoder.

Silverlight UI

XAML in Silverlight allows you to do a lot of stuffs with the UI using its declarative tags. Few, real interesting things you can do, without any extra skill required, includes, drawing a curve, masking, controlling opacity, define animation ... all through XML like declarative tags ... Wow!. In this tutorial, I will be showing you how to create an interactive overlay on a running video. For this, I have a video with three markers defined on it (using Encoder). Now let us first examine the UI.

The UI

Few things, I would like to explain here, before we proceed to next step, since they have been referred ahead. Take a sneak into the code for things, I have marked in bold. Notice that:

  • Movie name is "MainMovieStream" defined as an attribute "x:Name".
  • The "MarkerReached" event is registered for the movie as "MainMovieStream_MarkerReached".
  • Canvas with a name "TopOverlay" which is placed -325 pixels on the left.
  • "TopOverlay" canvas has an inner element "TopText" with an event "MouseLeftButtonDown" handled by "TopText_MouseLeftButtonDown" function
  • A Canvas "BottomOverlay" is defined in a similar faishon except its top is "131".
Silverlight Story Board

Take a sneak into the code for things, I have marked in bold. Notice that:

  • Storyboard "TopOverlayIn" targets the canvas "TopOverlay".
  • The "Storyboard.TargetProperty" tells us that the "Left" property has to be changed.
  • The "SplineDoubleKeyFrame" defines, that after every 1 sec the target property moves near to the "Value=0". Hence, the Canvas.Left moves from -325 to 0
  • The Storyboard "TopOverlayOut" does exactly the opposite of "TopOverlayIn".

MediaControl.xaml

The Storyboards are treated as Canvas resource which would be used when required. Let us see the complete XAML for our tutorial.

C# Code

When you add a XAML file into your solution, visual studio responds with adding an associated code behind file for the XAML. Besides, you would also find a App.xaml and its code behind file with same name. While doing any development on Silverlight, most of the time you would ask "How can I pass values to Silverlight application at runtime" or in another way "How can I make it as a component to be used in other projects?". This is done through parameter passing at the time of initialization.

App.xaml.cs

Let us sneak into App.xaml.cs file where the necessary changes has been made for the same. The only changes required in the App.xaml.cs file are:

  • Declare an "IDictionary" object for paramters as a class variable

    public partial class App : Application {

        privateIDictionary<string, string> initParams;


    ...

  • Initialize it in the "Application_Startup"

    private void Application_Startup(object sender, StartupEventArgs e)

    {

        this.RootVisual = new MediaControl();

        InitParams = e.InitParams;

    }

MediaControl.xaml.cs

Now let us sneak into the MediaControl.xaml.cs file to see how we collect the parameters and how we handle the animation and events.

In the code above we get the reference of the Silverlight application using "Application.Current as App" (marked in bold) in the "Page_Loaded" event. Once we have got the handle of the application we can access its public properties. In this case the parameters. As you can see, I am iterating through each parameters and storing the values into my local variables. The marker parameters here contains the storyboard names that we would see in the next section. Also notice, how I am handling the "MarkerReached" event and the "MouseLeftButtonDown" events. The actions are self explanatory here.

Embedding Silverlight RichMediaAd Control

Once you have done with this code, your control is ready to be used. When you compile a Silverlight application, you would notice that it generates a RichMediaAd.xap file under ClientBin folder of your web application which references the Silverlight application. This .xap file is nothing but a compressed file containing your application manifest and the DLL. You can use a simple un-zip command to view the files inside. In the page

Now let us see the code where we embed this Silverlight control we made.

Once you have embedded the XAP file. It is ready to run. Notice, that I am sending all necessary parameters at runtime, including the media I want to use.

Happy Silverlight Programming !!


 
  Posted in:  .Net