Pages

Showing posts with label Visual Studio 2010. Show all posts
Showing posts with label Visual Studio 2010. Show all posts

Wednesday, July 6, 2011

Handling null values with bound RadioButtonList

Sometimes when you're binding a RadioButtonList and there's a null value in one of the records, you can end up getting an exception thrown. The problem here is that it tries to select a ListItem that has the same value as the record retrieved from the database, in this case, null.

There are plenty of workarounds for this issue, including changing your query to don't retrieve nulls, or using a COALESCE instead, for example. In this post, I'll show a simple trick to handle this.


Binding to nothing

As I said, the big secret is to have a ListItem with the same value retrieved from the query. If your retrieved value is NULL, your ObjectDataSource will convert it to an empty string automatically, so you'd only need to have a ListItem with an empty string marked to be its value, like the following:

<asp:RadioButtonList runat="server" ID="radioButtonList1" SelectedValue='<%# Bind("NullableColumn") %>'>
    <asp:ListItem Text="MyEmptyStringOption" Value=""/>
    <asp:ListItem Text="MyOption1" Value="1" />
    <asp:ListItem Text="MyOption2" Value="2"/>
    <asp:ListItem Text="MyOption3" Value="3"/>                    
</asp:RadioButtonList>


By doing that, when bound, the selected option will appear as the EmptyStringOption, so we have already prevented that Exception from happening. But what would we write to the empty string option text? "None"? It makes no sense having an option that says None on the screen, right?

So let's hide it. That way, we'll always have at least one option selected, even if the return value is null, but the user will only see the options with an actual value, making it look like the RadioButtonList has no selected option at all.

If you check ListItem's attributes, you'll see that it does not have a Visible attribute, so we're going to hide it through CSS. Even if it had a Visible attribute, if we'd set it to "False", the ListItem wouldn't even be rendered, causing the exception to return to happen, as we wouldn't have an option with an empty string value.


To hide it, simply add the style attribute to it, like this:

<asp:ListItem Text="MyEmptyStringOption" Value="" style="display: none;" />


But now you'll see something else. Even if not instantly, the compiler might show you a warning message, telling you that element ListItem does not have a 'style' attribute even though it works perfectly fine. If that warning message annoys you enough to make you want to get rid of it like it does to me, remove the style attribute from the ListItem, and add it programmatically on the Page's Load event, like this:

protected void Page_Load(object sender, EventArgs e)
{
    // First find the ListItem in question, and then add the style attribute to it
    MyRadioButtonList.Items.FindByValue("").Attributes.Add("style", "display: none");
}


This will have the same effect, and it will not show you that warning...

Monday, June 20, 2011

Implementing a ModalPopupExtender

It should be easy, but as I've encountered some problems along the way, I thought I'd best blog about it.


AjaxToolkit has an extender to make it easier for us to implement a modal dialog (or a Popup) for our ASP.NET Web Forms, the ModalPopupExtender. It could be used for confirmations, when a user choses to delete something, for example. I'll demonstrate a simple Popup with two options, and two buttons.


From now on I'll assume you have AjaxToolkit controls added to your toolbox. If you don't, you can go ahead and find out how to do it here.


Poping it up


After you've added AjaxToolkit to your toolbox, add a new WebSite to your solution, and open the default page code.

First of all, let us define our Popup's style:

.ModalPopupBackground
{
    background-color: Gray;
    filter: alpha(opacity=70);
    opacity: 0.7;
}

.PopupBody
{
    border: 1px solid silver;
    padding: 5px;
    background-color: #f5f5c5;
    text-align: left;
    font-size: 15px;
    color: Gray;
}        

This will add a Gray background when the Popup is active, and our PopupBody class will be defined to be our Panel's Css Class, which will be shown inside our Popup.

We also have to register our AjaxToolkit DLL on the page, and add a ScriptManager, like this:

<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>

<ajaxToolkit:ToolkitScriptManager runat="server" ID="manager1" />



Now we can add our controls to the page. Add a button, and a label to interact with the Popup, and our ModalPopupExtender. Just remember that these controls must be inside a tag form with runat="server".


