Don Wibier's Blog
  • 20th Aniversary of BASTA! in Mainz, Germany

    This week, John and I put up the booth at the 20th anniversary conference of BASTA! in Mainz, Germany.

    image

    Oliver has a fully booked workshop, and both of us will speak as well.

    We will do our daily raffles where you could win a Bluetooth speaker, a drone or even a platform subscription of choice.

    If you’re at BASTA!, come by and get your raffle ticket and tell us what you’re building with DevExpress!

  • This week DevExpress is in Stockholm, Sweden

    From Monday, September 18th and Tuesday, September 19th, DevIntersection Europe is happening in Stockholm, Sweden. This time it is all about the .NET Core v2 launch.

    image

    DevExpress is proud to be partner and John and I are available on location to hand out goodies and give some nice demo’s and answer questions.

    The speaker line-up as really good and I’m proud to present a session myself.

    If you’re at DevIntersection Europe, come by and say ‘hi’!

  • Webinar: Bootstrapping your Web App with DevExpress

    This week I presented the webinar about our DevExpress Bootstrap Controls. You can rewatch it on our YouTube channel.

    image

    I took an existing third party Bootstrap design from startbootstrap.com and showed how easy it is to incoprorate the DevExpress Bootstrap Controls in the design.

    If you want to use this approach in your own application, make sure to take a Bootstrap v3 theme!

    The DevExpress controls will render Bootstrap v3 compliant HTML since Bootstrap v4 is still in Beta.

    If you want to play around with the app I created, feel free to clone or fork the project from GitHub at: https://github.com/donwibier/DXBootstrap

    Did you  create a Bootstrap based Web App with the DevExpress Bootstrap controls, let me know by replying on this post or by sending me an e-mail.

  • Microsoft Identity and XPO: A true universal storage provider for more than a dozen different databases

    Shortly after Microsoft introduced their Identity system as a replacement for the ASP.NET Membership API, there was some documentation published about it's architecture and a nice sample showed up at the Microsoft web-site on how to use MySQL instead of MS SQL Server to store the information by creating a custom storage provider.

    I immediately though about creating something similar based with our own great ORM tool eXpress Persistent Objects (XPO).

    One of the big advantages of XPO is that it supports more than a dozen database back-ends out of the box like: Advantage, SQL Anywhere, Sybase, DB2, Interbase/Firebird, MS-Access, Oracle, Pervasive, PostgreSQL, SQLite, VistaDB and yes; MS SQL Server and MySQL!

    You can read more about the supported DB systems and their versions here.

    I started this little project quite some time ago, but only recently had some time to finish it off and share it with you.

    A quick overview on the architecture and what needs to be implemented

    As I mentioned before, the documentation about ASP.NET Identity is well done and you can read all about it here, so I will not dive too deep into that.

    To understand which parts of the architecture of Identity are being handled by the XPO based storage provider, you can take a look at the following diagram which describes the global architecture of Identity:

    ASP.NET Application Your project
    Managers UserManager, RoleManager etc.
    Stores UserStore, RoleStore etc.
    Data Access Layer XPO
    Data Source Database

    As you can see, the Data Access Layer will be implemented with XPO, and we need to create Store and Manager classes to facilitate the XPO based data layer.

    The last step is to make a couple of smaller changes in your project's ~/App_Start/IdentityConfig.cs file to instantiate the correct Manager objects for you application.

    Some goals I want to achieve

    There are a couple of things I want to achieve with this package.

    Easy to get

    The end-result for me would be that the changes you need to make to your project should be as little as possible, and I want this all being packed up in a NuGet package, so the storage provider can be easily included in your project.

    This last point raises a question: "This Nuget package will be released on NuGet, but XPO is neither open-source nor free, but it is available for all of our paying customers. How do we solve this?"

    Fortunately, that is (since a couple of months) fairly simple: Remember this blogpost about the DevExpress NuGet feed?

    This means that if you have configured the DevExpress NuGet feed in Visual Studio or in the NuGet.targets file of your solution, this Storage Provider package can have a dependency to the DevExpress.Xpo package.

    Easy to setup

    I want this to be setup as easy as possible. This means that even if you want to include it in a project which doesn't use XPO, you should not be bothered with the initialization of XPO. Also if you do use XPO, it should not get in your way.

    This means there is a small package as a dependency which contains some generic helper code for XPO which I use through-out projects. If you think this is convenient, feel free to use it as well.

    What needs to be done?

    It all starts with a small data model which will be represented by the XPO classes in this project. Below, there is a schematic overview of this model:

    This model is pretty much the same as what is being used in the Entity Framework storage provider where I would like to point out one interesting detail; all the persistent classes descend from the XpoDxBase class. Besides the fact that all descendants will have an Id, AddStampUTC and ModStampUTC field, there is another reason for this. It will become clear later in this post.

    A quick look at the original provider

    Let's create a new project with individual authentication in Visual Studio.

    NewProject

    If we now take a look at ~/App_Start/IdentityConfig.cs, there is the ApplicationUserManager class being generated which descends from a generic base class UserManager<ApplicationUser>.

        
    public class ApplicationUserManager : UserManager<ApplicationUser>
    {
        public ApplicationUserManager(IUserStore<ApplicationUser> store)
            : base(store)
        {
        }
    
        // ... more code ...
    }
    

    The generic class determines which class to use to represent users in the manager. This ApplicationUser can be found in the ~/Models/IdentityModels.cs file:

       
    public class ApplicationUser : IdentityUser
    {
        public ClaimsIdentity GenerateUserIdentity(ApplicationUserManager manager)
        {
            // Note the authenticationType must match the one defined 
            // in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = manager.CreateIdentity(this, 
                        DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
            return userIdentity;
        }
    
        public Task<ClaimsIdentity> GenerateUserIdentityAsync(
            ApplicationUserManager manager)
        {
            return Task.FromResult(GenerateUserIdentity(manager));
        }
    }
    

    The same approach is used for the SignIn manager:

        
    public class ApplicationSignInManager : SignInManager<ApplicationUser, string>
    {
        public ApplicationSignInManager(ApplicationUserManager userManager, 
                IAuthenticationManager authenticationManager) :
            base(userManager, authenticationManager) { }
    
        public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
        {
            return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
        }
    
        public static ApplicationSignInManager Create(
            IdentityFactoryOptions<ApplicationSignInManager> options, 
            IOwinContext context)
        {
            return new ApplicationSignInManager(
                    context.GetUserManager<ApplicationUserManager>(), 
                    context.Authentication);
        }
    }
    

    The reason for this approach is that you can easily use your own classes in case you want to store additional account information like address or day of birth. This is something I want to incorporate in the XPO Storage provider as well.

    There is one interesting thing to notice in the ApplicationUser class; it is inherited from the IdentityUser class which in its turn is inherited from a generic IdentityUser class.

    The idea behind this is very nice, since this gives us the possibility to customize a couple of things like the type of the identity field and the types for Role, Login and Claim entities.

    In coorporation with Entity Framework, you don’t need to do a lot of additional things because these classes can be directly used in the DbContext of Entity Framework.

    We could use the same approach for XPO by following these steps, but a better way is to use the DTO design pattern which gives us more flexibility in the end.

    The DX.Data.Xpo package

    This package contains some code I use through-out different projects and it will serve as a base for the Identity Storage provider as well. Let’s go quickly through the files.

    XpoDatabase

    This class has the XPO related initialization code as described in the documentation. It also has some experimental features which are not used in the Identity Storage provider like working with different datalayers to copy data.

    The most important code in this class are some helper methods to by used in the Async methods of the storage provider.

        
    public class XpoDatabase : IDisposable
    {
    
        //... more code ...
    
        public virtual void Execute(Action<XpoDatabase, Session> work, 
                bool transactional = true, bool commit = true)
        {
            using (Session s = transactional ? GetUnitOfWork() : GetSession())
            {
                work(this, s);
                if (transactional && commit && (s is UnitOfWork))
                    ((UnitOfWork)s).CommitChanges();
            }
        }
        
        public virtual T Execute(Func<XpoDatabase, Session, T> work, 
                bool transactional = true, bool commit = true)
        {			
            T result = default(T);
            using (Session s = transactional ? GetUnitOfWork() : GetSession())
            {
                result = work(this, s);
                if (transactional && commit && (s is UnitOfWork))
                    ((UnitOfWork)s).CommitChanges();
            }
            return result;
        }
    
        //... more code ...
    
    }    
    

    XpoStore

    This generic helper class makes it easy to select a bunch of objects en perform updates on that collection.

    XpoDtoDatasource

    The XpoDtoDatasource class deals with the XPO entities and the DTO classes and serves as a (good old) ObjectDatasource implementation at the same time.

    Since the XpoDatasource class is an abstract generic class, you will need to implement it for all entities. This class relies on the XpoDatabase class.

    DX.Data.Xpo.Identity

    This is what the blogpost is all about, the universal storage provider for Identity.

    The project is setup quite straightforward. There are a number of DTO classes which are inherited from the Identy classes, but implement an interface to support the DTO mechanism built in the DX.Data.Xpo project.

    The DTO classes are prefixed with XP like shown in the image below:

    image

    The structure of these files are pretty much the same, there is a generic class which allows us to fine-tune certain things like key type and some other type depending on the class.

    If we take a look at the XPIdentityRole.cs file, there is the generic class:

    public abstract class XPIdentityRole<TKey, TXPORole> : 
        XpoDtoBaseEntity<TKey, TXPORole>, IRole<TKey>, IDxRole<TKey>
        where TKey : IEquatable<TKey>
        where TXPORole : XPBaseObject, IDxRole<TKey>
    {
        public XPIdentityRole(TXPORole source, int loadingFlags) :
                base(source, loadingFlags)
        {
            Users = new List<IDxUser<TKey>>();
        }
    
        public XPIdentityRole(TXPORole source) :
                this(source, 0)
        {
    
        }
        public XPIdentityRole() :
                this(null, 0)
        {
    
        }
    
        public virtual ICollection<IDxUser<TKey>> Users { get; protected set; }
        public virtual IList UsersList { get { return Users.ToList(); } }
    
        public override TKey Key { get { return Id; } }
        public TKey Id { get; set; }
        public string Name { get; set; }
    
        public override void Assign(object source, int loadingFlags)
        {
            var src = CastSource(source);
            if (src != null)
            {
                this.Id = src.Key;
                this.Name = src.Name;
            }
        }
    }    
    

    And for easy and standard use, there is the non-generic class:

    public class XPIdentityRole : XPIdentityRole<string, XpoDxRole>
    {
        public XPIdentityRole(XpoDxRole source) : 
                base(source)
        {
        }
        public XPIdentityRole(XpoDxRole source, int loadingFlags) :
                base(source, loadingFlags)
        {
        }
        public XPIdentityRole()
        {
        }
    }
    

    Instead of doing the Assign implementation manually, we could use something like Automapper instead, but I like to have the full control here.

    The UserStore and RoleStore

    With all the preparations described earlier, the actual implementation of the stores for the Storage provider is pretty straightforward. Again, I've created a full generic class which implements all the Identity interfaces including Claims and Logins support. Next there is a more simplyfied generic class, which only has the generic types which are going to be used in the ~/App_Start/IdentityConfig.cs of your project.

    Below is the code for the RoleStore which also shows how to deal with the Async methods by using the code from the DX.Data.Xpo library.

    public class XPRoleStore<TKey, TRole, TXPORole> : XpoStore<TXPORole, TKey>,
        IQueryableRoleStore<TRole, TKey>
        where TKey : IEquatable<TKey>
        where TRole : XPIdentityRole<TKey, TXPORole>, IRole<TKey>
        where TXPORole : XPBaseObject, IDxRole<TKey>, IRole<TKey>
    {
        public XPRoleStore() : 
            base() {  }
        public XPRoleStore(string connectionName) : 
            base(connectionName) { }
        public XPRoleStore(string connectionString, string connectionName) : 
            base(connectionString, connectionName) { }
        public XPRoleStore(XpoDatabase database) : 
            base(database) { }
    
        #region Generic Helper methods and members
    
        protected static Type XPORoleType { get { return typeof(TXPORole); } }
        protected static TXPORole XPOCreateRole(Session s) 
        { 
            return Activator.CreateInstance(typeof(TXPORole), s) as TXPORole; 
        }
    
        #endregion
    
        public IQueryable<TRole> Roles
        {
            get
            {
                XPQuery<TXPORole> q = new XPQuery<TXPORole>(GetSession());
                var result = 
                    from u in q
                    select Activator.CreateInstance(typeof(TRole), u as TXPORole) as TRole;
                return result;
            }
        }
    
        public Task CreateAsync(TRole role)
        {
            ThrowIfDisposed();
            if (role == null)
                throw new ArgumentNullException("role");
    
            return Task.FromResult(XPOExecute<object>((db, wrk) =>
            {
                var xpoRole = XPOCreateRole(wrk);
                xpoRole.Assign(role, 0);
    
                return null;
            }));
        }
    
        public Task DeleteAsync(TRole role)
        {
            ThrowIfDisposed();
            if (role == null)
                throw new ArgumentNullException("role");
    
            return Task.FromResult(XPOExecute<object>((db, wrk) =>
            {
                wrk.Delete(wrk.FindObject(XPORoleType, 
                        CriteriaOperator.Parse($"{KeyField} == ?", role.Id)));
                return null;
            }));
        }
    
        public Task<TRole> FindByIdAsync(TKey roleId)
        {
            ThrowIfDisposed();
    
            return Task.FromResult(XPOExecute((db, wrk) =>
            {
                var xpoRole = wrk.FindObject(XPORoleType, 
                        CriteriaOperator.Parse($"{KeyField} == ?", roleId));
                return xpoRole == null ? 
                        null : 
                        Activator.CreateInstance(typeof(TRole), xpoRole, 0) as TRole;
            }));
    
        }
    
        public Task<TRole> FindByIdAsync(string roleId)
        {
            ThrowIfDisposed();
    
            return Task.FromResult(XPOExecute((db, wrk) =>
            {
                var xpoRole = wrk.FindObject(XPORoleType, 
                        CriteriaOperator.Parse($"{KeyField} == ?", roleId));
                return xpoRole == null ? 
                        null : 
                        Activator.CreateInstance(typeof(TRole), xpoRole, 0) as TRole;
            }));
        }
    
        public Task<TRole> FindByNameAsync(string roleName)
        {
            ThrowIfDisposed();
            if (String.IsNullOrEmpty(roleName))
                throw new ArgumentException("roleName is null or empty");
    
            return Task.FromResult(XPOExecute((db, wrk) =>
            {
                var xpoRole = wrk.FindObject(XPORoleType, 
                        CriteriaOperator.Parse("NameUpper == ?",
                                                    roleName.ToUpperInvariant()));
                return xpoRole == null ? 
                        null : 
                        Activator.CreateInstance(typeof(TRole), xpoRole, 0) as TRole;
            }));
    
        }
    
        public Task UpdateAsync(TRole role)
        {
            ThrowIfDisposed();
            if (role == null)
                throw new ArgumentNullException("roleName");
    
            return Task.FromResult(XPOExecute<object>((db, wrk) =>
            {
                TXPORole r = wrk.FindObject(XPORoleType, 
                                CriteriaOperator.Parse($"{KeyField} == ?", 
                                                        role.Id)) as TXPORole;
                if (r != null)
                {
                    r.Assign(role, 0);
                }
                return null;
            }));
        }
    }
    

    The second less generic class can look as simple as below:

    public class XPRoleStore<TRole, TXPORole> : DxRoleStore<string, TRole, TXPORole>
        where TRole : XPIdentityRole<string, TXPORole>, IRole<string>
        where TXPORole : XPBaseObject, IDxRole<string>, IRole<string>
    {
        public XPRoleStore() : 
            base() { }
        public XPRoleStore(string connectionName) : 
            base(connectionName) { }
        public XPRoleStore(string connectionString, string connectionName) : 
            base(connectionString, connectionName) { }
        public XPRoleStore(XpoDatabase database) : 
            base(database) { }
    }
    

    For the UserStore, there is a bit more code involved. You can check that out by cloning or forking the project. Once you go through the code, you'll see that the approach is quite the same as the RoleStore.

    How to use this in your own WebApp

    I have mentioned a couple of directions on where to change things after you've completed the project template. Let's summarize the steps below:

    • First make sure you have your personal DevExpress NuGet feed configured as described here
    • Next, we can add the DX.Data.Xpo.Indentity package
    • Now there are a couple of things we need to change in code:
      • In ~/App_Start/IdentityConfig.cs and ~/Models/IdentityConfig.cs we need to replace:

        using Microsoft.AspNet.Identity.EntityFramework;

        with

        using DX.Data.Xpo.Identity;
              
      • Now we also need to change some code in the ApplicationUser which is located in ~/Models/IdentityConfig.cs. Replace the class with:
        	
        public class ApplicationUser : XPIdentityUser<string, XpoApplicationUser>
        {
            
            // don't forget the constructors !!!
            public ApplicationUser(XpoApplicationUser source) : 
                base(source)
            {
            }
        
            public ApplicationUser(XpoApplicationUser source, int loadingFlags) : 
                base(source, loadingFlags)
            {
            }
        
            public ApplicationUser() :
                base()
            {
            }
        
            public override void Assign(object source, int loadingFlags)
            {
                base.Assign(source, loadingFlags);
                //XpoApplicationUser src = source as XpoApplicationUser;
                //if (src != null)
                //{
                //	// additional properties here
                //	this.PropertyA = src.PropertyA;
                //	// etc.				
                //}
            }
            public ClaimsIdentity GenerateUserIdentity(ApplicationUserManager manager)
            {
                // Note the authenticationType must match the one defined in 
                // CookieAuthenticationOptions.AuthenticationType
                var userIdentity = manager.CreateIdentity(this, 
                                    DefaultAuthenticationTypes.ApplicationCookie);
                // Add custom user claims here
                return userIdentity;
            }
        
            public Task<ClaimsIdentity> GenerateUserIdentityAsync(
                    ApplicationUserManager manager)
            {
                return Task.FromResult(GenerateUserIdentity(manager));
            }
        }          
              
      • Since the ApplicationUser is a DTO class, we also need to add the persistent counterpart. This is the class which will be stored in the database by XPO. You can add it to the ~/Models/IdentityConfig.cs.
        	
        // This class will be persisted in the database by XPO
        // It should have the same properties as the ApplicationUser
        [MapInheritance(MapInheritanceType.ParentTable)]
        public class XpoApplicationUser : XpoDxUser
        {
            public XpoApplicationUser(Session session) : base(session)
            {
            }
            public override void Assign(object source, int loadingFlags)
            {
                base.Assign(source, loadingFlags);
                //ApplicationUser src = source as ApplicationUser;
                //if (src != null)
                //{
                //	// additional properties here
                //	this.PropertyA = src.PropertyA;
                //	// etc.				
                //}
            }
        }            
                
      • Next we need to initialize the ApplicationUserManager by using the XPUserStore. Because of the generic setup, we can easily specify the XPO persistent class together with the DTO class:
             
        public class ApplicationUserManager : UserManager<ApplicationUser>
        {
            public ApplicationUserManager(IUserStore<ApplicationUser> store)
                : base(store)
            {
            }
        
            public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
            {
                var manager = new ApplicationUserManager(
                        new XPUserStore<ApplicationUser, XpoApplicationUser>(context.Get<XpoDatabase>()));
        
                // ... 
            }
             
            // ...
        }
              
      • And the last thing we need to change is the ApplicationDbContex class. It is also in ~/Models/IdentityConfig.cs. In XPO there is no DBContext class so:
        	
        public class ApplicationDbContext 
        {
            public static DX.Data.Xpo.XpoDatabase Create()
            {
                return new DX.Data.Xpo.XpoDatabase("DefaultConnection");
            }
        }
              
    • And finally we can remove the Microsoft.AspNet.Identity.EntityFramework NuGet package as well as the EntityFramework package from the project.

      image

    Getting the packages and source

    The NuGet packages are already available on NuGet.org so you can just add them to your project.
    Do note that building your project does not work if you don't have your personal DevExpress NuGet feed configured!

    If you want to check out all of the code, feel free to fork or clone the repo from my GitHub account at: https://github.com/donwibier/DXWeb. This code is free to use and you can contact me by replying on this blog post. You can even do a pull-request in case you found something in my code.

    Let me know if this is interesting and/or usefull for you.

  • Impressions of DeveloperWeek Nuremberg 2017

    Last week, John and I put up our booth at the DeveloperWeek Nuremberg, Germany.

    It was nice to see a lot of existing customers as well as people who were looking for WPF controls as well as JavaScript / Angular controls and I was able to show our React DataGrid to a number of React developers.

    Below is an impression of Developerweek Nuremberg 2017:

     

    Check here to see if we will be at a conference near you!

  • This week we’re at DeveloperWeek Nuremberg, Germany

    From Monday June 26th until June 28th, John and I are in Nuremberg, Germany for DeveloperWeek. I will have a session about our own TestCafe product and we will be showing all the cool features of our v17.1 release.

    Developerweek2017

    We will be handing out nice goodies and raffle tickets. There will be a daily raffle where you could win a platform subscription of choice or a cool Bluetooth speaker.

    We hope to see you there!

  • Impressions from NDC Oslo 2017

    Last week, John drove from Frankfurt area all the way up to Oslo (while I took a flight instead), so we could put up our awesome booth at the Oslo Spektrum Arena for NDC Oslo 2017.

    The conference was really well organized with 9 parallel tracks, 3 days long!

    Both MS Channel 9 and .NET Rocks had there portable studios put up for live audio and video streaming with interviews of  speakers.

    At the attendee party there was this great 80's coverband "Loveshack" who did a great performance with all the great rock hits from Van Halen's "Jump" to Cindy Lauper's "Girls just want to have fun".

    At our booth, I have talked with existing customers but also with a lot of people who didn't hear from us before. This gave me the opportunity to demo all the cool things we have in DevExtreme, WPF and our Reporting and Dashboard solutions. Because of the promo video we have for Coderush, I got quite some questions on that subject as well.

    To see what NDC Oslo is all about, check the gallery below!


  • Meet us at NDC Oslo this week

    This week, from June 12th until June 16th 2017, NDC Oslo is taking place. With more than 170 speakers, 21 workshops and 175 sessions, you'll be absolutely sure to be completely up to date at the end of this week.



    DevExpress is proud to be a partner at one of the biggest developer conferences in Scandinavia.

    John and I will be available with our booth where we will show you everything you want to know about our v17.1 release (and other DevExpress related matters).

    Make sure you come by to get a daily raffle ticket and the DevExpress beer mug.

    See you in Oslo!

  • Techorama 2017 Impressions

    Last week, Julian, John and I where at the 4th edition of the Techorama Conference in Antwerp, Belgium.

     

    This year the conference was bigger as the previous editions, which was the reason to move from Mechelen to Antwerp.

    The speaker selection was impressive and Scott Guthrie was here to kick off with the opening keynote. After the keynote, he did a Q&A session.

     

    We talked with a lot of attendees where there was a lot of interest in DevExtreme, Angular and dotnet Core, but also our WPF controls had a fair amount of interest. We even got questions about DevExpress and React so we where proud to show our CTP of the DevExtreme React DataGrid! This grid has been developed from the ground on up to take full advantage of all the sweetness that React brings.

    Below is an impression of what Techorama was all about:

     

    We would like to thank everybody visiting us as well as the organization for putting together such a great conference!

  • We are at Techorama in Antwerp, Belgium this week

    From May 22nd till May 24th, DevExpress is proud to be silver partner of the Techorama Conference in Antwerp, Belgium.

     

    The international speaker lineup is, as always, really good where the keynote will be presented by Scott Guthrie!

    Our CTO, Julian as well as John and I will be present and ready to show and tell you everything about our latest v17.1 release.

    As usual we'll be handing out tickets for our daily raffle and cool give-aways.

    Make sure to come by and say Hi!

1
2 3 4 5 6 7 8
LIVE CHAT

Chat is one of the many ways you can contact members of the DevExpress Team.
We are available Monday-Friday between 7:30am and 4:30pm Pacific Time.

If you need additional product information, write to us at info@devexpress.com or call us at +1 (818) 844-3383

FOLLOW US

DevExpress engineers feature-complete Presentation Controls, IDE Productivity Tools, Business Application Frameworks, and Reporting Systems for Visual Studio, along with high-performance HTML JS Mobile Frameworks for developers targeting iOS, Android and Windows Phone. Whether using WPF, ASP.NET, WinForms, HTML5 or Windows 10, DevExpress tools help you build and deliver your best in the shortest time possible.

Copyright © 1998-2017 Developer Express Inc.
All trademarks or registered trademarks are property of their respective owners