22 Sep 2010 @ 2:00 PM 

In traditional ASP.NET application, you have option to use several session states mode including In-Process, State Server, SQL Server, or even Custom. In fact, the simplest way and most common scenario is using In-Process where the session states is actually stored in the web server memory.

However, you will definitely face challenges when using in-proc session mode in Windows Azure. As the matter of fact, you may be fine if you are running only with one instance. The reason is because when you have more than one role instance, Windows Azure will create separate VMs for each role instance. As it, each role instance will own their own memory space that is not sync-up amongst other instance-roles. Well, it’s not a good idea to restrict our application to stick to one instance, since probably the reason you choose Windows Azure is the ability to scale in and out elastically.

Alright,let me simply show you why it’s challenging.

Running with one instance

1. The first step,I open Visual Studio and simply select New Project – Cloud – Windows Azure Cloud Service. And type in SessionDemo.

image_0EAFE89B

2. When the New Cloud Service Project dialog box comes out, select ASP.NET WebRole and change the name to SessionDemo_WebRole, and click OK.

image_5C704A85

3. In the default.aspx page, I simply insert several ASP.NET component as shown below.

   1: <asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
   2:     <h2>
   3:         Welcome to ASP.NET!
   4:     </h2>
   5:     <p>
   6:         Enter value for session "CustomerName" : 
   7:         <asp:TextBox runat="server" ID="txtCustomerName" />
   8:         &nbsp;<asp:Button Text="Save Session" ID="btnSaveSession" runat="server" 
   9:             onclick="btnSaveSession_Click" />
  10:         <br />
  11:         <br />
  12:         <asp:Button Text="Display Session" ID="btnDisplaySession" runat="server" 
  13:             onclick="btnDisplaySession_Click" />
  14:         <br />
  15:         <asp:Label Text="" ID="lblSessionValue" runat="server" />
  16:     </p>
  17: </asp:Content>

4. Next, go to default.aspx.cs and type the following code:

   1: public partial class _Default : System.Web.UI.Page
   2: {
   3:     protected void Page_Load(object sender, EventArgs e)
   4:     {
   5:  
   6:     }
   7:  
   8:     private const string SESSION_NAME_KEY = "CustomerName";
   9:  
  10:     protected void btnSaveSession_Click(object sender, EventArgs e)
  11:     {
  12:         Session[SESSION_NAME_KEY] = txtCustomerName.Text;
  13:         System.Diagnostics.Trace.TraceInformation("New value of session CustomerName : {0} is stored in {1}.", 
  14:             txtCustomerName.Text, RoleEnvironment.CurrentRoleInstance.Id);
  15:     }
  16:  
  17:     protected void btnDisplaySession_Click(object sender, EventArgs e)
  18:     {
  19:         System.Diagnostics.Trace.TraceInformation("Request is handled by " + RoleEnvironment.CurrentRoleInstance.Id);
  20:         if (Session[SESSION_NAME_KEY] != null)
  21:             lblSessionValue.Text = "Value for CustomerName is : " + Session[SESSION_NAME_KEY].ToString();
  22:     }
  23: }

What it does is just simply display the session value to the screen as well as write it to log by calling Trace.TraceInformation() method.

5. Run the application by click on Run button or F5. Fill-in “Bob” on the textbox and click on “SaveSession” button. When you click on “DisplaySession”, you will simply get “Bob” value which you’ve entered earlier.

image_418F2906

6. Alternately, you can also notice the log at development fabric indicate that “New value of session CustomerName : Bob is stored in deployment(495).SessionDemo.SessionDemo_WebRole.0.

image_25219B4C

Yes, so far so good. You may change to other value, I guarantee you that it’s still working well as per now.

Running with more than one instance

7. By default, Visual Studio will specify only 1 instance per role. If you need more, you can just simply modify it by click on the intended role and fill in the value of “Instance count:”

image_39FFA59A

Now, change the instance count from 1 to 2.

