ASP.NET Core 5.0 – Bearer Authentication

ASP.NET Core supports several authentication methods which are Basic, Bearer, Digest, OAuth and others. This article will show you how to build a Bearer authentication to your Web API using IAsyncAuthorizationFilter and IPolicyEvaluator interfaces.


Bearer Authentication

Bearer authentication is an HTTP authentication scheme also called token authentication that involves security tokens called bearer tokens. Bearer Token is set in the Authorization header of HTTP Request.

Authorization: Bearer API Token

Why not use built in [Authorize]?

ASP.NET core official documentation does not talk about how to implement a custom Bearer Authentication. I have seen ton of samples explaining either [Authorize] or IDENTITY providers or OAUTH type authentications. However, this approach does not work on WEB API 2.0 apps which is written in .NET Full Framework.
NOTE: I’ve used IAuthenticationFilter interface to implement authentication in WEB API 2.0.

Creating ASP.NET 5.0 WEB API Project

Fire up your favorite IDE and create a brand new ASP.NET CORE Web API project template. The default template is pretty good to get started to implement Bearer token authentication method.

Project edit view

After successfully creating API project, click on edit project file and you should be able to see TargetFramework is netcoreapp5.0 and LangVersion is C# 9.0 which is in preview mode.


IAsyncAuthorizationFilter & IPolicyEvaluator

IAsyncAuthorizationFilter Interface – A filter that asynchronously confirms request authorization. Read more

IPolicyEvaluator Interface – Base class for authorization handlers that need to be called for a specific requirement type. Read more

Let’s implement IPolicyEvaluator interface first. The interface has two methods called AuthenticateAsync and AuthorizeAsync,

1) AuthenticateAsync method checks for Authorization header and read Bearer token from the request header.

  • Check Authorization header present in the request.
  • Read Bearer token and compare against the stored token.
  • Once token match successfully, set some Claims thus, you want to identity the request later.

2) AuthorizeAsync method does check whether the request has been already evaluated by IPolicyEvaluator and looks Succeeded or Challenged status and return Policy Authorization Result.

Below, you can find complete code for PolicyEvaluator class.

public sealed class BearerPolicyEvaluator : IPolicyEvaluator
private const string Scheme = "Bearer";
public Task<AuthenticateResult> AuthenticateAsync(AuthorizationPolicy _, HttpContext context)
if (!context.Request.Headers.ContainsKey("Authorization"))
return Task.FromResult(AuthenticateResult.Fail("No Authorization header found!"));
string authHeader = context.Request.Headers["Authorization"];
string bearerToken = authHeader?.Replace("Bearer ", string.Empty);
if (!string.Equals(bearerToken, "authToken", StringComparison.Ordinal))
return Task.FromResult(AuthenticateResult.Fail("Invalid token"));
var claims = new[]
new Claim(ClaimTypes.NameIdentifier, "1000"),
new Claim(ClaimTypes.Name, "Deepu Madhusoodanan")
var identity = new ClaimsIdentity(claims, Scheme);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme);
var authenticateResult = AuthenticateResult.Success(ticket);
return Task.FromResult(authenticateResult);
public Task<PolicyAuthorizationResult> AuthorizeAsync(AuthorizationPolicy _,
AuthenticateResult authenticationResult, HttpContext context,
object resource)
var authorizeResult = authenticationResult.Succeeded
? PolicyAuthorizationResult.Success()
: PolicyAuthorizationResult.Challenge();
return Task.FromResult(authorizeResult);

Next, implement IAsyncAuthorizationFilter interface.

OnAuthorizationAsync method calls above PolicyEvaluator API to get authentication and authorization result.

public sealed class BearerAuthorizeFilter : IAsyncAuthorizationFilter
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
if (context?.HttpContext?.Request?.Headers == null) throw new ArgumentNullException(nameof(context));
if (!context.HttpContext.Request.Headers.ContainsKey("Authorization"))
context.Result = CreateUnauthorized();
var policyEvaluator = context.HttpContext.RequestServices.GetRequiredService<IPolicyEvaluator>();
var authenticateResult = await policyEvaluator.AuthenticateAsync(default, context.HttpContext);
var authorizeResult = await policyEvaluator.AuthorizeAsync(default, authenticateResult, context.HttpContext, context);
if (authorizeResult.Challenged)
context.Result = CreateUnauthorized();
context.HttpContext.User = authenticateResult.Principal;
static IActionResult CreateUnauthorized() => new UnauthorizedObjectResult(new ErrorMessage("Unauthorized", 401));

