Don Wibier's Blog
  • CloudProviders: Connecting the ASP.NET File Manager and Upload Control to Amazon S3 Storage (Now available in v14.2)

    What started as the preparations for a webinar ended as a really cool feature in v14.2!

    You can now manage your files on Amazon S3 Storage with the ASPxFileManager because we’ve added brand new cloud providers, and you don’t need coding for it. Let’s see how you set it up:

    Preparations on Amazon

    After signing in or signing up at http://aws.amazon.com/, the Amazon Web Services overview is being displayed. You will first need to setup a user which is allowed to access the S3 Storage Buckets. This is done by clicking the Identity & Access Management link in the Administration & Security (IAM) Section:

    In the dashboard which shows up, create a user by clicking the User menu item, and Create New Users:

    AddUser

    Enter the desired username (you are able to create several users in one go, but we will stick with one) and click Next:

    AddUser2

    Pay attention on the following screen which is only displayed once, click the hyperlink to get the users keys:

     AddUser3

    AddUser4

    Copy the indicated information to a save place because you will never see them again in Amazon!

    After storing theses keys, you have to click on the orange box to go to the Services overview from where you can go back the AIM Dashboard. Now you can create a group with S3 Policies enabled:

    AddGroup1

    Give the group some logical name and click Next Step:

    AddGroup2

    In the Set Permissions screen, scroll down in the Select Policy Template section to select the Amazon S3 Full Policy:

    AddGroup3

    On the confirmation screen, click Next Step:

    AddGroup4

    In the Group Overview, click on the group name:

    AddGroup5

    And add the user to this group:

    AddGroup6

     

    AddGroup7

    Now the security related things have been setup so you can create the S3 Bucket. Click the Orange Box in the Left Corner, and select S3:

    S3Image1

    On the Simple Storage welcome screen, click the Create Bucket button, enter the bucket name and select a region:

    S3Image3

    Connecting the ASPxFileManager to the bucket

    In Visual Studio, drop an ASPxFileManager on a page or UserControl and specify the following properties:

    Image 21

    If you start your application, you’ll notice that you can start managing your bucket straight away!

    Uploading directly with an ASPxUploadControl to the bucket

    If you only want to upload files to Amazon S3 Storage, you can drop an ASPxUploadControl on your form and specify the following properties:

    Image 22

    You might want to specify some additional properties like ShowUploadButton = true, so you don’t need any additional coding at all.

    If you prefer using Azure BlobStorage instead of Amazon S3, check here to find out how easy that is!

    UPDATE

    Click here to see the instructions and demo for WebForms and MVC on YouTube!

  • CloudProviders: Uploading files to Azure BlobStorage using the ASP.NET Upload Control (Now available in v14.2)

    Besides the cloud support in the ASPxFileManager, we’ve also added support in the ASPxUploadControl to upload files directly to Azure BlobStorage.

    Let me show you how easy it is to use this exiting new feature.

    First we need to get the access details of the Blob Container were we would like to upload to. This can be done by creating a new container or using an existing one. For exact details on how to get ready, please read the blog post about CloudProviders: Connecting the ASP.NET File Manager to Azure BlobStorage (Now available in v14.2).

    Screen5

    Once you have prepared the Blob Container you can go to Visual Studio and drop an ASPxUploadControl on your page or UserControl:

    UploadProperties

    While you’re at it, also don’t forget to check the other new features of the ASPxUploadControl like Settings.EnableDragDrop:

    UploadProps

    Finally enable the ShowUploadButton, and hit Ctrl+F5 to start uploading to Azure straight away!

    Make sure you register for the upcoming webinar at December 9th where I will tell and show you more about it.

  • CloudProviders: Connecting the ASP.NET File Manager to Azure BlobStorage (Now available in v14.2)

    What started as the preparations for a webinar ended as a really cool feature in v14.2!

    You can now manage your files on Azure BlobStorage with the ASPxFileManager because we’ve added brand new cloud providers, and you don’t need coding for it. Let’s see how you set it up:

    Preparations on Azure

    After signing in or signing up at http://azure.microsoft.com/, you can click on the Storage button on the left-side features menu

    Screen1

    Next, we need to specify a couple of details on the storage account, like the name, the data center location, subscription and replication.

    Remember the URL

    Screen2

    After the storage account has been created, we can create the actual container:

    Screen3

    Specify the name and select the optional Access restrictions:

    Remember the Name.

    Screen4

    Once the container has been created, we can copy the access key by clicking the Manage Access Keys on the bottom menu:

    Screen5

    That’s it for the preparations in Azure.

    Connecting the ASPxFileManager to the container

    After we’ve dropped an ASPxFileManager on an ASP.NET Form, we only need to specify the following properties in the Object Inspector:

    Screen6

    Don’t forget to specify the SettingsEditing properties so you can manage folders and files in the container.

    After hitting Ctrl+F5 to start up your web application, you can start making folders and upload files to the container!

    Screen7

    Did you know that you can also use the ASPxUploadControl to upload directly to Azure BlobStorage ?

    UPDATE

    Click here to watch the instructions and demo for WebForms and MVC on YouTube!

  • DevExpress Grids – Faster Sorting, Grouping and Summaries (Coming soon in v14.2)

    Besides all the new features we have been blogging about, there are also numerous improvements on existing controls and features in v14.2. While our grid controls on all platforms are famous for their speed and are recognized through the awards we keep winning, we just couldn’t resist making them even faster!

    Besides putting in some pepper here and there, we also revised our data processing code improving every single detail of it. This relates to sorting, grouping and calculating summaries, basically the most common data operations in the grid.

    image

    The actual performance increase on your application depends on a number of other factors as well but we have timed and measured extensively on a number of common scenarios and it turns out that the grids are more then 10 times faster in those cases!

    GridActiveDemo

    We did our testing on an XtraGrid, bound to 4,000,000 strongly-typed objects on an Intel® Core™ i5-2500 Processor and you will see the differences between v13.2 and v14.2 in seconds.

    image

    Because we have a common code base for the different presentation layers, these improvements are implemented on the ASPxGridView, XtraGrid, XtraVerticalGrid and DXGrid.

    What did we do?

    One of the most important changes we already did in v13.1 is dropping some legacy technologies like DXperience 13.1 will be .NET 4 or above, and the discontinuation of support for .NET Client Profile. These technical decisions allowed us to use powerful and effective C# features which we couldn’t use before. We actually started making changes in v14.1 but didn’t mention this because we were not finished with the entire plan. This does explain why our comparison tests are between v13.2 and v14.2 to give you a good overview.

    Conclusion

    I you didn’t try our v14.2 beta, please download and test it and tell us what you think!

    Stay tuned for more exciting v14.2 news

  • Source code of the ASP.NET Blog Engine available on GitHub

    After some valuable feedback, I have put the source code of the ASP.NET blog engine which I created in the 3 story webinar on GitHub.

    You can clone it from within VisualStudio by going to the Team Explorer, at Local Git Repositories click New and enter the repo URL:

    https://github.com/donwibier/XPressMe.git

    When you next have selected a local folder and click Clone, the source will be retrieved.

    Image 002

    (Make sure you have the Git tools installed in VisualStudio for this)

    If you want to get it from the command line, enter the following command in the Git Bash Shell:

    $ git clone https://github.com/donwibier/XPressMe.git C:/Projects/GitHub/XPressMe

    After opening the solution in VisualStudio, you might get a message to convert the solution to the DevExpress version you’ve installed on your machine. If not, convert it using the DevExpress / Project Converter Menu item.

    Image 003

    There will be a webinar coming up at January 13th where I will show you how to rebuild this tool with our MVC extensions!

  • Best practices: Secure ASP.NET Web with DevExpress: A2 - Broken Authentication and Session Management

    I’ve had a lot of experience in dealing with writing secure ASP.NET websites. I’ve created a custom CMS framework using DevExpress ASP.NET and been through several security audits with this project. I’d like to share my experience with you in using best practices to make your websites secure. In this series of blog posts, I'll explain common web security topics and how you can make sure your websites are secure.

    Open Web Application Security Project

    OWASP is one of the most well-known organizations which focuses on improving security of software. They have published a checklist with common design errors and issues. The OWASP Top Ten represents a broad consensus about what the most critical web application security flaws are.

    Let’s see what this type of attack is about and how to fix it:

    A2 - Broken Authentication and Session Management

    Session variables are great for maintaining a state or keeping some personalized information at hand in a web application. These variables are stored on the server and are globally accessible throughout the application. After a certain time of inactivity of a user, they are also cleaned up automatically.

    Every user has its own instances of these variables so the data is not exposed to any other users. 

    Hackers, however, try to exploit any weakness to gain access to other user’s session data.

    Lets see how the ASP.NET framework handles this so we can see if there are ways to tamper with this.

    In general, there are roughly 3 ways to identify a session:

    • Specifying a sessionID as part of the URL or QueryString parameter with all URL’s and requests to the web-server.
    • By submitting a (hidden) FormField with some sessionID with all requests
    • Storing a sessionID in a cookie which will be send over with all requests

    By default, ASP.NET uses the last method since it has the least side affects, but for the test we will tell the ASP.NET framework to use the first method by specifying the following in the web.config of a new empty project:

    <system.web>
      <sessionState cookieless="true" />
    </system.web>

    Next we create a simple default.aspx page which looks like this:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication8.Default" %>
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
              <asp:Panel runat="server" ID="pnlAnon">
                    <fieldset>
                         <asp:Label runat="server" ID="lbUsername" AssociatedControlID="tbUsername" Text="Username" /><br />
                         <asp:TextBox runat="server" ID="tbUsername" /><br />
                         <asp:Label runat="server" ID="lbPassword" AssociatedControlID="tbPassword" Text="Password" /><br />
                         <asp:TextBox runat="server" ID="tbPassword" /><br />
                    </fieldset>
                    <asp:Button runat="server" ID="btLogin" Text="Login" OnClick="btLogin_Click" />
              </asp:Panel>
              <asp:Panel runat="server" ID="pnlLoggedIn" Visible="false">
                    <asp:Label runat="server" ID="lbWelcome" /><br />
                    <asp:Button runat="server" ID="btLogout" Text="Logout" OnClick="btLogout_Click" />
              </asp:Panel>
        </div>
        </form>
    </body>
    </html>

    With the following code-behind:

    namespace WebApplication8
    {
         public partial class Default : System.Web.UI.Page
         {
              protected void Page_Load(object sender, EventArgs e)
              {
                    if ((!IsPostBack) && (!IsCallback))
                    {
                         UpdateControls();
                    }
              }
              protected void UpdateControls()
              {
                    pnlAnon.Visible = String.IsNullOrEmpty((string)Session["Username"]);
                    pnlLoggedIn.Visible = !pnlAnon.Visible;
                    if (pnlLoggedIn.Visible)
                         lbWelcome.Text = String.Format("Welcome {0}!", Session["Username"]);
    
              }
              protected void btLogin_Click(object sender, EventArgs e)
              {
                    Session["Username"] = tbUsername.Text;
                    UpdateControls();
                    Response.Redirect("~/");
              }
    
              protected void btLogout_Click(object sender, EventArgs e)
              {
                    Session.Remove("Username");
                    UpdateControls();
                    Response.Redirect("~/");
              }
         }
    }

    As you can see, the code is pretty straight forward; when no session variable is present, we show the pnlAnon which allows us to enter some username and password.

    When we submit,  the entered username is placed in the session variable and the controls are updated. If you run this in your web-browser, you will see the following:

    image

    Because of the cookieless setting, you see a mangled URL being produced by the ASP.NET framework which inserts the sessionID into the URL.

    Now we fill something in and hit Login:

    image

    Lets copy the URL in Internet Explorer:

    image

    As you can see both browsers are now working in the same session.

    When removing the web.config setting, ASP.NET will store this information in a cookie named ASP.NET_SessionId and it is created if it didn’t already exists. The cookie holds the same value as the URL portion in the example above, and when you copy the cookie value from one browser to another, you will have the same effect.

    This is a potential opening for a hacker which is called Session Fixation. For this to happen a hacker needs to setup a session first and next try to trick a user to go to the site by providing a hyperlink (in a fake e-mail from your bank for example). If this succeeds, the user will work in the session of the hacker. If you want to read more about these kind of attacks, there is a good article here.

    If you have developed your own login mechanism in your site which relies on Session variables like the example above, you can imagine that this is a potential security issue.

    By using the membership API which is available in ASP.NET from version 2 and up, you have reduced these kind of threads for a great deal. The membership API gives you all functionality you would expect for handling users and logins.

    The standard configuration of the Membership API uses its own data store for persisting user details, but if you have another data store to keep your users, consider creating your own Membership provider

    public class MyMembershipProvider : MembershipProvider
    {
         public override bool ValidateUser(string username, string password)
         {
               //...
         }
         public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
         {
               //...
         }
         public override MembershipUser GetUser(string username, bool userIsOnline)
         {
               //...
         }
         public override bool ValidateUser(string username, string password)
         {
               //...
         }
         // override other methods you need
    }

    You will need to configure it in your web.config:

    <system.web>
        <membership defaultProvider="MyMembershipProvider" userIsOnlineTimeWindow="10">
          <providers>
            <clear />
            <add name="MyMembershipProvider" type="MyNamespace.MyMembershipProvider, MyAssembly" 
                    enablePasswordReset="true" requiresQuestionAndAnswer="false" applicationName="/" />
          </providers>
        </membership>

    Optionally you could create a Role provider as well and configure it accordingly.

    The membership API uses an authentication ticket which will also be stored in a cookie but it is much harder to tamper with since it holds some additional information. A nice side-effect of using the membership API is that all controls in the toolbox like the LoginControl and LoginStatus control can be used without additional coding.

    So by using the membership API, we have reduced the risk of a hacker getting your sensitive information, and we can be pretty sure about the identity of a user but we still have the Session Fixation issue. There are several counter measures you can take:

    Make sure the business logic don’t depend on Session variables and use as less as possible. In several of our demo projects, we use session variables but only for persisting some status in between callbacks and we also make sure we initialize them first before reading them.

    If the above is not possible, you could introduce an extra cookie e.g. Auth which holds a unique generated value which will also be stored in a session variable as soon as a user logs in. Next with every page load, you can check if the cookie value is equal to the session variable.

    A login method for this could look like this:

    protected void btLogin_Click(object sender, EventArgs e)
    {
          if (Membership.ValidateUser(tbUsername.Text, tbPassword.Text))
          {
               string guid = Guid.NewGuid().ToString();
               Session["Auth"] = guid;
               // now create a new cookie with this guid value
               Response.Cookies.Add(new HttpCookie("Auth", guid));
          }
          else 
               throw new HttpException("Invalid username or password")
    }

    And a logout method would look like:

    protected void btLogout_Click(object sender, EventArgs e)
    {
          Session.Clear();
          Session.Abandon();
          Session.RemoveAll();
          if (Request.Cookies["ASP.NET_SessionId"] != null)
          {
               Response.Cookies["ASP.NET_SessionId"].Value = string.Empty;
               Response.Cookies["ASP.NET_SessionId"].Expires = DateTime.Now.AddMonths(-20);
          }
    
          if (Request.Cookies["Auth"] != null)
          {
               Response.Cookies["Auth"].Value = string.Empty;
               Response.Cookies["Auth"].Expires = DateTime.Now.AddMonths(-20);
          }
    }

    In every page load you could then place the following code:

    string sessionVal = (string)Session["Auth"];
    string cookieVal = Request.Cookies["Auth"] != null ? Request.Cookies["Auth"].Value : "";
    if (!Request.IsAuthenticated || String.IsNullOrEmpty(sessionVal) || 
          String.IsNullOrEmpty(cookieVal) || (sessionVal != cookieVal))
    {
       // NOT Logged in (or tampered) redirect to the login page
    }
    //else
       //Logged in so everything is ok

    For this to work effectively, you will need to give the user some incentive to use the Logout button on your site so you can cleanup the session yourself, and empty the ASP.NET_sessionId cookie so the user will receive a new one id on his next visit to the site:

    Sessions expire after a certain amount of inactivity of the user. This time is by default 20 minutes. If possible, make it even shorter by setting the following web.config setting:

    <system.web>
      <sessionState timeout="10" />
    </system.web>

    Another way of preventing Session Fixation is by changing the sessionID with every request in the cookie. This should be tested though since this might cause problems when embedding Java Applets or ActiveX controls in your page which also rely on the user session.

    Alternatively, you could build your own SessionStateProvider.

    As you can see, protecting your data is a serious task, but also consider the following points to reduce other types of hack attempts:

    • Install an SSL certificate on your web-site and make sure at least the login process runs on SSL
    • Try to assign a new sessionID to the user upon login
    • Store passwords encrypted in the database
    • Do not use home grown authentication mechanisms
    • Keep session time-outs short
    • Do not send one e-mail which contains both username and password (it is plain text after all)

    DevExpress is Secure

    DevExpress takes ASP.NET security as a top priority. We constantly test our tools and if by chance a flaw appears then we’ll notify you immediately on a fix/workaround/etc.

    Leave a comment below with your thoughts on ASP.NET security.

  • WinForms Data Grid: Excel Inspired Conditional Formatting (Coming soon in v14.2)

    One of the many features we’ve added to our Data Grid and Tree List controls is Excel inspired conditional formatting of individual data cells. This feature allows your end-user not only to sort or group the data inside the grid, but also to visualize selected cells, rows with data bars, icons and predefined or custom appearance schemes. 

    WinForms-Grid-ExcelFormatting

    We have built-in support for the following common comparison rules:

    • Top / Bottom
    • Above / Below Average
    • Greater / Less Than
    • Value List
    • Unique / Duplicate

    You can obviously define even more (complex) conditions, in code yourself. By using the design-time facilities, you can define style conditions without writing a single line of code!

    Conditional formatting rules allow you to modify cell backgrounds, text-colors and font-settings and can be applied to either a single cell or an entire row. In case of multiple formatting conditions apply on the same cell, we’ll just combine these conditions for you (unless specified otherwise).

    We have added an extra menu item to the grid's column context menu to allow the end-user to apply the conditional formatting.

    WinForms-Grid-ExcelFormatting-GridMenu

    Stay tuned for more exiting new features in our v14.2 release!

  • Best practices: Secure ASP.NET Web with DevExpress: A1- Injection

    I’ve had a lot of experience in dealing with writing secure ASP.NET websites. I’ve created a custom CMS framework using DevExpress ASP.NET and been through several security audits with this project. I’d like to share my experience with you in using best practices to make your websites secure. In this series of blog posts I’ll write about security so you can take your advantage of it before you start to code.

    Open Web Application Security Project

    OWASP is one of the most well-known organizations which focuses on improving security of software. They have published a checklist with common design errors and issues. The OWASP Top Ten represents a broad consensus about what the most critical web application security flaws are.

    Let’s see what this type of attack is about and how to fix it:

    A1 - Injection

    This kind of attack allows a hacker to send custom server-side commands to your web-server by manipulating the url or it’s query strings, or manipulate data entered in forms which are being posted back to the server.

    Let me give you a small example on how this works on the AdventureWorks database:

    Suppose we want to display a filtered grid with products, where the filter is specified by a query string parameter:

    protected void Page_Load(object sender, EventArgs e)
    {
          if (!IsPostBack)
          {
               using (SqlConnection conn = new SqlConnection(
                        ConfigurationManager.ConnectionStrings["AdventureWorks2012ConnectionString"].ConnectionString))
               {
                    string sqlText = String.Format(@"SELECT ProductID, ProductNumber, Name 
                                                     FROM [Production].[Product] 
                                                     WHERE Name LIKE '%{0}%'", 
                                                   Request.QueryString["q"]);
                    using (SqlCommand cmd = new SqlCommand(sqlText, conn))
                    {
                          conn.Open();
                          SqlDataReader rd = cmd.ExecuteReader();
                          GridView1.DataSource = rd;
                          GridView1.DataBind();
                    }
               }
          }
    }

    This al looks pretty nice and when we specify a url like: Default.aspx?q=Crank, the result will be like:

    clip_image001

    But what if we specify:

    Default.aspx?q=Crank ' union all select 0,'',TABLE_SCHEMA%2B'.'%2BTABLE_NAME from INFORMATION_SCHEMA.TABLES –

    clip_image002

    Wow! Look at that! It displays all tables in the database and that is how an injection attack works.

    Because the constructed SQL is being generated runtime with no checking at all, I was able to change the entire sql statement by injecting some obscure code and get sensitive information about the system for subsequent hacking attempts.

    The statement was altered from:

    SELECT ProductID, ProductNumber, Name 
    FROM [Production].[Product] 
    WHERE Name like '%Crank%'

    To:

    SELECT ProductID, ProductNumber, Name FROM [Production].[Product] 
    WHERE Name like '%Crank' union all 
    select 0, '', TABLE_SCHEMA + '.' + TABLE_NAME from INFORMATION_SCHEMA.TABLES --%'

    Perhaps you’re thinking: “Yeah but I have a database with different fields, and you don’t know the amount of fields I am selecting for the union etc.”

    Those thoughts are really of no concern for a hacker. He can give it a shot by spending 30 minutes every day for a week and he will sort it out.

    Remember: Hacking is not a quick job but it requires time and patience.

    So can this be fixed ?

    Sure, this can be fixed in several ways:

    Weak solution: Remove quotes

    We could strip out all single quotes by calling:

    Request.QueryString["q"].Replace("'", "")

    But this could cause culture related issues.

    Better solution: Parameterized Queries

    protected void Page_Load(object sender, EventArgs e)
    {
          if (!IsPostBack)
          {
               using (SqlConnection conn = new SqlConnection(
                        ConfigurationManager.ConnectionStrings["AdventureWorks2012ConnectionString"].ConnectionString))
               {
                    string sqlText = "SELECT ProductID, ProductNumber, Name 
                                      FROM [Production].[Product]     
                                      WHERE Name LIKE @SearchText";                                
                    using (SqlCommand cmd = new SqlCommand(sqlText, conn))
                    {
                          cmd.Parameters.Add(new SqlParameter("@SearchText", 
                                                String.Format("%{0}%", 
                                                    Request.QueryString["q"])));
                          conn.Open();
                          SqlDataReader rd = cmd.ExecuteReader();
                          GridView1.DataSource = rd;
                          GridView1.DataBind();
                    }
               }
          }
    }

    If you would try the same trick again, you will see that nothing is found since my attempt with the union is now part of the LIKE parameter.

    An additional bonus is that you will gain a bit of performance since MS-SQL Server is now capable of caching the SQL Statement internally, so it doesn’t need to parse your statement with every request.

    Alternative better solution: Use an ORM tool

    Another way of avoiding SQL injection is by using some ORM (Object Relational Mapping) tool like the Entity Frame Work or eXpress Persistent Objects.

    Because you are not working with SQL directly the ORM tool will construct the proper queries with parameters for you.

    DevExpress is Secure

    DevExpress takes ASP.NET security as a top priority. We constantly test our tools and if by chance a flaw appears then we’ll notify you immediately on a fix/workaround/etc.

    Leave a comment below with your thoughts on ASP.NET security.

  • BASTA!2014: Recap

    Last week, Oliver, John, Rachel and I were in Mainz Germany at the BASTA!2014 Event.

    We have talked with a lot of people and we showed them demos of our tools and products.

    clip_image002

    clip_image004

    clip_image006

    The sessions Oliver and I gave were visited well

    clip_image008

    And Oliver appeared to be quite professional Quiz Master on our Mixer Party with “Who wants to be a dotNET Millionaire”. Besides the amount of fun we had, it turned out to be a hit as well!

    clip_image010

    For everybody who was at Basta!2014, I hope you enjoyed it as much as we did and for everybody who couldn’t make it, we’ll be at Microsoft TechEd in Barcelona end of October!

  • BASTA! 2014: Products, presentations, prizes ... PARTY!

    From September 22nd through to September 26th the BASTA! 2014 event will take place in Mainz, Germany and DevExpress is happy to be a Gold Partner.uisuperhero

    We’ll be present at full Euro-strength with Oliver, Rachel, John and myself attending with our awesome booth, stuffed with tons of goodies and giveaways.

    We’ll be able to show you our Winforms, ASP.NET and DevExtreme Javascript suites as well as eXpress AppFramework and more at the booth. Stop by and talk to us about what you are working on and find out if there is a way that we can help you.

    Oliver and I are also giving a number of sessions during the conference. You can check out Oliver's speaker profile and my own for more information on the sessions we'll be delivering.

    If C# development is your area of interest, it is worth bearing in mind that Oliver is the track chair for C# Days. This is a track of sessions running throughout the conference that is designed to cater for the beginner right through to the advanced C# developer looking to be more effective and successful with C#.

    As always, we'll have some exciting giveaways and raffles on the DevExpress booth. Make sure you visit us to find out how to enter. You could go home with one of our product licenses!

    If that isn’t enough, we’ll be sponsoring a games night on Tuesday evening, September 23rd.
    Oliver will be hosting an exciting edition of Who Wants to be a .NET Millionaire! We'll have food, beer, fun and some amazing prizes just waiting to be won.

    SAM_2299

    If you are not going to be at BASTA! 2014 but you do want to join us for the games night, you can join us just for the evening entertainment. Our friends at BASTA! are allowing our invited guests to join the DevExpress Games Night. All you need to do is register so that we can be sure we get enough food and drinks for everyone who joins us.

    REGISTER NOW!

    We can’t wait to meet you next week!

1 2 3 4 5 6 7
8
9
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, Delphi, HTML5 or iOS & Android development. 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-2018 Developer Express Inc.
All trademarks or registered trademarks are property of their respective owners