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.
1. The first step,I open Visual Studio and simply select New Project – Cloud – Windows Azure Cloud Service. And type in SessionDemo.
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.
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: <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.
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.”
Yes, so far so good. You may change to other value, I guarantee you that it’s still working well as per now.
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:”
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.
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.
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.
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.
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: ....
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: ...
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: }
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>
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: }
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: }
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: }
1: protected void ddlBlobContainer_SelectedIndexChanged(object sender, EventArgs e)
2: {
3: BindUploadList();
4: }
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: }
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: }
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, 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
.
In the post, Steve mentioned that, in general there’re 2 ways to map domain to point to a location.
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 carefully
.
1. Log in to your domain registrar portal.
You should see some summary info of your domain subscription.
2. Go to Domains tab, then click on the domain that you wish to map.
3. Click on the value of the name server, which your Domain refer to.
4. Now, you can find appropriate record type and map it to your intended location.
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.
6. Here’s the screenshot after a few minutes
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
.
I’ll post more Azure-related post in future. Stay tuned here.

Categories
Tag Cloud
Blog RSS
Comments RSS
Last 50 Posts
Back
Back
Void
Life
Earth
Wind « Default
Water
Fire
Light 