Configure services

Final step would be registering authentication interface in Startup.cs class

public void ConfigureServices(IServiceCollection services)
   services.AddControllers(o => o.Filters.Add(new BearerAuthorizeFilter()));

NOTE: Using this approach, you wouldn’t need to use any middleware like use.Authentication() or [Authorize] attribute on API controllers.

Source repository

Github –


In this post I described how to implement custom Bearer token in ASP.NET Core projects with out using built in Authorize mechanism.

A big thank you to Microsoft MVP Steve Gordon who recommended to use JWT tokens and built in [Authorize] mechanism for APS.NET core projects!

Hope you enjoy reading the article and please feel free to give this a try and let me know your thoughts and suggestions.



A simple, lightweight data access library for any ADO.Net providers like SQL server, Oracle & MySQL.

Source –

No Dependencies

Since Data.Net is written in .NetStandard 2.0 no third party libraries are required.

Supporting platforms

Data.Net support multiple frameworks and platforms.

  • Net Core 2.0 / ASP.NET Core 2.0
  • Net Standard 2.0
  • NetFramework 4.6.1
  • NetFramework 4.6.2
  • NetFramework 4.7.0


Install Data.Net via Nuget

PM> Install-Package Data.Net

Execute a query and return a single value from the first row

using (var db = new Database()) //make sure connection string is configured in the config file with <connectionStrings><clear/><add../></connectionStrings>
  var firstName = db.ExecuteScalar<string>("SELECT FirstName From Users_Test Where Email = @Email",
                  parameters:new DataParameters{{"Email", "" } });

Execute a query and convert to POCO object

public class User
    public string FirstName { get; set; } //make sure property name is same as table column name, otherwise use alias in sql query.
    public string LastName { get; set; }
    public string Email { get; set; }

using(var db = new Database(new OracleConnection("connectionString")))
    List<User> q = db.Query<User>("SELECT EmailAddress as Email,LastName FROM Users_Test");
    Assert.IsTrue(q.Count > 0);

Execute a stored procedure and get multiple output parameter and return value.

 var parameters = new DataParameters
    { "@Email", "" },
    { "@RecordCount"}, //Default parameter direction is 'output'
    { "@AnotherOutParameter"},
    { "@ReturnVal",ParameterDirection.ReturnValue}

  var q = db.Query<User>("PROC_NAME", CommandType.StoredProcedure, parameters);
  Assert.IsTrue(q.Count > 0);
  Assert.IsTrue(dataParameter.Value<int>("@RecordCount") > 0);
  Assert.IsTrue(dataParameter.Value<int>("@AnotherOutParameter") > 0);
  Assert.IsTrue(dataParameter.Value<int>("@ReturnVal") > 0);

Execute a command with DB transaction.

using (var db = new Database())
      db.BeginTransaction(); //create transaction.
      db.ExecuteNonQuery("sql", parameters:new DataParameters{{"Email", "" } });
      db.ExecuteNonQuery("sql", parameters:new DataParameters{{"Email", "" } });
      db.CommitTransaction(); //commit transaction.
  catch (Exception)
      db.RollbackTransaction(); // rollback if any failure. 

Execute multiple query using a single DB connection instance

using(var db = new Database())
  var reader1 = db.ExecuteReader("sql",CommandType.Text,parameters,CommandBehavior.Default);
  var reader2 = db.ExecuteReader("sql",CommandType.Text,parameters); //default behaviour is close connection

Create DB provider specific parameter object

Data.Net support multiple overloads so that you can create DB specific parameter object like below.

public void Add(IDbDataParameter parameter) {}  //For any Ado.Net specific provider
public void Add(string name, object value) {}
public void Add(string name, ParameterDirection direction = ParameterDirection.Output,DbType dbType = DbType.Int32, int size = 0) {}

Example usage

var p = new DataParameter();

p.Add(new OracleParameter("name","value"));

Please check out more samples in the Unit test app.

.Net Core porting challenges