<asp:UpdatePanel runat="server">
        <ContentTemplate>
            <center>
                <asp:Button Text="Click Me" ID="btnClickMe" runat="server" />
                <br />
                <asp:Label ID="lblResult" Visible="false" Text="" runat="server" />
                <ajaxToolkit:ModalPopupExtender ID="modalPopup" runat="server" TargetControlID="btnClickMe"
                    PopupControlID="pnlPopup" OkControlID="btnHidden" CancelControlID="btnHidden"
                    BackgroundCssClass="ModalPopupBackground" DropShadow="true" />
            </center>
        </ContentTemplate>
    </asp:UpdatePanel>

I don't think I need to explain the ModalPopupExtender's properties. They're very straight-forward, and you can also find their explanation at the ASP.NET Ajax page.


One thing to note here is that we've set the OkControlID and CancelControlID to a dummy, hidden button. We do that because if we set them to the right controls, no PostBack is fired, so no code-behind is executed. It would be OK for the Cancel button though, but as I was developing this example, when I had the CancelControlID property set to the actual cancel button, after I clicked it once I had to reload the page for the Popup to be shown again. So instead, I put some JavaScript code on the Cancel's button OnClientClick event to hide the Popup. This was the simplest workaround I could think of.


And now this is our panel, which will be displayed as the Popup:

<asp:Panel runat="server" ID="pnlPopup" CssClass="PopupBody">
        <asp:RadioButtonList ID="radioList" runat="server" >
            <asp:ListItem Text="Option 1" Value="1" />
            <asp:ListItem Text="Option 2" Value="2" />
        </asp:RadioButtonList>
        
        <br />
        <center>
            <asp:Button Text="dummy" ID="btnHidden" runat="server" Style="display: none;" />
            <asp:Button Text="Ok" ID="btnOk" runat="server" style="padding-right: 10px;" 
                onclick="btnOk_Click" />
            <asp:Button Text="Cancel" ID="btnCancel" runat="server" OnClientClick="$find('modalPopup').hide();" />            
        </center>
    </asp:Panel>

As I said, the cancel button has some JavaScript to hide the Popup when it's clicked.

You can also notice that our dummy button doesn't have its visible property set to false, instead we've hidden it through style marks. We did that because if we set it to not be visible through the Visible property, it won't even be rendered, so the Popup won't find it, and won't be shown. But hidding it through style marks does the trick, and makes it work just fine. So if your Popup is not being shown, check if your dummy button has Visible = false and change it to style marks, as display: none.


To complete the trick, we add some code to handle our button OK click event:

protected void btnOk_Click(object sender, EventArgs e)
{
    lblResult.Text = string.Format("You have selected option {0}", radioList.SelectedValue);
    lblResult.Visible = true;
}


So when the Popup is shown and the Ok button is clicked, a PostBack is generated and the Click event handler code is executed and the Popup is hid. And when the Cancel button is clicked, it does nothing but hide the Popup. If you would add some code-behind to it, it would also be executed though.


And that's it, you should now have a modal Popup with two Radio Buttons as options, an OK and a Cancel button, like the images below. Once again, hope this helps...



Friday, May 6, 2011

Filtering a DataGridView

Been reading a lot of people getting confused about how to develop a filter to a DataGridView.

The easiest way to do that is to apply the filter to a BindingSource object, which will then modify the DataGridView to display the filtered result in it.

So, here's my example form design:




The only property I've changed on the designer on the DataGridView and the BindingSource is their names.
That ComboBox will let us decide which column we want to filter, with the TextBox's value. That CheckBox will indicate whether the filter is active or not.

A very easy way to implement a Live Filter

We'll implement a live filter, meaning the data will be filtered as the user types, instantly. Now, this kind of filter is pretty good for small data, small collections. Imagine instantly filtering 30000 records...

For our live filter, we'll assign each key control's event to the same handler, this way we'll have to write less code, it'll be easier.

Our DataGridView will have two columns, so here we throw in some sample data, and configure the comboBoxColumns items using an anonymous type, all inside our form's Load event:

private void FormTestGrid_Load(object sender, EventArgs e)
{
    // This prepares our data source and our grid:

    DataTable dt = new DataTable();

    DataColumn colName = new DataColumn("Name");
    DataColumn colPrice = new DataColumn("Price");

    dt.Columns.Add(colName);
    dt.Columns.Add(colPrice);

    dt.Rows.Add("Bike", 150.00);
    dt.Rows.Add("Helmet", 59.99);
    dt.Rows.Add("Shoes", 90.99);
    dt.Rows.Add("Shirt", 30.00);
    dt.Rows.Add("Blouse", 75.00);
    dt.Rows.Add("Cap", 30.00);
    dt.Rows.Add("Pants", 50.00);
    dt.Rows.Add("Glasses", 15.00);

    bindingSource.DataSource = dt;

    dataGridView.DataSource = bindingSource;

    dataGridView.Columns.Add("colName", "Name");
    dataGridView.Columns.Add("colPrice", "Price");

    dataGridView.Columns["colName"].DataPropertyName = "Name";
    dataGridView.Columns["colPrice"].DataPropertyName = "Price";


    // And this prepares our ComboBox to enable us to select what column we want to filter:

    comboColumns.DataSource =
        new[]
        {
            new { Text = "Name", Value = "Name"},
            new { Text = "Price", Value = "Price"},
        };

    comboColumns.DisplayMember = "Text";
    comboColumns.ValueMember = "Value";
}


The above code fills a DataTable and tells the BindingSource that it's its DataSource, adds the Columns to our Grid and binds them to the correct data source columns.
It also adds the items that represent our columns to the ComboBox.


Now we declare the method that will receive every control's key events:

private void FilterAction(object sender, EventArgs e)
{
}


We set our events to that handler, inside our constructor (Could also be inside our Load event):

public FormTestGrid()
{
    InitializeComponent();

    comboColumns.SelectedValueChanged += new EventHandler(FilterAction);
    txtFilter.TextChanged += new EventHandler(FilterAction);
    chkFilter.CheckedChanged += new EventHandler(FilterAction);
}

The BindingSource component has a 'Filter' property which accepts SQL-Like Syntax constraints. For more information check the MSDN documentation on it.

And now we can write the method that will actually apply the filter, FilterAction.

private void FilterAction(object sender, EventArgs e)
{
    if (chkFilter.Checked)
    {
        bindingSource.Filter = string.Format("{0} like '%{1}%'", comboColumns.SelectedValue, txtFilter.Text);                
    }
    else
    {
        bindingSource.Filter = string.Empty;
    }
}


Notice that we use 'like' instead of '=' so that it doesn't have to be the exact same value to filter, but that's just for our example, you should decide what works better for you.


So this is it, just with those few lines of code, assigning three control's events to the same handler, we can implement our live filter to our Grid.

Thursday, February 24, 2011

Capture a Custom Control Event directly on the Web Page

This is actually something simple, but as it envolves delegates and events, it might be a little confusing to those who are not too familiar with it.


When to use it

Sometimes we'll want to change our page design or some control visibility or value according to user interaction, or some other event. That's pretty straightforward when everything we need belongs to our page. However, we could be expecting this 'trigger action' to come from a defined user control. Defined user controls are a group of controls and objects, also containing .NET code in a code-behind file that we develop so that we can use it in various places throughout our application. It follows the same purpose of a method, for example. If we have some control grouping that we'll need to use somewhere else, on another page, make it a defined user control.

When do I need to interact with the page?

There are lots of examples of when you'd want to change something on the page depending on something that is in the defined control. In this case we'll focus on events.
For my example, we'll have a defined control that lets our user chose a panel's backcolor. We must implement that on multiple pages, that's why we've made a user control for it.

How?

As you may already know, you can't see your user control's controls directly from your page, so you can't assign event handlers to their events. But we can expose that event by creating a public event directly on the user defined control.

First let's create our defined control:


<asp:Label runat="server" Text="Choose a background color:" ID="lblColor" />
<asp:DropDownList ID="dropColor" runat="server" AutoPostBack="True" OnSelectedIndexChanged="dropColor_SelectedIndexChanged">
    <asp:ListItem Text="Blue" Value="#0000FF" />
    <asp:ListItem Text="Red" Value="#FF0000" />
    <asp:ListItem Text="Green" Value="#00FF00" />
    <asp:ListItem Text="Yellow" Value="#FFFF00" />
</asp:DropDownList>

Notice that we've set property AutoPostBack on our DropDownList to true. That way we'll get a postback everytime the selected value changes.

And we'll declare a public event on our defined control code-behind:

public delegate void ColorSelectedDelegate(string value);
public event ColorSelectedDelegate ColorSelected;    

protected void dropColor_SelectedIndexChanged(object sender, EventArgs e)
{
    ColorSelected(dropColor.SelectedValue);
}

That way, when the user selects a color, the SelectedIndexChanged event will trigger our public custom event ColorSelected.

Here's our page design:

<%@ Register TagPrefix="usc" TagName="color" Src="~/BackColorControl.ascx" %>

<h1>Painting Class:</h1>
<form runat="server" id="form1">
    <table>
        <tr>
            <td align="right">
                <usc:color ID="uscColor" runat="server" OnColorSelected="PaintPanel" />
            </td>
            <td align="left">
                <asp:Panel ID="pnlPaint" runat="server" Width="100px" Height="100px" BorderColor="Black" BorderWidth="2px" />
            </td>
        </tr>
    </table>
</form>

You can see that we've set property "OnColorSelected='PaintPanel'" when we declared our defined control. That adds the method PaintPanel as a handler to that event. And we're passing the value of the color selected onto our page. So all we have to do next is actually paint the panel:

protected void PaintPanel(string value)
{
    pnlPaint.BackColor = System.Drawing.Color.FromName(value);
}


So, making it simple:

We have to declare a public event on our user defined control that will somehow expose the DropDownList's selected value. When we declare the user defined control on a page, we can add handlers to public events with property "On[Event's Name]". That way, we can get our selected value on the page, and apply it elsewhere, or do whatever we want.

Tuesday, December 21, 2010

Getting started with Windows Azure

For the last couple of weeks, we've been studying converting our solution to a Windows Azure Application. So this post is gonna explain the basics of Windows Azure. Note that I did not put any payment information here. I don't even have the list of prices and I don't know what is charged and what isn't for sure.

Let's understand it.

How it works

We basically have two types of projects within a Windows Azure Application Solution: We have Web Roles, which can be Web Applications, and Worker Roles, which can be class libraries, console applications. Note that a Web Role can only be a Web Application, not a Web Site. See post "Converting a Web Site to a Web Application" for more details.

The Web Role will call the Worker Roles to do some heavy work, like background working. Something asynchronous that doesn't necessarily send a response to the Web Role, although you could have this situation. How will it call them? We have a communication pipe, a Queue. As surprising as it may be, it works exactly as a Queue object: first in, first out. The Web Role goes and puts a message in the Queue. Within a time span, the Worker Roles check the Queue for any new message, and verify whether it's assigned to them or not. If it is, they do their work, and delete the message. Simple.

To add Roles, just right click the folder Roles and select the desired option. You can also make an existing project (if compatible) a Role.
When you create a Role, you'll get a file named WebRole.cs or WorkerRole.cs, depending on which type of role you've created. These inherit from class RoleEntryPoint. These files contain methods such as OnStart(), OnStop() and Run(). You'll understand it later.

This is an image of what the Solution Explorer looks like with a Web Role and a Worker Role:


Notice that we have two configuration files: ServiceConfiguration.cscfg and ServiceDefinition.csdef. Those basically contain information about the roles and their settings.

Storage?

We have SQL Azure, Tables, and Blobs.

SQL Azure seems to go smoothly with basic instructions. It only requires that each table has a Clustered Index. Also, you can put your already existing database there, scripting it. I haven't tested it yet, but it looks like SQL Server 2008 R2 supports connecting to SQL Azure as if it was an ordinary SQL Server instance, meaning that it shows the server on Object Explorer, and lets you visually navigate through its objects. You can then script your existing database and run the scripts through Management Studio. For existing applications, connecting to it should be as simple as changing the Connection String.

