Blogs

The One With

  • Building ASP.NET Web Apps for iOS

         

    Building an ASP.NET Web App for iOS means making sure it looks and behaves just like a native iOS app.

    Let me show you how to build one using the ASP.NET Controls from DXv2.

    Preparing the Project

    We’ll start by creating a new ASP.NET Empty Web Application

    New ASP.NET Web Application

    and copy the iOS theme files to the App_Themes folder. (Note: The iOS theme files are attached in the sample project at the bottom)

    image

    After you import the iOS theme into the project, make sure it is applied to your Default.aspx page.

    The core of our app will be the TabBar.  And we’ll use the ASPxPageControl to mimic it.

    After you drag the ASPxPageControl from the Toolbox, set it’s SkinID to TabBar.

    <body>
        <form id="form1" runat="server">
          <dx:ASPxPageControl runat="server" ID="TabBar" SkinID="TabBar" 
            ActiveTabIndex="0">
            <TabPages>
              <dx:TabPage>
                <ContentCollection>
                  <dx:ContentControl runat="server" SupportsDisabledAttribute="True">
                  </dx:ContentControl>
                </ContentCollection>
              </dx:TabPage>
            </TabPages>
            <ClientSideEvents 
              Init="OnTabBarInit" 
              ActiveTabChanged="function(){ Adjust(); }"/>
          </dx:ASPxPageControl>
        </form>
    </body>
    

    and assign two client side events:

    • Init: Will be fired when control is initialized.
    • ActiveTabChanged: Will be fired when a tab page is changed.

    we need to do this to make sure that our TabBar is at the very bottom of the page.

    <script type="text/javascript">
        function Adjust() {
          TabBar.SetHeight(ASPxClientUtils.GetDocumentClientHeight());
        }
        function OnTabBarInit() {
          ASPxClientUtils.AttachEventToElement(window, "orientationchange",
              function () { Adjust(); }, false);
          if (!ASPxClientUtils.touchUI) {
            ASPxClientUtils.AttachEventToElement(window, "resize",
              function () { Adjust(); }, false);
          }
          Adjust();
        }
    </script>
    

    ASP.NET Web App for iOS

    Building App Screens

    Adding app screens is done by adding new tab pages.

    For each tab, we set the image and make it 42 by 79 in size.

    And we are ready done!

    ASP.NET Web App for iOS

    Download the sample project here

    Cheers

    Azret

  • Build for Beautiful with DXv2: Metro Inspired WinForms Apps

         

    Designing beautiful apps is not an easy task. But with DXv2, building beautiful Metro inspired applications is easier than ever. Let me show you how:

    WinForms Metro App - Tile Control

    WinForms Metro App - Grid Control

     

    Prepare the project

    Create a new WinForms Project and add a DevExpress Form to it. This will be the main or “home” screen for the app.

    WinForms Metro App - Add New Form

    We’ll need to bring in two assemblies:

    WinForms Metro App - Add Reference

    1: DevExpress.Metro.Navigation: This assembly contains sample code for building basic Metro inspired layouts and navigation. You will also find additional goodies like Transitions, which you can use in other areas of your app.

    2: MetropolisDark4Touch: This is a new Metropolis Dark skin that has been optimized for touch. We’ll register it like so:

    static void Main() {
        DevExpress.Skins.SkinManager.Default.RegisterAssembly(
            typeof(DevExpress.UserSkins.MetropolisDark).Assembly
        );
    
        DevExpress.LookAndFeel.UserLookAndFeel.Default.SetSkinStyle(
            "Metropolis Dark 4 Touch"
        );
    
        DevExpress.Skins.SkinManager.EnableFormSkins();
    
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new DXv2());
    }
     

    Add your business screens

    After we prepare the app for Metro, we can start designing our screens. For the home screen, we’ll use the new TileControl.

    WinForms Metro App Toolbox - Tile Control

    WinForms Metro App - Home Screen

    Note: You can watch the Getting Started with Tile Control Video here.

    To build a new app screen we simply create a new DevExpress Form and customize it to our needs. For example, a simple customers list displayed in a Grid at design time:

    WinForms Metro App - Grid Control Screen

    To switch to this screen in our app, simply invoke it from the click event:

    private void CustomersItem_Click(object sender, TileItemEventArgs e) {
        this.GoTo<Customers>();
    }

    And that’s pretty much it Smile

    Download the sample app and skin here. (Build: 11.2.7+)

    Step by step video:

    Cheers

    Azret

     

  • Rich Text Editor - Adding a Barcode into a Document

         

    In my previous post Adding a chart into a Document, I showed you how you can create custom proprietary calculated field to render a live chart. Let’s use the same technique to render a barcode. I will reuse the existing barcode generators from our Reporting Suite.

    Data Matrix Barcode

    Field Code:

    • BRCODE (BARCODE is a reserved field, Final name TBD).

    Switches:

    • \t – Specifies the barcode type. Supported barcodes.
    • \l – If this switch is set, the eye readable text will be drawn at the bottom of the barcode.
    • \w – Specifies the barcode width
    • \h – Specifies the barcode height
    • \d – Barcode Data
    • \p – Barcode specific option. For example for Code128, this switch determines the character set to be used. e.g. \p 128b
    • \r – This switch is used by a number of barcode types to determine the density. e.g. \r 2.6
    • \c \e \o \k – Barcode specific options. (See note below)

    Example:

    {BRCODE \t PDF417 \w 300 \h 150 \m text \r 3 \c 1 \p 3 \e 3 \o \l \d "PDF 417"}

    Download the source code

    Notes:

    I should note that even though the techniques I am showing you here open up oh so many possibilities, don’t enable this for your users just yet. Give us some time to sort all the details outs Smile. And if you are an early adopter, send me an email with your questions, comments and suggestions. Especially if you have an interesting use-case for this.

    Cheers

    Azret

  • Windows Live developer platform adds OAuth 2.0

         

    OAuth 2.0Today Windows Live team announced support for OAuth 2.0

    Quote “Not only have we made Messenger Connect the most up-to-date implementation of OAuth 2.0, but we’ve also taken this opportunity to improve key aspects of the developer and end user experience when going through the user authorization process…”


    I blogged about our new OAuth library recently and showed you how to connect to Facebook. Here is another example, this time we’ll connect to the new Windows Live - v5.0.

    Download Code

    Cheers

    Azret

  • Rich Text Editor - Adding a Chart into a Document

         

    Rachel already showed you what you can do (Master-Detail Mail Merge) with a generic calculated field like DOCVARIABLE. I want to take it a bit further and show you how to create a custom field.

    Would you like to embed a chart into your documents? Smile

    Rich Text Document with Live Chart

    Field Code:

    • CHART

    Switches:

    • \c – Specifies the chart type. Supported charts are bar, pie and line. If not specified defaults to pie.
    • \l – This switch determines if the chart should display a legend.
    • \w – Specifies the chart width
    • \h – Specifies the chart height
    • \d – Comma separated data points

    Example:

    {CHART \c pie \w 500 \h 300 \l \d "Asia|4140336501,Africa|994527534,Europe|738523843,North America|528720588,South America|385742554,Oceania|36102071,Antarctica|3687"}

    Download the source code

    Cheers

    Azret

  • OAuth Library – The Basics of Implementing a Service Provider

         

    OAuthLast time I showed you how to connect to Facebook, Twitter and Google using the DevExpress OAuth Library. This time, let me show you an example of the most basic OAuth 1.0 service provider. Before you dig into the implementation however, I want to point you to a prerequisite article on http://hueniverse.com by Eran Hammer-Lahav. Eran does a very good job explaining the protocol flow.

    How to implement an OAuth Service Provider

    OAuth 1.0 Service Provider

    Live Demo

    Cheers

    Azret

  • WPF Grid Control – Per-Pixel Scrolling, DataRowTemplateSelector and some fun

         

    I am pretty excited about the new Per-Pixel Scrolling option that’s coming out in v2011 vol 1. Emil explained it in his post here. The smooth per-pixel scrolling experience is exactly what I wanted for my little WPF Facebook Client.

    Check out this example where I enable the Per-Pixel Scrolling and also make use of the DataRowTemplateSelector to dynamically select a row template.

    Cheers

    Azret

  • OAuth Library – (available now in v2011, volume 1)

         

    OAuthIn v2011 volume 1, the OAuth library that we’ve developed for internal use, is available to all our customers.

    The DevExpress OAuth library supports the consumer side for OAuth 1.0 and OAuth 2.0 Draft as well as the provider side for OAuth 1.0.

     

     

     

    The following example How to login to Twitter, Google and Facebook using OAuth demonstrates how to login to some of the most popular services that support OAuth authentication.

    How to login to Twitter, Google and Facebook using OAuth

    Cheers

    Azret

  • MIX 2011 - Keynote and Announcements

         

     

    Here we are at MIX 11 in Las Vegas, NV. The exhibit hall is very cool with big IE9 and IE10 kiosks in the middle where developers can try the latest bits of IE. Our booth is right next to it, and everyone is actually running straight to us for those cool T-Shirts J.  The organizers of the event did a good job setting everything up so that our team could catch up on some needed sleep.  

     

    Speaking of IE9 and IE10... Everyone is talking about today’s keynote and the exciting features that the IE team was able to deliver with the latest release of IE9. Dean Hachamovitch and Steven Sinofsky demoed IE9 and Chrome side by side focusing on how hardware acceleration truly changes the user experience, especially for the new capabilities in HTML5. If that wasn’t exciting enough, the guys have announced an IE 10 Platform Preview. Definitely check it out!

    Later, Scott Guthrie recapped some awesome things his team has put out this year: MVC 3, Razor, WebMatrix and NuGet. Yes, totally #winning Scott (an inside keynote joke J). Scott also announced Entity Framework 4.1 and a new update to the ASP.NET MVC Tools. The new update brings HTML5 support into the MVC3 project wizards, jQuery 1.5 and Modernizr - http://www.modernizr.com/ more on those later.

    Then, Mr. Gu invited Scott Hanselman to the stage where Scott H. showed how he built http://thisdeveloperslife.com/ using Visual Studio, WebMatrix and EF 4.1.

    I am off to catch a session, will keep you guys posted...Here's a photo of our kiosk for those interested (and if you are here in Vegas, make sure to stop by say hell o and get your VIP pass for the party Wed night)

    MIX 2011 Las Vegas NV - DevExpress Kiosk

    Cheers

    Azret

  • OData and OAuth - Part 5 – OAuth 1.0 Service Provider in ASP.NET MVC

         

    OAuthImplementing an OAuth service provider is not a difficult task once you select an OAuth library that you like. The one I am going to be using is the one I like the most. It’s simple to use and gives me a lot of freedom when it comes to token management.

    The authentication flow should already be familiar from our experience as an OAuth consumer

    Let’s follow the spec. From section 6 - Authenticating with OAuth of the 1.0 spec:

    Service Provider Grants Request Token

    Typically, you would write and IHttpHandler for handling OAuth requests in ASP.NET. I find that it’s much cleaner to have them go through the MVC Controller.

    public ActionResult GetRequestToken() {
        Response response 
            = ServiceProvider.GetRequestToken(
                Request.HttpMethod,
                Request.Url);
        
        this.Response.StatusCode = response.StatusCode;
        return Content(response.Content, response.ContentType);
    }

    Behind the scenes, ServiceProvider.GetRequestToken() will parse the query parameters and validate the signature of the request based on the specified signing method. The specified consumer key will be validated using a ConsumerStore object that we can configure in Web.config.

    <section name="oauth.consumerTokenStore" type="BankOfShire.OAuth.ConsumerTokenStore" />

    The default implementation accepts anonymous/anonymous but it’s a good idea to require a consumer registration and issue consumer keys and secrets. Just like we did for twitter here.

    public class ConsumerStore : ConfigurationSection, IConsumerStore {
        public virtual IConsumer GetConsumer(string consumerKey) {
            if (String.Equals(consumerKey, "anonymous")) {
                return new ConsumerBase() {
                    CallbackUri = null,
                    ConsumerKey = "anonymous",
                    ConsumerSecret = "anonymous",
                };
            }
            return null;
        }
    }

    The responsibility for issuing request tokens is assigned to RequestTokenStore. Configurable in Web.config:

    <section name="oauth.requestTokenStore" type="BankOfShire.OAuth.RequestTokenCache" />

    Request tokens in OAuth 1.0 are short lived. They should only be valid during the authentication process. If you look at the authentication flow above, that would be from B to F.

    So how long should the request token lifetime be? Yahoo for example issues tokens that expire after 1 hour. Is this enough time for the user to type in their credentials? I think so. Maybe even too long. Remember, longer lifespan means more physical hardware. The ideal situation is too keep request tokens in memory without having to persist them in the database. For small sites, ASP.NET Cache should do fine:

    public class RequestTokenCache : RequestTokenStore {
        public override IToken GetToken(string token) {
            HttpContext context = HttpContext.Current;
            if (context != null) {
                return context.Cache.Get("rt:" + token) as IToken;
            }
            return null;
        }
    
        public override IToken AuthorizeToken(string token, 
                string authenticationTicket) {
            HttpContext context = HttpContext.Current;
            if (context == null) {
                return null;
            }
            IToken unauthorizeToken = context.Cache.Get("rt:" + token) as IToken;
            if (unauthorizeToken == null
                            || unauthorizeToken.IsEmpty) {
                return null;
            }
            IToken authorizeToken = new Token(
                unauthorizeToken.ConsumerKey,
                unauthorizeToken.ConsumerKey,
                unauthorizeToken.Value,
                unauthorizeToken.Secret,
                authenticationTicket,
                unauthorizeToken.Verifier,
                unauthorizeToken.Callback);            
            context.Cache.Insert(
                "rt:" + authorizeToken.Value,
                authorizeToken,
                null,
                DateTime.UtcNow.AddSeconds(base.ExpirationSeconds),
                System.Web.Caching.Cache.NoSlidingExpiration
            );
            return authorizeToken;
        }
    
        public override IToken CreateUnauthorizeToken(string consumerKey, 
                string consumerSecret, string callback) {
            IToken unauthorizeToken = new Token(
                    consumerKey,
                    consumerSecret,
                    Token.NewToken(TokenLength.Long),
                    Token.NewToken(TokenLength.Long),
                    String.Empty, /* unauthorized */
                    Token.NewToken(TokenLength.Short),
                    callback);
            HttpContext context = HttpContext.Current;
            if (context != null) {
                context.Cache.Insert(
                       "rt:" + unauthorizeToken.Value,
                       unauthorizeToken,
                       null,
                       DateTime.UtcNow.AddSeconds(base.ExpirationSeconds),
                       System.Web.Caching.Cache.NoSlidingExpiration
                    );
            }
            return unauthorizeToken;
        }
    }

    But I strongly recommend exploring other caching solutions: Memcached, Velocity and other distributed caches if you can. If you can’t, just store them in the database and do some clean up periodically.

    Service Provider Directs User to Consumer

    Once the request token is issued, the consumer will redirect to the provider site so that the user can enter the credentials. We’ll need to markup some UI.

    [HttpPost]
    public ActionResult AuthorizeToken(AuthorizeModel model) {
        try {
            IToken token;
            if (!VerifyRequestToken(out token)) {
                return View(model);
            }
            if (model.Allow != "Allow") {
                return Redirect(token.Callback);
            }
            MixedAuthenticationIdentity identity 
                    = MixedAuthentication.GetMixedIdentity();
            if (identity == null
                            || !identity.IsAuthenticated) {
                if (!ModelState.IsValid) {
                    return View(model);
                }
            }
            MixedAuthenticationTicket ticket
                = identity != null && identity.IsAuthenticated ?
                    identity.CreateTicket() :
                    MembershipService.ResolvePrincipalIdentity(
                        model.Email,
                        model.Password);
            bool authorized = false;
            if (CanImpersonate(ticket)) {
                if (AuthorizeRequestToken(
                        ticket,
                        out token)) {
                    MixedAuthentication.SetAuthCookie(ticket, true, null);
                    authorized = true;
                }
            } else {
                ModelState.AddModelError("", "Email address or Password is incorrect.");
            }
            if (authorized) {
                Uri returnUri = ((Url)token.Callback).ToUri(
                    Parameter.Token(token.Value),
                    Parameter.Verifier(token.Verifier));
                return Redirect(returnUri.ToString());
            }
            return View(model);
        } catch (Exception e) {
            ModelState.AddModelError("", e);
            return View(model);
        }
    }

    ServiceProvider has a helper method to deal with request token authorization. We’ll authorize request tokens using the same ticket that we use for normal sign-ins. (You can read about MixedAuthenticationTicket here.)  The RequestTokenStore will be responsible for issuing authorized tokens. See RequestTokenStore.AuthorizeToken above.

    bool AuthorizeRequestToken(MixedAuthenticationTicket ticket, 
            out IToken token) {
        ValidationScope scope;
        token = ServiceProvider.AuthorizeRequestToken(
                    Request.HttpMethod,
                    Request.Url,
                    ticket.ToJson(),
                    out scope);
        if (token == null || token.IsEmpty) {
            if (scope != null) {
                foreach (ValidationError error in scope.Errors) {
                    ModelState.AddModelError("", error.Message);
                    return false;
                }
            }
            ModelState.AddModelError("", "Invalid / expired token");
            return false;
        }
        return true;
    }

    image

    Service Provider Grants Access Token

    Once the request token has been authorized, we need to issue a permanent (or long lived) access token.

    public ActionResult GetAccessToken() {
        Response response 
            = ServiceProvider.GetAccessToken(
                Request.HttpMethod,
                Request.Url);
    
        this.Response.StatusCode = response.StatusCode;            
        return Content(response.Content, response.ContentType);
    }

    It will be the responsibility of the AccessTokenStore to issue new tokens. Here is an implementation that we use for our site. Remember, we use XPO for our data access with MySql in the back.

    <section name="oauth.accessTokenStore" type="BankOfShire.OAuth.AccessTokenCache" />
    public class AccessTokenCache : AccessTokenStore {
        public override IToken GetToken(string token) {
            if (String.IsNullOrEmpty(token)) {
                return null;
            }
            IToken t = null;
            using (Session session = _Global.CreateSession()) {
                t = session.GetObjectByKey<Data.Token>(token);
                if (t == null
                                || t.IsEmpty) {
                    return null;
                }
            }
            return t;
        }
        public override void RevokeToken(string token) {
            if (String.IsNullOrEmpty(token)) {
                return;
            }
            using (Session session = _Global.CreateSession()) {
                session.BeginTransaction();
                Data.Token t = session.GetObjectByKey<Data.Token>(token);
                if (t != null) {
                    t.Delete();
                }
                session.CommitTransaction();
            }
        }
        public override IToken CreateToken(IToken requestToken) {
            if (requestToken == null || requestToken.IsEmpty) {
                throw new ArgumentException("requestToken is null or empty.");
            }
            Token token = new Token(
                requestToken.ConsumerKey,
                requestToken.ConsumerSecret,
                Token.NewToken(TokenLength.Long),
                Token.NewToken(TokenLength.Long),
                requestToken.AuthenticationTicket,
                String.Empty,
                String.Empty
            );
            using (Session session = _Global.CreateSession()) {
                DateTime utcNow = DateTime.UtcNow;
                session.BeginTransaction();
                Data.Token t = new Data.Token(session);
                t.Value = token.Value;
                t.Secret = token.Secret;
                t.ConsumerKey = token.ConsumerKey;
                t.ConsumerSecret = token.ConsumerSecret;
                t.AuthenticationTicket = token.AuthenticationTicket;
                t.Created = utcNow;
                t.Modified = utcNow;
                t.Save();          
                session.CommitTransaction();
            }
            return token;
        }
    }

    An XPO object for our token store:

    [Persistent("Tokens")]
    public class Token : XPLiteObject, DevExpress.OAuth.IToken {
        public Token() : base() { }
        public Token(Session session) : base(session) { }
        
        [Key(AutoGenerate = false)]
        [Size(128)]
        public string Value { get; set; }
        [Size(128)]
        public string Secret { get; set; }
    
        [Indexed(Unique=false)]
        [Size(128)]
        public string ConsumerKey { get; set; }
        [Size(128)]
        public string ConsumerSecret { get; set; }
    
        [Size(SizeAttribute.Unlimited)]
        public string AuthenticationTicket { get; set; }
    
        public DateTime Created { get; set; }
        public DateTime Modified { get; set; }
    
        bool DevExpress.OAuth.IToken.IsEmpty {
            get {
                return String.IsNullOrEmpty(Value) ||
                    String.IsNullOrEmpty(Secret) ||
                    String.IsNullOrEmpty(ConsumerKey) ||
                    String.IsNullOrEmpty(ConsumerSecret);
            }
        }
    
        bool DevExpress.OAuth.IToken.IsCallbackConfirmed {
            get { 
                return true; 
            }
        }
    
        string DevExpress.OAuth.IToken.Callback {
            get { return String.Empty; }
        }
    
        string DevExpress.OAuth.IToken.Verifier {
            get { return String.Empty; }
        }
    }

    That’s it, as far as the authentication flow is goes. Now when a request for a protected resources comes in (with a previously issued access token) we can check the Authorization’ header and create the appropriate MixedAuthenticationIdentity.

    MixedAuthenticationTicket ticket;
    stringauthorizationHeader = HttpContext.Current != null?
            HttpContext.Current.Request.Headers["Authorization"] : null;
    if(!String.IsNullOrEmpty(authorizationHeader)) {
       
        ValidationScope scope;               
        TokenIdentity tokenIdentity = ServiceProvider.GetTokenIdentity(
                        context.Request.HttpMethod,
                        context.Request.Url,
                        authorizationHeader,
                        outscope);
        if(tokenIdentity == null) {
            if(scope != null) {
                foreach (ValidationError error inscope.Errors) {
                    throw newHttpException(error.StatusCode, error.Message);
                }
            }
            return null;
        }
        ticket = MixedAuthenticationTicket.FromJson(tokenIdentity.AuthenticationTicket);

    }

    Note that the MixedAuthentication helper class takes care of this so our Application_AuthenticateRequest will work the same for both Forms Authentication (cookie) and OAuth (Access Token).

    protected void Application_AuthenticateRequest(object sender, EventArgs e) {
        MixedAuthenticationPrincipal p = MixedAuthentication.GetMixedPrincipal();
    
        if (p != null) {
            HttpContext.Current.User = p;
            Thread.CurrentPrincipal = p;
        }
    }

     

    What’s next

    Download source code for Part 5

    Cheers

    Azret

  • OData and OAuth - Part 4 – Managing Identities

         

    We’re almost ready to implement an OAuth 1.0 Service provider. But first, let’s make sure our member accounts are properly password protected. Since we allow to sign in using different credentials into the same account, we need a place to store all those different identities.

    public enum AuthenticationType : int {
        Principal = 0,
        Google = 1,
        Facebook = 2,
        Twitter = 3,
    }
    
    [Persistent("Identities")]
    public class Identity : XPLiteObject {
        public Identity() : base() { }
        public Identity(Session session) : base(session) { }
    
        [Key(AutoGenerate = true)]
        public Guid ID { get; set; }
        
        [Indexed(Unique = true)]
        [Size(128)]
        public string Hash { get; set; }
    
        [Indexed(Unique = false)]
        public Nullable<Guid> Principal { get; set; }
    
        [Size(128)]
        public string Token { get; set; }
        [Size(128)]
        public string Secret { get; set; }
    
        public AuthenticationType AuthenticationType { get; set; }
    
        public DateTime Created { get; set; }
        public DateTime Modified { get; set; }
    }

    AuthenticationType

    Specified the type of the identity.

    Hash

    A unique value given to an identity by the provider. We must make sure that this value is unique per provider/authentication type.

    • AuthenticationType.Principal: We use “Principal” + Email address
    • AuthenticationType.Google: We use “Google” + Email address. Google does not let users change their email address so this value is unique.
    • AuthenticationType.Facebook: We use “Facebook” + ID. Facebook does allow users to change their email address. If we were to hash “Facebook” + Email address, and the user changes the email at a later time, we will not be able to resolve the identity after the change. So ID is what we need.
    • AuthenticationType.Twitter: We use “Twitter” + ID. Twitter doesn’t even provide email addresses but provides a screen name and an ID. Screen names can be changed so we can’t use them either. So ID is what we need.

    Note: Examine the FromTwitter, FromGoogle and FromFacebook methods in the AuthenticationService.cs

    To compute the hash value we use MixedAuthenticationTicket.GetHashCode:

    public string GetHashCode(string identitySecret) {    
        using (HMACSHA1 hash
                    = new HMACSHA1(Encoding.ASCII.GetBytes(identitySecret))) {
            
            return Convert.ToBase64String(
                hash.ComputeHash(Encoding.ASCII.GetBytes(
                    this.AuthenticationType.ToLowerInvariant() +
                    this.Identity.ToLowerInvariant())));
        }
    
    }
    
    

    The “identitySecret” - a hash key, we’ll configure in Web.config.

        <appSettings>
           <add key="Identity_Private_Key" value="tR3+Ty81lMeYAr/Fid0kMTYa/WM=" />
        </appSettings>
    

    Token & Secret

    This is where we store the latest access token and token secret that were issued by the provider. And in the case of AuthenticationType.Principal, we store the hashed password and the password hash key (salt).

    Principal

    An ID of the Principal object to resolve to.

    Putting it Together

    The new sign up page:

    [HttpPost]
    public ActionResult Signup(Signup model, string returnUrl) {
         if (!ModelState.IsValid) {
             return View(model);
         }
         try {
             MembershipCreateStatus createStatus;         
             MixedAuthenticationTicket ticket = MembershipService.CreatePrincipal(
                 model.Email, /* We use email as our primary identity */
                 model.Email,
                 model.FullName,
                 model.Password,
                 out createStatus);
    
             if (createStatus == MembershipCreateStatus.Success) {
                 MixedAuthentication.SetAuthCookie(ticket, true, null);
                 return RedirectToAction("", "home");
             }
    
             ModelState.AddModelError("", MembershipService.ErrorCodeToString(createStatus));
             return View(model);
         } catch (Exception e) {
             ModelState.AddModelError("", e);
             return View(model);
         }
    }
    
    

    Updated sign in page:

    [HttpPost]
    public ActionResult Signin(Signin model, string returnUrl) {
        if (!ModelState.IsValid) {
            return View(model);
        }
        try {                
            if (Impersonate(MembershipService.ResolvePrincipalIdentity(
                    model.Email, 
                    model.Password), true)) {
    
                return RedirectToAction("", "home");
            }
    
            ModelState.AddModelError("", "Email address or Password is incorrect.");
            return View(model);
        } catch (Exception e) {
            ModelState.AddModelError("", e);
            return View(model);
        }
    }
    
    public MixedAuthenticationTicket ResolvePrincipalIdentity(string identity, string password) {            
        MixedAuthenticationTicket ticket 
            = new MixedAuthenticationTicket("Principal", identity.ToLowerInvariant(), 
                String.Empty, 
                Guid.Empty,
                String.Empty);
        
        using (Session session = _Global.CreateSession()) {
            string identityCode 
                = ticket.GetHashCode(ConfigurationManager.AppSettings["Identity_Private_Key"]);
    
            Identity identityRecord = session.FindObject<Identity>(
                new BinaryOperator(
                        "Hash",
                        identityCode)
                );
            
            if (identityRecord == null) {
                return MixedAuthenticationTicket.Empty;
            }
    
            string encodedPassword = HMACSHA1(password, identityRecord.Secret);
            if (!encodedPassword.Equals(identityRecord.Token)) {
                return MixedAuthenticationTicket.Empty;
            }
    
            ticket.Principal = identityRecord.Principal;
            return ticket;
    
        }
    }
    

    For our own (Principal) authentication everything is straightforward and simple. For federated authentication it’s tricky. What should we do when someone signs in for example using Facebook for the first time? Should we auto create the identity and principal? Should we auto create the identity, redirect to the “confirm account” page and only than create the principal? Or should we keep the credentials in the cookie and only create persistent records when the user confirms the account?. My preference is toward option #2 for the following reasons:

    • Storing tokens (or any sensitive information) on the client side is not a good practice (even if we encrypt ticket cookie). And we need to keep track of the issued tokens so we have performs actions on user’s behalf.
    • The sign-in identity is unique (and will remain that way) and we’re going to persist it at some point anyway. So why not create it right away? (right after we acquired the token). You can put an expiration timestamp on auto created identities and GC them periodically.
    • Auto-creating principals without user’s confirmation is also not an option. What if one has an account already and wants to associate this *new* login with that *existing* account.

    in other words:

    public MixedAuthenticationTicket ResolveFederatedIdentity(
        MixedAuthenticationTicket ticket, IToken accessToken) {
    
        if (!ticket.IsAuthenticated) { return MixedAuthenticationTicket.Empty; }
       
        using (Session session = _Global.CreateSession()) {
            session.BeginTransaction();
            DateTime utcNow = DateTime.UtcNow;
            string identityCode 
                = ticket.GetHashCode(ConfigurationManager.AppSettings["Identity_Private_Key"]);
            Identity identityRecord = session.FindObject<Identity>(
                new BinaryOperator(
                        "Hash",
                        identityCode)
                );
            if (identityRecord != null) {
                if (identityRecord.Token == accessToken.Value
                                && identityRecord.Secret == accessToken.Secret) {
                    ticket.Principal = identityRecord.Principal;
                    return ticket;
                }
            }
            if (identityRecord == null) {
                identityRecord = new Identity(session);
                identityRecord.Created = utcNow;
                identityRecord.Hash = identityCode;
            }        
            identityRecord.Modified = utcNow;
            identityRecord.Token = accessToken.Value;
            identityRecord.Secret = accessToken.Secret;
    
            switch (ticket.AuthenticationType) {
                case "Google":
                    identityRecord.AuthenticationType = AuthenticationType.Google;
                    break;
                case "Facebook":
                    identityRecord.AuthenticationType = AuthenticationType.Facebook;
                    break;
                case "Twitter":
                    identityRecord.AuthenticationType = AuthenticationType.Twitter;
                    break;
                default:
                    throw new ArgumentException("Authentication type is not supported.", "ticket");
            }
            identityRecord.Save();
            session.CommitTransaction();
            ticket.Principal = identityRecord.Principal;
            return ticket;
        }
    }
    

    Now we need to confirm the account and create the principal:

    public MixedAuthenticationTicket ActivatePrincipal(
        MixedAuthenticationTicket ticket,
        out MembershipCreateStatus status) {
    
        status = MembershipCreateStatus.ProviderError;
        using (Session session = _Global.CreateSession()) {
            session.BeginTransaction();
            string identityCode 
                = ticket.GetHashCode(ConfigurationManager.AppSettings["Identity_Private_Key"]);        
            Identity identityRecord = session.FindObject<Identity>(
                new BinaryOperator(
                        "Hash",
                        identityCode)
                );
            if (identityRecord == null) {
                return MixedAuthenticationTicket.Empty;
            }
    
            /* Update or Create Principal */
            Principal principalRecord = null;
            if (identityRecord.Principal.HasValue 
                        && identityRecord.Principal.Value != Guid.Empty) {
                principalRecord = session.GetObjectByKey<Principal>(identityRecord.Principal.Value);
            }
            DateTime utcNow = DateTime.UtcNow;
            if (principalRecord == null) {
                principalRecord = new Principal(session);
                principalRecord.ID = Guid.NewGuid();
                principalRecord.Created = utcNow;
            }
            principalRecord.FullName = ticket.FullName;
            principalRecord.Email = ticket.Email;
            principalRecord.Modified = utcNow;
            /* Update Identity */
            identityRecord.Principal = principalRecord.ID;
            identityRecord.Modified = utcNow;
            /* Commit */
            principalRecord.Save();
            identityRecord.Save();
            session.CommitTransaction();
            status = MembershipCreateStatus.Success;
            ticket.Email = principalRecord.Email;
            ticket.Principal = principalRecord.ID;
            ticket.FullName = principalRecord.FullName;
            return ticket;
        }
    }
    

    What’s next

    Download source code for Part 4

    Cheers

    Azret

  • OData and OAuth – Part 3 - Federated logins with Twitter, Google, Facebook

         

    OAuth

    It’s time to look at OAuth protocol itself. In short, OAuth is a token based  authentication that became popular in recent years due to the adoption by big web giants like Google, Twitter, Facebook etc.

    There is a lot of good material on the web explaining the protocol flow in great details:

    http://oauth.net/about/ 

    http://hueniverse.com/oauth/ 

    http://www.viget.com/extend/oauth-by-example/

    http://dev.twitter.com/pages/auth 

     

     

    For us, it’s important because The Hobbit’s Bank Of the Shire exposes developer API and we want to make sure that any client app that is to use this API will not know the credentials of our members. And because everyone who lives in the Shire has an account on Twitter or Facebook and they would like to be able to sign into their accounts using those identities. Let’s start by adding support for federated logins: “Sign in with”

    When “signing in with”, we’ll redirect to the same Signin action on the AccountController with a parameter that tells us what service to use for authentication. Let’s start with Twitter (OAuth 1.0):

    <a href='@Url.Action("signin", "account", new { oauth_service = "tw" })' style="float:left; margin-left:10px;">
       <img style="float:left; border:0px; " src='@Url.Content("~/Content/Twitter.png")' alt="" />
    </a>
    public ActionResult Signin(Nullable<Guid> id) {    
        string service = Request.QueryString.Get("oauth_service");
        
        if (String.Equals(service, "tw", StringComparison.InvariantCultureIgnoreCase)) {
            return Redirect(
                AuthenticationService.GetAuthorizeUriForTwitter(Request.Url)
            );
        }
        
        MixedAuthenticationTicket ticket = MembershipService.CreateTicketForPrincipal(id);
        if (Impersonate(ticket, true)) {            
            return RedirectToAction("", "home");
        }
    
        return View(new Signin(MembershipService.GetPrincipals()));
    }

    AuthenticationService.GetAuthorizeUriForTwitter will make call to http://twitter.com/oauth/request_token to get the request token. Once the token is issued, it will return a URL to the http://twitter.com/oauth/authorize so the user can grant the access. (A complete OAuth flow for twitter is published here: http://dev.twitter.com/pages/auth). We’ll also need to register The Hobbit’s Bank Of the Shire with Twitter so that we are issued a Consumer Key and Consumer Secret: Twitter App Registration https://dev.twitter.com/apps/new.

    The Consumer Key and Consumer Secret is securely kept in the Web.config. Especially the Consumer Secret, as it’s used for signing the requests and only The Hobbit’s Bank Of the Shire and Twitter should know the value.

    <appSettings>
        <add key="Twitter_Consumer_Key" value="YOUR CONSUMER KEY" />
        <add key="Twitter_Consumer_Secret" value="YOUR CONSUMER SECRET" />
    </appSettings>

    Back to AuthenticationService.GetAuthorizeUriForTwitter, takes in a Uri parameter for the callback. We’ll use the same Signin action. Once redirected back, we’ll acquire an access token from twitter and sign in as that twitter user:

    public ActionResult Signin(Nullable<Guid> id) {
        string service = Request.QueryString.Get("oauth_service");
        if (String.Equals(service, "tw", StringComparison.InvariantCultureIgnoreCase)) {
            return Redirect(
                AuthenticationService.GetAuthorizeUriForTwitter(Request.Url)
            );
        }
    
        MixedAuthenticationTicket ticket = MixedAuthenticationTicket.Empty;
        string callback = Request.QueryString.Get("oauth_callback");
        if (String.Equals(callback, "tw", StringComparison.InvariantCultureIgnoreCase)) {
            ticket = AuthenticationService.FromTwitter(Request);
            if (Impersonate(ticket, true)) {
                return RedirectToAction("", "home");
            }
        }
        ticket = MembershipService.CreateTicketForPrincipal(id);
        if (Impersonate(ticket, true)) {
            return RedirectToAction("", "home");
        }
    
        return View(new Signin(MembershipService.GetPrincipals()));
    }

    image

    and we’re back on our property

    Google & Facebook

    We’ll follow the same pattern for Google and Facebook. Key difference is that Facebook uses OAuth 2.0 protocol. More here.

    public ActionResult Signin(Nullable<Guid> id) {
        string service = Request.QueryString.Get("oauth_service");
        if (String.Equals(service, "tw", StringComparison.InvariantCultureIgnoreCase)) {
            return Redirect(
                AuthenticationService.GetAuthorizeUriForTwitter(Request.Url)
            );
        } else if (String.Equals(service, "g", StringComparison.InvariantCultureIgnoreCase)) {
            return Redirect(
                AuthenticationService.GetAuthorizeUriForGoogle(Request.Url)
            );
        } else if (String.Equals(service, "fb", StringComparison.InvariantCultureIgnoreCase)) {
            return Redirect(
                AuthenticationService.GetAuthorizeUriForFacebook(Request.Url)
            );
        }
    
        MixedAuthenticationTicket ticket = MixedAuthenticationTicket.Empty;
        string callback = Request.QueryString.Get("oauth_callback");
        if (String.Equals(callback, "tw", StringComparison.InvariantCultureIgnoreCase)) {
            ticket = AuthenticationService.FromTwitter(Request);
        } else if (String.Equals(callback, "g", StringComparison.InvariantCultureIgnoreCase)) {
            ticket = AuthenticationService.FromGoogle(Request);
        } else if (String.Equals(callback, "fb", StringComparison.InvariantCultureIgnoreCase)) {
            ticket = AuthenticationService.FromFacebook(Request);
        } else {
            ticket = MembershipService.CreateTicketForPrincipal(id);
        }
    
        if (Impersonate(ticket, true)) {
            return RedirectToAction("", "home");
        }
    
        return View(new Signin(MembershipService.GetPrincipals()));
    }

    and we’re back on our property

    We now know how to do a “Sign in with”. All the Hobbits want to start using this feature right away. Unfortunately, we don’t have the ability to resolve federated identities back to our Principal object. We’ll cover this in the next post.

    Download source code for Part 3

    Cheers

    Azret

  • OData and OAuth - Part 2 – FormsAuthenticationTicket & MixedAuthentication

         

    Continuing where we left off last time, let’s take a closer look at how we do authentication. When a member signs in by clicking on his name

    we look up the Principal object and if it exists we set a cookie with the FormsAuthenticationTicket

    public ActionResult Signin(Nullable<Guid> id) {
        if (id.HasValue && id != Guid.Empty) {
            Principal p = MembershipService.GetPrincipal(id.Value);
            if (p != null) { 
                FormsAuthentication.SetAuthCookie(p.Email, true);
                return RedirectToAction("", "home");
            }
        } 
        return View(new Signin(MembershipService.GetPrincipals()));
    }

    we do this using forms authentication facilities in ASP.NET - we configured it in Web.Config  <authenticationmode="Forms" />

    For simplicity of course, we’re not using any passwords. This is The Shire after all, there is no way, for example, Gandolf would sign in as Sam Smile.

    Once the cookie set, forms authentication will create an IIdentity from which we can access the encrypted FormsAuthenticationTicket.

    and if you look closer, the only information about the user that we have is the user name IIdentity.Name. For the most part this is enough to query all the relevant information from the database. But I don’t really want to hit the DB on every single request for bits of information that does not change. Let’s just store it in the cookie.

    A common practice is to store additional bits in the FormsAuthenticationTicket.UserData. This way, what ever we store in there (First and Last names, ID, Roles etc…) will be encrypted. Our new Signin action:

    public ActionResult Signin(Nullable<Guid> id) {
        if (id.HasValue && id != Guid.Empty) {        
            MixedAuthenticationTicket ticket = new MixedAuthenticationTicket(
                        "Principal",
                        id.Value.ToString("N"),
                        String.Empty /* Email [Optional] */,
                        id  /* Principal ID */,
                        string.Empty /* Full Name [Optional] */);
            if (Impersonate(ticket, true)) {            
                return RedirectToAction("", "home");
            }
        }
        return View(new Signin(MembershipService.GetPrincipals()));
    }
    bool Impersonate(
        MixedAuthenticationTicket ticket,
        bool remember) {
        bool bOK = false;
        if (ticket.IsAuthenticated 
                && ticket.Principal.HasValue 
                && ticket.Principal.Value != Guid.Empty) {
    
            Principal p = MembershipService.GetPrincipal(ticket.Principal.Value);
            if (p != null) {
                ticket.FullName = p.FullName;
                ticket.Email = p.Email;
    
                MixedAuthentication.SetAuthCookie(ticket, remember, null);
                bOK = true;
            }
        }
        return bOK;
    }

    Now let’s make sure we read the values back from the cookie and have them available through out the lifetime of the request:   

    public class Global : System.Web.HttpApplication {
        protected void Application_AuthenticateRequest(object sender, EventArgs e) {
            MixedAuthenticationPrincipal p = HttpContext.Current.User.GetMixedPrincipal();
            if (p != null) {
                HttpContext.Current.User = p;
                Thread.CurrentPrincipal = p;
            }
        }
    }

    Our IIdentity is now:
    
    

    Let’s use the full name in the top menu:

    Before:

    if ((HttpContext.Current.User != null)  && (HttpContext.Current.User.Identity != null)
                   && HttpContext.Current.User.Identity.IsAuthenticated) {
           <div>           
               @Html.ActionLink(
                   HttpContext.Current.User.Identity.Name,
                   "", "home",
                   null,
                   null)
           </div>                                                      
    }

    After:

    if ((HttpContext.Current.User != null)  && (HttpContext.Current.User.Identity != null)
                    && HttpContext.Current.User.Identity.IsAuthenticated) {
    
            DevExpress.OAuth.Web.Authentication.MixedAuthenticationIdentity identity
                = HttpContext.Current.User.Identity as DevExpress.OAuth.Web.Authentication.MixedAuthenticationIdentity;
            <div>            
                @Html.ActionLink(
                    identity != null && !string.IsNullOrEmpty(identity.FullName) ? identity.FullName :
                                 HttpContext.Current.User.Identity.Name,
                    "", "home",
                    null,
                    null)
            </div>                                                        
    }

    The API

    MixedIdentity is sorted so let’s go back to our OData service and make sure we only expose things that a member is authorized to see. So if previously, a call to get Principals would list everyone, we now want to make sure that only the Principal for the authenticated user is listed. Same for Valuables.

    [ConnectionString("BankOfShire")]
    public class OData : XpoDataService {
        public static void InitializeService(DataServiceConfiguration config) {
            config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
            config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
        }
    
        protected override void RegisterEntities() {
            RegisterEntity(typeof(Principal), "Principal", null, new String[] {} );
            RegisterEntity(typeof(Valuable), "Valuables", null, new String[] {} );
        }
    
        [QueryInterceptor("Principal")]
        public Expression<Func<Principal, bool>> AuthorizedPrincipals() {
            if (!HttpContext.Current.Request.IsAuthenticated) {
                return (principal) => false;
            }
            MixedAuthenticationIdentity identity = HttpContext.Current.User.Identity as MixedAuthenticationIdentity;
            if (identity == null
                                || !identity.Principal.HasValue) {
                return (principal) => false;
            }
            return (principal) => principal.ID == identity.Principal.Value;
        }
    
        [QueryInterceptor("Valuables")]
        public Expression<Func<Valuable, bool>> AuthorizedValuable() {
            if (!HttpContext.Current.Request.IsAuthenticated) {
                return (valuable) => false;
            }
            MixedAuthenticationIdentity identity = HttpContext.Current.User.Identity as MixedAuthenticationIdentity;
            if (identity == null
                                || !identity.Principal.HasValue) {
                return (valuable) => false;
            }
            return (valuable) => valuable.Owner == identity.Principal.Value;
        }
    }

    Now if we are to sign in and make a request (from the same browser)

    http://localhost:65099/data/api/odata.svc/principal

    we will only see data that belongs to the signed-in user:

    <?xml version="1.0" encoding="utf-8" standalone="yes" ?> 
     <feed xml:base="http://localhost:65099/data/api/OData.svc/" 
                xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
                xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
                xmlns="http://www.w3.org/2005/Atom">
      <title type="text">principal</title> 
      <id>http://localhost:65099/data/api/odata.svc/principal</id> 
      <updated>2011-02-25T02:13:58Z</updated> 
      <link rel="self" title="principal" href="principal" /> 
     <entry>
      <id>http://localhost:65099/data/api/OData.svc/Principal(guid'4306ffae-a80e-419d-823d-5a7cd2986bfa')</id> 
      <title type="text" /> 
      <updated>2011-02-25T02:13:58Z</updated> 
     <author>
      <name /> 
      </author>
      <link rel="edit" title="Principal" 
        href="Principal(guid'4306ffae-a80e-419d-823d-5a7cd2986bfa')" /> 
      <category term="BankOfShire.Data.Principal" 
            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
     <content type="application/xml">
     <m:properties>
      <d:ID m:type="Edm.Guid">4306ffae-a80e-419d-823d-5a7cd2986bfa</d:ID> 
      <d:FullName>Frodo</d:FullName> 
      <d:Picture m:type="Edm.Binary">iVBORo4mhUxtrHo31PdvRcaV2xEN4yc62DjZedjYvlak...</d:Picture>
      <d:Email>Frodo@TheShire.com</d:Email> 
      <d:Created m:type="Edm.DateTime">2011-02-25T01:52:08</d:Created> 
      <d:Modified m:type="Edm.DateTime">2011-02-25T01:52:08</d:Modified> 
      </m:properties>
      </content>
      </entry>
    </feed>
    

    SQL statement that XPO sent to MySql:

    SELECT N0.`ID`,N0.`FULLNAME`,N0.`PICTURE`,N0.`EMAIL`,N0.`CREATED`,N0.`MODIFIED` 
    FROM `PRINCIPALS` N0
    WHERE (N0.`ID` = ?P0) ' WITH PARAMETERS {4306FFAE-A80E-419D-823D-5A7CD2986BFA}

    Tips & Tricks

    If you look at the Principal object, you’ll see that we store member picture as row bytes. This is not really useful, for the consumers of our API. The XPO Data Service Provider let’s you handle this situation using special Hidden and Visible attributes:

    [Persistent("Principals")]
    public class Principal : XPLiteObject {
        [Key(AutoGenerate = true)]
        public Guid ID { get; set; }
        [NonPersistent]
        [Visible]
        public string PictureUri {
            get {
                WebOperationContext ctx = WebOperationContext.Current;
                if (ctx != null) {
                    Uri baseUri = ctx.IncomingRequest.UriTemplateMatch.BaseUri;
                    return String.Format("{0}://{1}:{2}/account/picture?id={3}",
                        baseUri.Scheme,
                        baseUri.Host,
                        baseUri.Port,
                        ID.ToString("D"));
                } 
                return String.Empty; 
            }
            set { /* NOP */ }
        }
    }

    What’s Next

    Download source code for Part 2

    Cheers

    Azret

  • OData and OAuth - Part 1 – Introduction

         

    I often receive questions about OData and authentication. Specifically, about OData + OAuth. The scenarios are very simple, you have a site/service and you want to provide developer API so that third-parties can integrate. The API must of course be secure, callers must properly be authenticated and only authorized resources/data must be available.

    Before we start going into details,  let’s build a sample site just so we have some context.

    image

    Our site we’ll be a front-end for the Hobbit's Bank Of The Shire Smile and we’ll use:

    The Site

    image

    The site would let members sing-in by presenting a list of all members, and a member would than click on himself to sign-in.

    image

    Members will be stored in the Principals table and represented by the XPO object Principal:

    [Persistent("Principals")]
    public class Principal : XPLiteObject {
        public Principal() { }
        public Principal(Session session) : base(session) { }
    
        [Key(AutoGenerate = true)]
        public Guid ID { get; set; }
    
        [Size(128)]
        public string FullName { get; set; }
    
        public byte[] Picture { get; set; }
        
        [Size(128)]
        [Indexed(Unique=true)]
        public string Email { get; set; }
        
        public DateTime Created { get; set; }
        public DateTime Modified { get; set; }
    }

    Once signed-in, a member would be able to see all the valuables in his safety-deposit box:

    image

    Valuables will be stored in the Valuables table and represented by XPO object Valuable:

    [Persistent("Valuables")]
    public class Valuable : XPLiteObject {
        public Valuable() { }
        public Valuable(Session session) : base(session) { }
        
        [Key(AutoGenerate = true)]
        public Guid ID { get; set; }
    
        [Size(128)]
        public string Name { get; set; }
    
        [Indexed(Unique=false)]
        public Guid Owner { get; set; }
    }

    The API

    Our data will be exposed using WCF Data Services using the XPO Data Service Provider:

    [ConnectionString("BankOfShire")]
    public class OData : XpoDataService {
        public static void InitializeService(DataServiceConfiguration config) {
            config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
            config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
        }
    }

    Web.config

      <connectionStrings>
        <add name="BankOfShire" 
             connectionString="XpoProvider=MySql;Server=localhost;Database=BankOfShire;Uid=root;Pwd=password;" />
      </connectionStrings>
    
    
    XPO Data Service Provider lives in DevExpress.Xpo.v10.2.Data.Services so we’ll to reference that. And because we are using MySQL we’ll need:

    We can now make some OData calls from the browser:

    image

    Now that the foundation is laid in here is what to expect from this series:

    Download the source code for Part 1

    Cheers
    Azret

  • Genetic Algorithms, Traveling Salesman and Charts

         

    I have came across my really old Genetic Algorithm code and thought I’d share it with you. The easiest way to understand GA is to think of it as a search function, a search for a way to get to a solution. Imagine you have a problem and you know the solution to it, but you don’t know how to get to that solution.

    Genetic Algorithms have many applications; designing circuit boards, code breaking, finding the best route to travel etc... The traveling problem is, I guess, the easiest to define and is the most common application of GA.

    Travelling Salesman Problem (TSP) is defined as follows: A salesman has to visit N number cities and the order in which he visits them is such that the total distance traveled is the minimum.

    At the first glance, this is easy to solve. There are N! number of possible combinations, we can just go through them and find the best.

    • 3 cities = 3! = 6 combinations
    • 4 cities = 4! = 24
    • 11 cities = 11! = 39 916 800
    • 12 cities = 12! = 479 001 600
    • 21 cities = 21! = 5.10909422 × 1019

    If you have a CPU capable of analyzing one billion (1,000,000,000) combinations per second, analyzing 21! combinations would take you 21! / 86,400 (1 day = 86 400 seconds) = 5.91330349 × 1014 days. That’s a lot of days my friends. We can surely use GA to get it done :)

    Traveling Salesman Problem

    Download the source from http://machine.codeplex.com/ (requires XtraCharts to compile)

    Let me know if you have any questions about Genetic Algorithms.

    Cheers

    Azret

Next page »
More from DevExpress
Live Chat
Have a pre-sales question?
Need assistance with your evaluation?
We are here to help.
Chat is one of the many ways you can contact members of the DevExpress Team. We are available Monday-Friday between 8:30am and 5:00pm Pacific Time.
If you need additional product information, require pre-sales assistance, or want help with your order, write to us at info@devexpress.com or call us at
+1 (818) 844-3383.