8. Run your application by pressing F5 / click on Run button. At the mean time, open up your development fabric UI as well. You may want to clear your log to see it more clearly.

image_19081EF4

As usual, I type “Bob” on the browser and click on “SaveSession”. If you inspect on the dev fabric UI, you will notice that only one of the two role will be handling your request.

image_2B5821DE

9. Click on the “DisplaySession” button to see whether you can see the value “Bob” is display. The answer is maybe yes, maybe no. If the instance 0 who are handling the request, then good that you would be able to retrieve the value. However, it’s also possible that instance 1 is the one who is handling your request. If this is the case, you will see no value displayed.

image_25A91A06

This proves that the in-proc session scenario doesn’t work in Windows Azure environment.

In the next post, I’ll show you how to use TableStorage Session to workaround this issue.

See you.

Posted By: admin
Last Edit: 17 Oct 2012 @ 09:08 AM

EmailPermalinkComments (2)
Tags
Tags:
Categories: Windows Azure
 21 Sep 2010 @ 1:54 PM 
In last post, I’ve shown you why and how the InProc session doesn’t work in Windows Azure. In this post, I’ll show you how to work around this issue, specifically using Azure Storage as Custom Session Provider. Well, actually it’s also possible for you to use other provider such as SQL.
AspProviders actually not only mean to be used for Session, it also available for Profile and Membership implementation in Azure Storage. However, I’ll only focus on the session state in this post. Session is implemented by using Table and Blob Storage to store the hashed value of our session. Don’t worry about the complexity because the way we access session in our application is exactly the same. You still use Session[“name”] to set and get the value.

How to use

0. Regarding the sample project, please refer to my previous post the continue if have not do so.
1. Download the provider that was originally uploaded on Windows Azure Code Sample. To simplify and avoid any confusion, I also upload the provider here as compiled dll format  or the entire complete solution.
2. Reference the AspProviders dll / project to your main intended project. (In this example, I use dll file only).
image_3CE2FF4B
3. You will need to add some configuration in web.config as following (below the configuration section):
   1: <configuration>

 

   2:   <appSettings>

 

   3:     <!-- account configuration -->

 

   4:     <add key="TableStorageEndpoint" value="http://127.0.0.1:10002/devstoreaccount1"/>

 

   5:     <add key="BlobStorageEndpoint" value="http://127.0.0.1:10000/devstoreaccount1"/>

 

   6:     <add key="AccountName" value="devstoreaccount1"/>

 

   7:     <add key="AccountSharedKey" value="Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="/>

 

   8:     <add key="DefaultSessionTableName" value="Sessions"/>

 

   9:   </appSettings>

 

  10:   ....

Do note that in the example above, I point the value of both TableStorageEndpoint as well as BlobStorageEndpoint to my local storage account. The same thing applies in AccountName and AccountSharedKey, I also point them to my local dev storage account. When uploading to Azure environment, do remember to change those configuration as required.
Alternately, you may also want to change the DefaultSessionTableName if you want to be stored in different table name.
4. Still in web.config file, locate to “system.web” section and insert the following configuration. This is to tell the ASP.NET engine that we will use “custom” session mode that was implemented with TableStorageSessionStateProvider.
   1: <system.web>

 

   2:   <sessionState mode="Custom" customProvider="TableStorageSessionStateProvider">

 

   3:     <providers>

 

   4:       <clear/>

 

   5:       <add name="TableStorageSessionStateProvider" type="Microsoft.Samples.ServiceHosting.AspProviders.TableStorageSessionStateProvider" />

 

   6:     </providers>

 

   7:   </sessionState>

 

   8:   ...

Alright, that’s all done. Now, you may want to test our new configured session state works.

Let’s test it