Blobs. "Blobs are chunks of data". Well, they are written as byte arrays, so you could use it to store .txt, .xml files, anything. You can create a container, which would be a folder, and put blobs inside of it. For example, each customer would have their own container, and inside, their Blobs.

Tables work like an Excel Sheet, or an Access Database. Their use are to store data that is not relational. An example would be storing each customer's code and connection string.

Clouding it

First, let's configure our Roles to use development storage. I've done this with Windows Azure SDK 1.3, so I'm assuming you have that installed.

Open settings page of a role. Right click it, click properties, then go to Settings Page. You'll see the following:


Add another setting and mark the settings type as a Connection String. Then, click on the [...] button, and check Use the Windows Azure storage emulator. You can name it whatever you want to, just keep that name in mind. Let's use something generic, like "DataConnectionString". Do that for each of your roles.

After you've done that, your project now knows where's his storage, so the next step is to write to the Queue.

We're gonna write a string message that tells our Worker Role to create a Blob .txt file, and write something to it. Firstly, there's a piece of code that we need to execute before we can connect to our development storage account:

using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.ServiceRuntime;


CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
{
      // Provide the configSetter with the initial value
      configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));

      RoleEnvironment.Changed += (s, arg) =>
      {
            if (arg.Changes.OfType().Any((change) => (change.ConfigurationSettingName == configName)))
            {
                  // The corresponding configuration setting has changed, propagate the value
                  if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
                  {
                        // In this case, the change to the storage account credentials in the
                        // service configuration is significant enough that the role needs to be
                        // recycled in order to use the latest settings. (for example, the 
                        // endpoint has changed)
                        RoleEnvironment.RequestRecycle();
                   }
             }
      };
});

I couldn't find an actual answer to "Why do I need to run this?", so if you do have an answer, leave a comment with it, and I'll add it here. I'll even leave the code's original comments. If you try to get the storage account without running the code above, you'll get an exception saying that you must call the method SetConfigurationSettingPublisher before accessing it. Also, I tried putting this on the OnStart() method on WebRole.cs, and it did not work. So just put it on Application_Start() on Global.asax. As for WorkerRoles, you should put it on the OnStart() method on WorkerRole.cs.

To add our Queue Message, I've put this on a button click event:

using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;


// Gets our storage account
CloudStorageAccount storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

// Gets a reference to our Queue
CloudQueue queue = storageAccount.CreateCloudQueueClient().GetQueueReference("blobqueue");
queue.CreateIfNotExist();
queue.AddMessage(new CloudQueueMessage("TXT;This is some text to be written"));

Notice that we call the CreateIfNotExist() method. This way we can always be sure we won't get a NullReferenceException. At least not when dealing with this Queue. And the Queue name MUST be entirely lowercase! You'll get a StorageClientException with message "One of the request inputs is out of range." if you have any uppercase character in its name.
Also notice that the message is pure string, so we're gonna have to handle message parts our own way.

So when the code above executes we have our first message on the Queue. Simple, right?
Now we're gonna get that message on our WorkerRole.


On the WorkerRole.cs file I've mentioned before, check the code that was generated inside the Run() method:

public override void Run()
{
      // This is a sample worker implementation. Replace with your logic.
      Trace.WriteLine("ClassLibraryRole entry point called", "Information");

      while (true)
      {
            Thread.Sleep(10000);
            Trace.WriteLine("Working", "Information");
      }
}

Yes, it's literally that: a while(true) loop. We trap the execution there, and then we can do whatever we want, including getting messages from the Queue. We could implement some sort of "timer against counter" logic to relief the processor a bit, like, each time it checks for a message and notices there isn't any, it sets the sleep time a little bit higher. Of course we'd have to handle that so it doesn't become a huge amount of time, set a maximum on that sleep.

Now let's handle getting messages from the Queue:

while (true)
{
      CloudStorageAccount storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

      CloudQueue queue = storageAccount.CreateCloudQueueClient().GetQueueReference("blobqueue");

      CloudQueueMessage msg = queue.GetMessage();

      if (msg != null)
      {
            string actionType = msg.AsString.Split(';')[0];
            string content = msg.AsString.Split(';')[1];

            switch (actionType)
            {
                  case "TXT":
                        // Write the Blob
                        break;
            }

            // After all work is done, delete the message
            queue.DeleteMessage(msg);
      }
      else
      {
            Thread.Sleep(10000);
      }
}

Like I said, we could implement a better solution for that Sleep() over there, but, in some cases, it is fully functional just as it is: checking the queue within a certain time span.

Now we're gonna get that message, and write its content to a Blob:

while (true)
{
      CloudStorageAccount storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

      CloudQueue queue = storageAccount.CreateCloudQueueClient().GetQueueReference("blobqueue");

      CloudQueueMessage msg = queue.GetMessage();

      if (msg != null)
      {
            string actionType = msg.AsString.Split(';')[0];
            string content = msg.AsString.Split(';')[1];

            switch (actionType)
            {
                  case "TXT":
                        CloudBlobContainer blobContainter = storageAccount.CreateCloudBlobClient().GetContainerReference("mycontainer");
                        blobContainter.CreateIfNotExist();
                        CloudBlob cloudBlob = blobContainter.GetBlobReference(string.Concat(DateTime.Now.ToString("dd-MM-yyyy_hh-mm-ss"), ".txt"));
                        cloudBlob.UploadText(content);
                        break;
            }

            // After all work is done, delete the message
            queue.DeleteMessage(msg);
      }
      else
      {
            Thread.Sleep(10000);
      }
}

That should create a new Blob container (a folder) and inside it, a .txt file (Blob). The same goes for the container name: it must not have any uppercase characters, or you will get a StorageClientException, with message "One of the request inputs is out of range.".
Simple again, huh.

Let's write something to the Table. In this example, we're gonna write customer records to the table: Customer ID, Customer's Name, and Customer's Connection String, assuming that each customer will have its own Database.

In a brief explanation of tables, the three important columns are: PartitionKey, RowKey, and TimeStamp.

Partition Key behaves like a string, so we could use it to filter our Records. For example, if we have two sources of customers, and we wanna know where they came from, we could have two different values for PartitionKey: "CustSource1" and "CustSource2". So when selecting those customers, we could filter them by PartitionKey.

RowKey is our primary key. It cannot be repeated, and it doesn't have auto-incrementation systems as identity fields. Usually, they get GUIDs.

TimeStamp is just a last modified time stamp.

To interact with Tables, we have to define a Model and a Context.
Our model will describe the record, and which columns it'll have. The context will interact directly with the table, inserting, deleting and selecting records.

It's important NOT to link these tables with SQL Server tables. They don't mantain a pattern. You can insert a record with 3 columns in a certain table, and then a record with completely different 6 columns in the same table, and it will take it normally.

To define our Model, we have to inherit from TableServiceEntity. We can then define our own columns and constructors and whatever we want to.

class CustModel : TableServiceEntity
{
    private const string PARTITIONKEY = "Cust";
    public const string TABLENAME = "CustModel";

    public CustModel(string custID, string name, string connStr)
        : base(PARTITIONKEY, custID)
    {
        Name = name;
        ConnStr = connStr;
    }

    public CustModel(string custID)
        : base(PARTITIONKEY, custID)
    {
    }

    public string Name { get; set; } 
    public string ConnStr { get; set; }
}


Once we have defined our Model, we'll work on our Context. The Context iherits from TableServiceContext. It also provides us some important key methods to work with. Our defined interaction methods should also be here, like the code below:

class CustDataContext : TableServiceContext
{
    private const string CUSTMODEL = "CustModel";

    public CustDataContext(string baseAddress, StorageCredentials credentials)
        : base (baseAddress, credentials)
    {
        CloudTableClient.CreateTablesFromModel(typeof(CustDataContext), baseAddress, credentials);
    }

    public IQueryable CustModel
    {
        get
        {
            return this.CreateQuery(CUSTMODEL);
        }
    }

    public void DeleteCustomer(CustModel cust)
    {
        this.DeleteObject(cust);
        this.SaveChanges();
    }