I was recently porting a .Net 4.6.2 C# Scheduler app to .Net core 1.0.1 Cent OS.7 64 bit machine in Azure and I’ve learned a good lesson especially with HttpClient API. I will be mainly focusing some of the issues I’ve encountered with .Net Core HttpClient library in Linux platform in this article.

As I mentioned above, Initially this app was targeting to .NetFramework Windows server and later I ported to Linux. Once after the app has been deployed to Azure Linux I was getting the following issues.

NOTE : Most of the issues I am talking here did not show up in Windows platform (Windows 10, Windows Server 2012 R2).

1) AppDomain & Unhanded exceptions

AppDomain.CurrentDomain.UnhandledException += UnhandledException;

The above one liner code for handling UnhandledException exception doesn’t work .Netcore 1.0 or 1.1. AppDomain class supports started from .NET Framework 1.1, however this was removed in .NetCore due to performance issue and other reasons here here and here which is fine I am totally agree the point. However, it would be great if they have alternate solution for handling Unhanded exception. Hoping this would get added in .Net Core 2.0 release.

2) ServicePointManager 

In .Net core there is no ServicePointManager class instead use base HttpHandler class and If you are on Windows use WinHttpHanlder and non windows platform make sure to use HttpClientHandler to call the method and properties like below.

 var handler = new HttpClientHandler
     AllowAutoRedirect = false;
     AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
 handler.ServerCertificateCustomValidationCallback += (sender, cert, chain, sslPolicyErrors) =&amp;gt; true;

3) PlatformNotSupportedException for ServerCertificateCustomValidationCallback

One of the common error you might encounter while using .Net core or Net standard in non windows platform is PlatformNotSupportedException. Hopefully they are going to address this in 2.0 versions. ServerCertificateCustomValidationCallback works fine in windows. However, by default this won’t work in Linux and MAC OS unless the libcurl library point to OpenSSL. I have opened a github issue and .Net corefx team was provided some solution to address the issue. Unfortunately there are no documentation explains these kind of issues.

The libcurl library in use (7.29.0) and its 
SSL backend ("NSS/3.19.1 Basic ECC") do not support custom handling of certificates. 
A libcurl built with OpenSSL is required.

4) System.Net.Http.HttpRequestException: The server returned an invalid or unrecognized response.
I have encountered this exception lately and I opened a new github issue and the corefx team planing to address this issue in 2.0.


Porting to .net core app is really great experience and good learning curve for the new platform. I would definitely recommend to check .NET Portability Analyzer to find out how much libraries and APIs are supporting to .Net Core. Also, follow github issue tracker for .Net Corefx repository.

References / Tools –

Convert C# camel case json property to pascal case

I am pretty sure that many of them faced the same scenario where you would end up copy/paste some json data from a third party API sites And using one of the tools like Visual Studio IDE or to generate POCO classes. However, these tools will not generate pascal case property’s automatically And if you want to maintain the coding standard you have to change the property’s to pascal case manually.

For example : Default camel case property’s generated based on Visual Studio IDE

public class Refunds
   public string @object { get; set; }
   public bool has_more { get; set; }

Since I had to convert many json property’s to pascal casing which is a tedious task so I have developed an app to convert camel case csharp json property to pascal case.

jsonProperty2TitleCase Core Features:

  • Convert property to Title case which is Pascal case
  • Add NewtonsoftJson property attribute to add the actual json property name for deserializing purpose.
  • Also, handles nested classes hierarchies.
  • Beautify your csharp code  (Remove all extra white spaces)

jsonProperty2TitleCase Output:

using Newtonsoft.Json;

public class Refunds
    public string Object { get; set; }

    public bool HasMore { get; set; }


Please feel free to give this a try and let me know your thoughts and suggestions.

Asp.Net MVC5 Authorization

The sample application will walk you through how to create Claim based Authorization Middleware with Owin and Katana libraries using .Net 4.5.2 framework.