1. I purposely, change the instance of my webrole to 3.
image_174CB812
2. Just run the application as usual and enter “Bob” to the textbox as what we’ve done in the previous post.
image_42D5D989
You can see that, other than our log that was written with TraceInformation, the AspProvider actually stored something on the table and blob with respect to our session key and value.
3. Now click on the “DisplaySession” button to see whether you can get the value. I believe it can right Smile. Yes, since the value is not stored on the webrole’s memory, however on the table storage.
image_7ECCF59C
4. As I mentioned before, AspProviders will store our session key / value in form of “hashed” in the table and blob storage, depending the configuration we’ve done on which account to store. To enable you to clearly see those table and blob, you may want to use AzureStorageExplorer to examine further when the session is created.
image_5E51C7B8
Now, you can see that there’s a record exists on my “Sessions” table inside my local account.
You can also download my complete sample project here.
I hope this post is useful for you.
Posted By: admin
Last Edit: 17 Oct 2012 @ 09:11 AM

EmailPermalinkComments (1)
Tags
Tags:
Categories: Windows Azure
 08 Sep 2010 @ 2:04 PM 
This is an additional post for Migrating ASP.NET Application to Windows Azure series. Please refer to previous related posts if you have not read it before.

Introduction

In the step 6 of the Part 3 post, remembering that I commented some portion of the code in AdminPhoto.aspx and App_CodePhotoManager.cs which unable be run directly on Windows Azure. What actually the feature does is enable us to perform bulk copy from the web server’s folder namely “upload” to the database. However, those code could not simply work on Azure since we have no control over the “upload” folder when our app has been uploaded to Windows Azure.
image_0D77A98A

The idea to implement similar feature

As I promise to answer to this issue, in this post I’ll show you step-by-step how to implement similar feature. We will be do those things in 2 files: AdminPhoto.aspx and AdminPhoto.aspx.cs.
The idea to use blob storage as replacement of “upload” folder. We can upload our photos to blob storage by using tool such as Azure Storage Explorer.
image_78315616
Assuming that I’ve created a container called “photos” and uploaded some photos in that container.
When user is ready to upload the photos inside the container, they will click on Import and what our application do is to store these photos to SQL Azure using the existing class library “PhotoManager.cs”.
*Please note that actually the better practice is to store those file in blob storage rather than SQL Azure since scalability and cost-efficient concern. However, since I’ve used SQL Azure to store the data (including photos) from the beginning of this post, I’ll just continue to do with respect to consistency manner.

Step by Step: how to implement

1. DataConnectionString setting on compute role.

Since we are using Azure Storage, we’ll need to add a setting on intended role (in my sample: PersonalWebRole) as shown below.
image_4D40A439
To do that, double click on PersonalWebRole which is located below CloudServicePersonalRoles folder. Subsequently click on Settings tab.
You may note that in the example I use DevelopmentStorage, of course you could be able to use the “real” Azure Storage. All you need to do is to create a Azure Storage Service and then specify the service name as well as the key as the value.

2. Some codes in WebRole.cs

To tell WebRole that “please refer to the setting to retrieve the storage value”, we’ll need to add something on OnStart method inside WebRole.cs. (the yellow highlighted section).
   1: public override bool OnStart()

 

   2: {

 

   3:     DiagnosticMonitor.Start("DiagnosticsConnectionString");

 

   4:

 

   5:     RoleEnvironment.Changing += RoleEnvironmentChanging;

 

   6:

 

   7:     CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>

 

   8:         {

 

   9:             configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));

 

  10:         });

 

  11:

 

  12:     return base.OnStart();

 

  13: }

3.  In AdminPhoto.aspx file.

I replace the commented section with the following codes.
   1: <div id="sidebar">

 

   2: <asp:ScriptManager ID="ScriptManager1" runat="server">

 

   3: </asp:ScriptManager>            <h4>Bulk Upload    Photos</h4>

 

   4:     <p>The following files were found in your <b><%
   1:  = ddlBlobContainer.SelectedValue