    public void AddCustomer(CustModel cust)
    {
        this.AddObject(CUSTMODEL, cust);
        this.SaveChanges();
    }

    public CustModel GetCustomerByID(string custID)
    {
        var results = from cust in this.CustModel
                      where cust.RowKey == custID && cust.PartitionKey == "Cust"
                      select cust;

        return results.FirstOrDefault();
    }

    public CustModel GetCustomerByName(string name)
    {
        var results = from cust in this.CustModel
                      where cust.Name == name && cust.PartitionKey == "Cust"
                      select cust;

        return results.FirstOrDefault();
    }
}

Notice the IQueryable property that returns us the table corresponding to the table name specified as a parameter. Whenever you want to access the table, that should be the property. You can also define more than one property, but always a table per property. The only other key method is the one called inside the constructor.
Oh and you have to add a reference to System.Data.Services.Client or you won't be able to call method CreateQuery().

Now how do we work with this? With the code below!

CloudStorageAccount storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
tableClient.CreateTableIfNotExist(CustModel.TABLENAME); 
  
CustDataContext custDataContext = new CustDataContext(storageAccount.TableEndpoint.ToString(), storageAccount.Credentials);
CustModel cust = new CustModel("1", "Felipe", "MyConnStr");
custDataContext.AddCustomer(cust);

It should create a table with the name defined in the constant CustModel.TABLENAME, respecting the columns defined in the Model. You do not have to create the columns manually, it'll do so automatically.



So this post explained the basics of Windows Azure, and how simple it is to work with it. If you are going to do so, I suggest you download some applications from codeplex, such as:



SQL Azure Migration Wizard helps you migrate your already existing database to SQL Azure.
Azure Storage Explorer lets you visually navigate through your storage objects, such as Queue Messages, Blobs, Containers, Tables, etc.

Wednesday, December 8, 2010

Converting a Web Site to a Web Application

To get our application to Windows Azure, we had to convert it from a Web Site to a Web Application.

I won't explain the differences between those two, you can go and Google it.


After some research, I found out the worst: there's no tool or wizard to do that, you have to do it manually. So open your Web Site solution, add a new Web Application project to it, and follow these steps.


First Step
Copy and paste everything. Copy everything on your Web Site, straight from the Solution Explorer, and paste it under the Web Application project. (don't forget to delete everything there first) To do that simply click the project and hit CTRL + V.

Second Step
Add the references again. You can check what are the references on the properties page for your Web Site. If it has any other projects references as well, you add them too. Keep adding them until you get no more missing reference errors.

Third Step
Now this is an amusing step. If you right click your newly created Web Application project, you'll notice an option that says: "Convert to Web Application". When you click that, Visual Studio basically reconnects your .aspx files with their corresponding code-behind files. All it does is change some minor things on the Page tags for your .aspx files. Possibly, you'll have to do this more than once, because if a page has a missing reference error, Visual Studio won't be able to work this on it, and it'll be ignored, so make sure you get all the reference errors first, and do this a couple of times.

Lastly
Keep trying to compile until you get no errors. And pay attention to the App_Code. When you convert it to a Web Application, Visual Studio renames the App_Code folder to "Old_App_Code". Do not rename it back, leave it just the way it is. On a Web Application, your classes don't need to be inside an App_Folder folder to work, they can be anywhere. So if you want to rename it, rename to something OTHER than App_Code, because it may cause some multiple declaration problems.

Important
Your code residing in the Old_App_Code may not be seen, although Visual Studio WILL NOT show you any compile-time errors. If it doesn't find your code, a runtime error will be thrown. To fix that, if you get any runtime errors, you just check where the calls are on your code, and put the cursor over it, Visual Studio will then probably show that it is not found, and suggest corrections. That happened to me, and in the end, all I had to do was reference the Web Application assembly (self referece, yes!), as it takes all classes in the project and puts it together in there. Be careful with namespaces here. And check for this everytime you get "Not Declared" or "Not Found" runtime errors.

So that's basically it, all I did was describe it all, in fewer and simpler words.

The post that guided me through all this can be found here.

Also, here's the official MSDN walkthrough.