Github source –


  • File -> New Project -> Asp.Net Web Application -> Asp.Net 4.5.2 Templates
  • Choose empty MVC project template


  • Install following nuget packages
    • Microsoft.AspNet.Identity.Core
    • Microsoft.AspNet.Identity.Owin
    • Microsoft.Owin
    • Microsoft.Owin.Host.SystemWeb
    • Microsoft.Owin.Security
    • Microsoft.Owin.Security.Cookies
    • Microsoft.Owin.Security.OAuth
    • Owin


  • Create a Owin Startup class and decorate with assembly attribute OwinStartup.
    using Microsoft.AspNet.Identity;
    using Microsoft.Owin;
    using Microsoft.Owin.Security.Cookies;
    using Owin;
    [assembly: OwinStartup(typeof(AspNetMVC5Authorization.Startup))]
    namespace AspNetMVC5Authorization
        public class Startup
            public void Configuration(IAppBuilder app)
            private void ConfigureAuthentication(IAppBuilder app)
                app.UseCookieAuthentication(new CookieAuthenticationOptions
                    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                    LoginPath = new PathString("/Auth/Login"), //sign page
                    CookieName = "AuthCookie",
                    CookieHttpOnly = true,
                    ExpireTimeSpan = System.TimeSpan.FromHours(1),
                    LogoutPath = new PathString("/Auth/Signout"), //sign out page
                    ReturnUrlParameter = "ReturnUrl",
                    CookieSecure = CookieSecureOption.SameAsRequest, //Use CookieSecureOption.Always if you intend to serve cookie in SSL/TLS (Https)
                    SlidingExpiration = true,


  • Create list of claims for the specific user with roles and other information
    internal class AuthenticationHelper
       internal static List<Claim> CreateClaim(UserSessionModel userSessionModel,params string[] roles) //Single or multiple roles
          var claims = new List<Claim>
              new Claim(ClaimTypes.NameIdentifier, userSessionModel.UserId.ToString()),  //User ideitifer
              new Claim(ClaimTypes.Name, userSessionModel.DisplayName),  //Username
              new Claim(Constants.UserSession, userSessionModel.ToJson()) //Custom entity with user info
          foreach (var role in roles) //custom roles goes here
              claims.Add(new Claim(ClaimTypes.Role, role, ClaimValueTypes.String, Constants.Issuer));
          return claims;


  • Create Authentication controller and process of the rest of the Authentication
    using Microsoft.AspNet.Identity;
    using Microsoft.Owin.Security;
    using System.Security.Claims;

    public class AuthController : BaseController
      private IAuthenticationManager AuthenticationManager
          get { return HttpContext.GetOwinContext().Authentication; }

      public ActionResult SignIn(SignInViewModel vm,string returnUrl = default(string))
              if (!ModelState.IsValid)
                  vm.ErrorMessage = "Email address and Password are required fields";
                  return View(vm);

              var userSession = Authenticate(vm); // Validate authentication from db or other source.

              if (userSession != null) //create claim with user info.
                  var identity = new ClaimsIdentity(AuthenticationHelper.CreateClaim(userSession, 
                  AuthenticationManager.SignIn(new AuthenticationProperties()
                      AllowRefresh = true,
                      IsPersistent = true,
                      ExpiresUtc = DateTime.UtcNow.AddHours(1)
                  }, identity);

                  if (!string.IsNullOrWhiteSpace(returnUrl) && Url.IsLocalUrl(returnUrl)) return Redirect(returnUrl);

                  return RedirectToAction("index", "home");
          catch (AuthenticationException e)
              vm.ErrorMessage = e.Message;
          return View(vm);

      private UserSessionModel Authenticate(SignInViewModel vm)
          if (vm.Email != "" || vm.Password != "password") throw new AuthenticationException("Login failed. Incorrect email address or password");

          return new UserSessionModel
              UserId = Guid.NewGuid(),
              DisplayName = "Deepu Madhusoodanan"

      public ActionResult Signout()
          return Redirect("~/");


  • Get the custom ojbect obect from Claim
public class BaseController : Controller
    protected internal UserSessionModel UserSessionModel { get; private set; }

    protected override void Initialize(RequestContext requestContext)
        var user = User as ClaimsPrincipal;
        if (user != null)
            var claims = user.Claims.ToList();
            var sessionClaim = claims.FirstOrDefault(o => o.Type == Constants.UserSession);
            if (sessionClaim != null)
                UserSessionModel = sessionClaim.Value.ToObject<UserSessionModel>();


[Authorize(ClaimType = ClaimTypes.Role, ClaimValue = "Contributor,User")]
public ActionResult Secure()
    var userSessionModel = UserSessionModel; //Get custom object from Security claim.
    return View();

Finally Custom Authorize attribute code

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
    public string ClaimType { get; set; }
    public string ClaimValue { get; set; }

    public override void OnAuthorization(AuthorizationContext filterContext)
        var principal = filterContext.RequestContext.HttpContext.User as ClaimsPrincipal;

        if (!principal.Identity.IsAuthenticated)
            filterContext.Result = new RedirectResult("~/auth/signin");

        var claimValue = ClaimValue.Split(','); //Split custom roles and validate custom cliams, issuer and vlaue.
        if (!(principal.HasClaim(x => x.Type == ClaimType && claimValue.Any(v => v == x.Value) && x.Issuer == Constants.Issuer)))
            filterContext.Result = new RedirectResult("~/Unauthorize.html");

MadMimi.Net Integration

I have been playing around with Transaction Email Services for a while and came across the tool named MadMimi, A email marketing tool lets you to send email from a different server so that you can track whether the email delivered or bounce.

MadMimi already have a C# version API and its quite old. The reason I wrote my own version is to prevent less code change to my current project so that if I want to switch to a different provider in the feature it would be easy.

A typical email sending code

using (var message = new MailMessage())
    message.From = new MailAddress("from");
    message.Subject = "Subject";
    message.Body = "This is test";
    using (var client = new SmtpClient())

Using Library

  var mailer = new Mailer("username", "apikey");
  using (var message = new MailMessage())
      message.From = new MailAddress("from email", "display name");
      message.To.Add("sender email");
      message.Subject = "Test";
      message.Body = "Email body";
      await mailer.SendAsync("Promotion Name", message);
  var status = mailer.TrackStatus; //URL to track the email
  var mailTransactionId = mailer.TransactionId; //Transaction Id.

When you compare the above code snippets you should see additional two liner code which integrate the library (Mailer class) and that is the only change you should make your existing project and apps if you would like to integrate this.

Sender Policy Framework) – MadMimi does not care if you have set up a SPF record in DNS. While most of the competitors, this is a mandatory requirement if you want to use your own “FROM” email address other than your DOMAIN.

1) Delivery speed – Some time the email take 5-6 minutes to deliver.
2) No SMTP relay support.
3) Attachment does not support via API.