%></b> folder, in your Azure Blobs Storage.
   5:     <br />Click on <b>Import</b> to import these pictures to your photo album.</p>

 

   6:     <asp:UpdatePanel ID="up" runat="server">

 

   7:         <ContentTemplate>

 

   8:             Select Container: <asp:DropDownList AutoPostBack="true" ID="ddlBlobContainer" runat="server"

 

   9:             onselectedindexchanged="ddlBlobContainer_SelectedIndexChanged" />

 

  10:             <br /><br />

 

  11:             <div style="height:300px; overflow:scroll; text-align:center; border:solid 1px #fff" >

 

  12:                 <asp:ListView runat="server" id="UploadList" repeatcolumns="1"

 

  13:                     repeatlayout="table" repeatdirection="horizontal"

 

  14:                     onitemdatabound="UploadList_ItemDataBound" >

 

  15:                     <LayoutTemplate>

 

  16:                         <div style="border:solid 1px #000; padding:5px; margin:5px" runat="server" id="itemPlaceholder">

 

  17:                         </div>

 

  18:                     </LayoutTemplate>

 

  19:                     <ItemTemplate>

 

  20:                         <asp:Image ID="img" runat="server" Width="120px" />

 

  21:                     </itemtemplate>

 

  22:                     <ItemSeparatorTemplate><br /><br /></ItemSeparatorTemplate>

 

  23:                     <EmptyDataTemplate>the container doesn''t contain any photos</EmptyDataTemplate>

 

  24:                 </asp:ListView>

 

  25:             </div>

 

  26:         </ContentTemplate>

 

  27:     </asp:UpdatePanel>

 

  28:     <asp:ImageButton ID="ImageButton1" Runat="server" onclick="Button1_Click" SkinID="import" />

 

  29: </div>

Let me explain you how these things were added
a. I added a DropDownList called ddlBlobContainer. This ddlBlobContainer will be used to list out all of our blob containers that were associated with our storage account.
b. When we select on one of the ddlBlobContainer, we’ll fetch all blob item in that container and display it to user interface (UI).  l use ListView as UI container rather than of using DataList. Inside the ListView, I added Image object to show the thumbnail display, so that use could be able to see it before performing bulk copy.
c. I use UpdatePanel to enable ajax functionality so that the browser won’t be refreshed in full page view. (Remember that we’ll also need to include the ScriptManager in order to use UpdatePanel).

4. In AdminPhoto.aspx.cs file.

a. The next thing to do when using Azure Storage is to initialize the storage account as well as object that we are going to use.
   1: private static bool storageInitialized = false;

 

   2: private static object gate = new Object();

 

   3: private static CloudBlobClient blobStorage;

 

   4:

 

   5: private void InitializeStorage()

 

   6: {

 

   7:     if (storageInitialized) return;

 

   8:     lock (gate)

 

   9:     {

 

  10:         if (storageInitialized) return;

 

  11:         try

 

  12:         {

 

  13:             var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

 

  14:             blobStorage = storageAccount.CreateCloudBlobClient();

 

  15:             CloudBlobContainer container = blobStorage.GetContainerReference("photos");

 

  16:             container.CreateIfNotExist();

 

  17:

 

  18:             var permission = container.GetPermissions();

 

  19:             permission.PublicAccess = BlobContainerPublicAccessType.Container;

 

  20:             container.SetPermissions(permission);

 

  21:         }

 

  22:         catch (Exception ex)

 

  23:         {

 

  24:             throw new Exception("Error : " + ex.Message);

 

  25:         }

 

  26:         storageInitialized = true;

 

  27:     }

 

  28: }

  • The storageInitialized variable is used as flag to indicate whether the storage has been initialized
  • The gate variable is to be used along with “lock” statement, to ensure that other threads won’t enter the critical section before the resource has been released.
  • The blobStorage object serves as CloudBlobClient, to manipulate the blob of container.
  • In the InitializeStorage method, we get the connection value from the settings, create cloud blob client, get / create the specific container (In this example called “photos”) and finally set the permission of the container to public access.
b. Subsequently, I added BindUploadList() method which fetches blob from the container and display it to the listview.
   1: private void BindUploadList()

 

   2: {

 

   3:     CloudBlobContainer container = blobStorage.GetContainerReference(ddlBlobContainer.SelectedValue);

 

   4:     IEnumerable<IListBlobItem> blobItems = container.ListBlobs();

 

   5:

 

   6:     var photoBlobs = from i in blobItems

 

   7:                      where i.Uri.AbsoluteUri.ToLower().EndsWith(".jpg")

 

   8:                      || i.Uri.AbsoluteUri.ToLower().EndsWith(".png") ||

 

   9:                      i.Uri.AbsoluteUri.ToLower().EndsWith(".gif")

 

  10:                      select i;

 

  11:

 

  12:     UploadList.DataSource = photoBlobs;

 

  13:     UploadList.DataBind();

 

  14: }

I also ensure that only file that ends with .jpg, .png, gif will be displayed.
c. The next thing is to implement the UploadList_ItemDataBound method to handle the ItemDataBound event.
   1: protected void UploadList_ItemDataBound(object sender, ListViewItemEventArgs e)

 

   2: {

 

   3:     if (e.Item.ItemType == ListViewItemType.DataItem)

 

   4:     {

 

   5:         IListBlobItem blobItem =  ((ListViewDataItem)e.Item).DataItem as IListBlobItem;

 

   6:         Image img = e.Item.FindControl("img") as Image;

 

   7:         img.ImageUrl = blobItem.Uri.AbsoluteUri;

 

   8:     }

 

   9: }

d. To ensure that each time the photos would be refreshed when container was selected, I implemented the following snippet.
   1: protected void ddlBlobContainer_SelectedIndexChanged(object sender, EventArgs e)

 

   2: {

 

   3:     BindUploadList();

 

   4: }

e. In the Page_Load method, I get the setting first and then dump the blob containers to the dropdownlist, so that user could select the available container.
   1: protected void Page_Load(object sender, EventArgs e)

 

   2: {

 

   3:     if (!Page.IsPostBack)

 

   4:     {

 

   5:         InitializeStorage();

 

   6:

 

   7:         var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

 

   8:         blobStorage = storageAccount.CreateCloudBlobClient();

 

   9:

 

  10:         IEnumerable<CloudBlobContainer> cloudBlobContainers = blobStorage.ListContainers();

 

  11:         ddlBlobContainer.DataSource = cloudBlobContainers;

 

  12:         ddlBlobContainer.DataTextField = ddlBlobContainer.DataValueField = "Name";

 

  13:         ddlBlobContainer.DataBind();

 

  14:

 

  15:         BindUploadList();

 

  16:     }

 

  17: }

f. When the button “Import” was clicked, I loop through all the available photo in the container. For each blob item in the container, I’ll read the blob item, buffer it into array of byte, and finally submit the photos to the SQL Azure.
   1: protected void Button1_Click(object sender, ImageClickEventArgs e) {

 

   2:     CloudBlobContainer container = blobStorage.GetContainerReference("photos");

 

   3:

 

   4:     foreach (IListBlobItem blobItem in container.ListBlobs())

 

   5:     {

 

   6:         CloudBlob obj = container.GetBlobReference(blobItem.Uri.AbsoluteUri);

 

   7:         BlobStream blobStream = obj.OpenRead();

 

   8:

 

   9:         System.Drawing.Image objImage = null;

 

  10:         objImage = System.Drawing.Image.FromStream(blobStream);

 

  11:

 

  12:         string uniqueBlobName = Guid.NewGuid().ToString();

 

  13:         byte[] buffer = new byte[obj.OpenRead().Length];

 

  14:         obj.OpenRead().Read(buffer, 0, (int)obj.OpenRead().Length);

 

  15:

 

  16:         PhotoManager.AddPhoto(Convert.ToInt32(Request.QueryString["AlbumID"]), uniqueBlobName, buffer);

 

  17:     }

 

  18:     GridView1.DataBind();

 

  19: }

5. Verification