Feel free to play around and fork it if you would like to make any change to this. The GitHub link is provided below for the sample project and library.

Repository –

First Data Global Gateway Integration in Asp.Net MVC C#

I have added a new Github repository for First Data Global Gateway Integration in Asp.Net MVC.  The sample provides a rest api implementation for credit card based payment processing. Since, I have choosen Asp.Net MVC empty project template you might need to install System.Net.HttpClient library from or install directly from visual studio.

Command – Install-Package Microsoft.Net.Http

Download Location or copy paste the url

This code was taken from the original source

Example Usage:

 var paymentService = new PaymentService("1.50", "0515","Card holder name","4111111111111111", "23".ToString()); //customer Id for Internal purpose to track which customer made the transaction...
 var transactionResult = await paymenetService.PostAsync();
 if (transactionResult == null) return;
 if (transactionResult.TransactionApproved && !transactionResult.TransactionError && transactionResult.CustomerRef == customerId.ToString())
 //transaction success....
 //transaction failed
 var message = transactionResult.Message;

Configuration Settings:
Following values needs to be changed in the web.config file.

<add key="GATEWAY_ID" value="Exact ID" />
<add key="GATEWAY_PWD" value="Password" />
<add key="TRANS_TYPE" value="00" />
<add key="HMAC_KEY" value="HMAC Key" />
<add key="KEY_ID" value="Key Id" />
<add key="GATEWAY_URL" value="" />

Transaction Summary file(transaction_summary.xml) from payment gateway is included in the App_Data folder.

Also, refer :

As per First Data knowledge base Note: “Code samples are provided “as is” and are not designed to be used in production.”


Custom Template in InfoPath 2010

I’ve been playing around with InfoPath forms this weekend  for converting paper forms to eForms (Infopath forms). One of the challenge  I have faced was maintaining the consistency of application look and feel for all the forms, since InfoPath designer doesn’t support master page layout  but it also provide an alternative solution called custom TEMPLATE control which you can convert any layout in to a .STP file and can reuse across all the forms.

Click here to Download the template

Open InfoPath Designer 2010 and select Template Parts as BLANK  and click Design Form