Let’s press Run button and see how it works!
a. We’ll need to login as administrator first before we can perform bulk upload.
image_516667FF
b. Having done so, please proceed to Manage link and click Edit on one of the Album.
image_000FBED8
c. You can now see the list of container in the dropdownlist, once you select one of them, the photos are refreshed accordingly.
image_75565152
Now, click on the Import button. In few moments, you can see that, you’ve successfully uploaded the photos.
image_70E3BA5B
Alright, we are now done.
I hope you enjoy this post and would be useful for you. See you at another post.
Posted By: admin
Last Edit: 17 Oct 2012 @ 09:19 AM

EmailPermalinkComments (0)
Tags
 06 Sep 2010 @ 2:10 PM 

Introduction

As most of you have known that, when creating service to host our application in Windows Azure, we are provided a special DNS with suffix .cloudapp.net. For example: http://welypersonal.cloudapp.net/ which is personal starter kit that have been moved to the cloud. You can refer to the series of migration post if you want to know more about it.

It’s very common requirement that we have our custom domain name and want to map it to the cloud-based application. For instance, I have my own wely-lau.net domain which was registered on DynaDot. And then, I would like to create subdomain, namely http://azure.wely-lau.net and map it to http://welypersonal.cloudapp.net.

Steve Marx’s post

Steve Marx, the Technical Strategist on Windows Azure blogged this post about it, specifically using GoDaddy as domain registrar . However, we notice that there’s some incorrect image that could lead to confusion. I emailed him before and he said he will fix it later on. We hope so Steve, as there’s so many people refer to your blog Smile.

image_0E873BA4

In the post, Steve mentioned that, in general there’re 2 ways to map domain to point to a location.

  1. Using “A” record to point to a specific address. However,we are unable to do that in Windows Azure. The reason is when we host our application to Azure,the IP address might be changed without our awareness. For example: when we increase the number of instance of our hosted application. The fabric controller, which is acting as the “brain” will look for available machine to move or create the VM for our application. As it, the IP would be change. Whereby, to use A record, we need to point it to static IP address. Thus, this is not an option for us.
  2. Using “CNAME” record, which can map a specific domain to another DNS entry, without have to setting the . This is the possible way to do it in Azure.

How to do it?

In this post, I’ll show you how to map your custom domain to Windows Azure. In order to follow my instruction, you will of course need to own your domain. You can buy or register your domain with some domain registrar such as GoDaddy, DynaDot, Register, etc.

In this example, I’ll show you how to do it in DynaDot, since my domain wely-lau.net was registered there. If you are using other domain registrar, no worries. I believe more or less, the functional and features are the same, just look for it carefullyOpen-mouthed smile.

1. Log in to your domain registrar portal.

You should see some summary info of your domain subscription.

image_23189CF0

2. Go to Domains tab, then click on the domain that you wish to map.

image_048E106D

3. Click on the value of the name server, which your Domain refer to.

image_37A9FE3C

4. Now, you can find appropriate record type and map it to your intended location.

image_25E9A20A

As you can see from the screenshot above, I create a sub domain “azure” by using CNAME record and map it to “welypersonal.cloudapp.net”.

Additionally, I can also forward my domain to any intended location, for example I map wely-lau.net and www.wely-lau.net to http://netindonesia.net/blogs/wely.

5. When ready, click on the “Use DynaDot DNS” to apply.

Do note that, I takes a few minutes to apply new domain setting.

image_2DFD7C07

6. Here’s the screenshot after a few minutes

image_46302059

Notice the URL. When I type http://azure.wely-lau.net, I map it to my personal starter kit application which could be found in http://welypersonal.cloudapp.net.

I hope this post is useful for you Smile.

I’ll post more Azure-related post in future. Stay tuned here.

Posted By: admin
Last Edit: 17 Oct 2012 @ 09:23 AM

EmailPermalinkComments (0)
Tags

 Last 50 Posts
 Back
Change Theme...
  • Users » 123
  • Posts/Pages » 72
  • Comments » 86
Change Theme...
  • VoidVoid
  • LifeLife
  • EarthEarth
  • WindWind « Default
  • WaterWater
  • FireFire
  • LightLight

About Me



    No Child Pages.