Design your own layout…I have created a sample STP layout and Save it as  Infopath Web Browser Template Part.

Once you  save the template as .STP file then you can add it as custom template in the template section

Click Add or Remove Custom Controls and select template part and browse your .STP file.

Once the template added successfully it will appear in the Custom control section

That’s it. Now you can reuse the new custom template / control to any new forms and existing forms.

Click here to Download the template

Hope this helps and If you have any comments, please feel free to write your feedback.


Silverlight Dashboard

I  have found a dashboard control from Microsoft expression website (created by which  inspired me to create a  dashboard control.

Click here to watch live   |   Click here to Download

In this article I’m going to explain the types of controls used to create a interactive dashboard.

  1. Grid based layout
  2. Customer Master / Detail  list
  3. Chart control
  4. Bing Map control
  5. Custom Splash screen

Grid based layout

A simple grid  layout with 2/2 row column.

<RowDefinition Height="5"/>
<RowDefinition Height="85"/>
<RowDefinition Height="*"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="250"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>

Customer Master / Detail  list

For master detail scenario ListBox control is the right choice to build.. The control will list the customer name and location, once you click the detail link its going to take you to a popup window for more information.
<ListBox x:Name="lbCustomer" Style="{StaticResource ListBoxBackground}" SelectionChanged="CustomerChanged">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImageSource}" Height="73" Width="73" VerticalAlignment="Top" Margin="0,10,8,0"/>
<TextBlock Text="{Binding Name}" Foreground="YellowGreen" FontSize="14" />
<HyperlinkButton Content="Detail" Foreground="DarkRed" Name="lnkDetailCustomer" Click="CustomerDetailClick" />

Chart Controls

Bar Chart

<toolkit:Chart Style="{StaticResource ChartBackground}" Name="chartCoulumn" Width="490" Height="290">
<toolkit:ColumnSeries SelectionChanged="ColumnSeriesChanged" Name="chart1" Title="Sales" DependentValuePath="Profit"
<Style TargetType="toolkit:ColumnDataPoint">
<Setter Property="Background" Value="YellowGreen"/>
<Setter Property="BorderBrush" Value="YellowGreen"/>

Pie chart

<toolkit:Chart Style="{StaticResource ChartBackground}" x:Name="chartPie" VerticalAlignment="Top" Width="340" Height="290">
<toolkit:PieSeries Margin="0,0,0,0" Padding="0,0,0,0" IndependentValuePath="Month"
DependentValuePath="Profit" AnimationSequence="Simultaneous"/>


<bing:Map Width="600" Grid.Row="2" Margin="2,2,2,2" HorizontalAlignment="Center" VerticalAlignment="Stretch"
CredentialsProvider="<Replace your credential here" Name="map" LogoVisibility="Collapsed" Culture="en-US" >

Click here to watch live   |   Click here to Download

Hope this helps and If you have any comments, please feel free to write your feedback.

Animation using PathListBox control in Silverlight

The PathListBox is new control introduced in Silverlight 4.0 for listing items in a various shapes like path, circle, arc, rectangle etc. This control is similar to traditional ListBox control which support data binding and display of one or more items at design time or dynamically at run time. The pathlistbox provides many properties like orienation, padding etc.

Watch Video |  Live Demo Download Source Code | Download Presentation

In this tutorial, we’ll create a simple animation using PathListBox Control..

Open Expression Blend Editor & Create a new project in Silverlight Application + Website.

Add a new shape  Ellipse in to the page.

Add a PathListBox control in to the page(PLB).

Drag & drop few images in to PLB control. (Press control to select multiple items from the project properties).

 Select PLB control from object & time line window.

Go to PLB control properties window and find out Layout Paths.

Click on select an object to use as a LayoutPath.

Select Ellipse shape as the LayoutPath

The images should show in circular layout path

Add a Projection for Ellipse  shape called PlaneProjection to rotate the Ellipse.

Add a StoryBoad control from object & time line window.

Switch to XAML version and write few lines of XAML code for animation purpose.

Add a Double Animation inside the StoryBoard control and set Target name & properties.

Add the following line of code in the Page Load method in order to start the animation.

Hit F5 and see the demo.

Watch Video |  Live Demo Download Source Code | Download Presentation

Hope this helps and If you have any comments, please feel free to write your feedback.