March 31, 2014

Different ways to combine urls

In asp.net, there are different way to combine urls with the easiest way to simply add multiple strings and the better way to use classes and methods already from asp.net. In this post, I will show different way to add multiple url parts to form a valid url.

In asp.net there are few classes with urls can be constructed like the Uri class. However, I actually prefer the use of UriBuilder class as it provides more options to specify the parameters like host, query string, anchor links, port number and so on. This is much easier class to work with than to build urls with other classes. So, below is the source code for two ways to build urls - one with concatenating strings and another with UriBuilder class.

String vs UriBuilder
  1. using System;
  2. using System.Text;
  3.  
  4. namespace WebApplication1
  5. {
  6.     public partial class UrlParts : System.Web.UI.Page
  7.     {
  8.         private bool isSecure = false;
  9.         private string host = "www.asp.net";
  10.         private int? port = 8080;
  11.         private string path = "mvc";
  12.         private string query = "s=entity|framework";
  13.         private string hash = "ef";
  14.  
  15.         //http: //www.asp.net/mvc?s=entity|framework#ef
  16.  
  17.         protected void Page_Load(object sender, EventArgs e)
  18.         {
  19.             Response.Write("from string: " + UrlsByStrings());
  20.             Response.Write("<br>from url builder: " + UrlsByUriClass());
  21.         }
  22.  
  23.         private string UrlsByStrings()
  24.         {
  25.             StringBuilder sb = new StringBuilder();
  26.  
  27.             if (isSecure)
  28.                 sb.Append("https://");
  29.             else
  30.                 sb.Append("http://");
  31.  
  32.             sb.Append(host);
  33.  
  34.             if (port.HasValue)
  35.                 sb.Append(":" + port.Value.ToString());
  36.  
  37.  
  38.             if (path != null)
  39.                 sb.Append("/" + path);
  40.  
  41.  
  42.             if (query != null)
  43.                 sb.Append("?" + query);
  44.  
  45.             if (hash != null)
  46.                 sb.Append("#" + hash);
  47.  
  48.             return sb.ToString();
  49.         }
  50.  
  51.  
  52.         private string UrlsByUriClass()
  53.         {
  54.             UriBuilder ub = new UriBuilder();
  55.             ub.Scheme = isSecure ? "https" : "http";
  56.             ub.Host = host;
  57.  
  58.             ub.Port = port.HasValue ? port.Value : -1;
  59.             ub.Path = path == null ? string.Empty : path;
  60.             ub.Query = query == null ? string.Empty : query;
  61.             ub.Fragment = hash == null ? string.Empty : hash;
  62.  
  63.             return ub.ToString();
  64.         }
  65.     }
  66. }

March 30, 2014

I can do lot of cool things with asp.net but sometimes I don't like the idea of postbacks, specially when working on large pages. Imagine a page with a number of controls and every postback will send the controls data back and and forth and recreate the controls. So, how can I write asp.net and call methods on code-behind from aspx pages without using postbacks.

March 27, 2014

Both RegisterStartupScript and RegisterClientScriptBlock are different ways to add javascript to an aspx pages. RegisterStartupScript renders the javascript at the bottom of the html source just before the form tag closes meaning that controls and html elements defined within the page can called up by the javascript. For example, if I have a span or div element within the page, I can change the color or any other style properties using RegisterStartupScript and the new style will appear straight way.

March 25, 2014

Copy Object using MemberwiseClone

MemberwiseClone method from the Object class can be used to perform a shallow copy of an object. The method creates a new Object, copies all the instance fields. For value type fields, it copies bit by bit. For reference types fields, the reference is copied. That is, if the reference field / object is changed by the initial object, then the cloned object will also get updated. I have written sample code to illustrate. I have used a web project - but you can use a console application if you like it.

  1. using System;
  2. using System.Collections.Generic;
  3.  
  4. namespace WebApplication1
  5. {
  6.     public class TestClone
  7.     {
  8.         public string Field1;
  9.         public DateTime Date1;
  10.         public double Double1;
  11.         public List<TestList> List1;
  12.  
  13.  
  14.         public object Clone()
  15.         {
  16.             return this.MemberwiseClone();
  17.         }
  18.     }
  19.  
  20.     public class TestList
  21.     {
  22.         public string Name;
  23.         public int Age;
  24.     }
  25. }

 

  1. private void Copy()
  2. {
  3.     TestClone t = new TestClone() { Date1 = new DateTime(2014, 3, 2), Double1 = 2.0, Field1 = "hhh" };
  4.     
  5.     //create a new list
  6.     t.List1 = new List<TestList>();
  7.     t.List1.Add(new TestList() { Age = 20, Name = "Smith" });
  8.     t.List1.Add(new TestList() { Age = 30, Name = "John" });
  9.  
  10.     TestClone t2 = (TestClone)t.Clone();
  11.     
  12.  
  13.     //modify t
  14.     t.Double1 = 3.0;
  15.     t.Field1 = "ABC";
  16.     t.List1.Add(new TestList() { Age = 40, Name = "Jim" });
  17.  
  18.  
  19.     //t3 will have old Double1 and Field1 values but new List1
  20.     TestClone t3 = (TestClone)t2.Clone();
  21.  
  22.     //t4 will have new Double1, Field1 values and new List1
  23.     TestClone t4 = (TestClone)t.Clone();
  24.  
  25. }

March 24, 2014

I created an application by copying an existing one and then changing the namespaces but I had to go through some trouble to get it working. It continuously failed with the message - "The located assembly's manifest definition does not match the assembly reference" - that is, the application is picking up wrong version of the referenced assembly.

Firstly, I had to change the names of the classes to the new namespace and then compile and make sure that it ran fine.

Secondly, instead of copying the bin directory directly, I add the nuget packages by right-clicking on Solution Explorer and clicking "Manage Nuget Packages". Now, doing this was easy until I realised the application has some compatibility issues with the new versions of the packages. Now, in order to avoid fixing the problem which might require code changes, I decided to get the old packages which was a bit difficult. Eventually, I deleted the packages from "Manage Nuget Packages" and then copied the bin directory and manually added references to the dlls by right clicking on References and choosing "Add Reference".

Now, I was confident that the application would work but it failed again with the message "The located assembly's manifest definition does not match the assembly reference". This is basically saying that I am pointing to a wrong package. I checked on "Manage Nuget Packages" but it was displaying the expected version. What I realised is that I have one package which already called another package which had the wrong version. After checking, I realised that I still had one of the newer packages that I needed to change to the older one. So, went through the same step described above. (The issues I had was with System.Web.Optimization and Microsoft.AspNet.Web.Optimization.WebForms packages).

Finally, I built the application again but it failed with not finding certain controls on the pages. That is, the code-behind could not find the controls on the aspx pages which was a bit weird. I have discussed this on another article as it is not directly relevant here - find out how I fixed it.

Finally, the application ran and it worked fine.

I created a project by copying some files from another project and for some reason the project would not compile and kept failing to find the asp.net controls from code behind. This was really strange as it looked all fine. So, I thought, I would give it a try by creating another new page and then copying the source code from one of the pages that is failing. Surprisingly, this worked and the new page could easily find the controls from the aspx pages which is the correct behavior.

Now, I could create new pages and delete the old ones but then it's silly and will take me a lot of time to fix it. Basically, what happened is that asp.net is somehow caching the old compiled version of the application and therefore pointing to the wrong namespace and so not find the controls.

To fix the issue, I placed incorrect xml in web.config file so it won't be a valid xml file anymore. Then, I recompiled the application and yeahhh - the application started working again as usual.

So, changing web.config to something invalid is forcing the application to remove the cache and rebuild.

March 21, 2014

Index Size in Sql Server Database

In the previous post, I showed how to retrieve the size of individual tables of a sql server database. In this post, I will show how to get the size of indexes in a sql server database. Here is the script that does that.

  1. USE AdventureWorks2012;
  2.  
  3. SELECT
  4.     ind.name              AS IndexName,
  5.     SUM(page_count * 8) AS IndexSizeKB,
  6.     SUM(page_count * 8) / 1024 as IndexSizeMB
  7. FROM sys.dm_db_index_physical_stats(
  8.     db_id(), object_id('dbo.TableName'), NULL, NULL, 'DETAILED') AS t
  9. JOIN sys.indexes AS ind
  10. ON t.[object_id] = ind.[object_id] AND t.index_id = ind.index_id
  11. GROUP BY ind.name
  12. ORDER BY IndexSizeKB DESC

 

The script looks up the sys.dm_db_index_physical_stats table and finds the page count and converts it to index size. Here's a screen shot of the result.

image

March 18, 2014

Size of Individual Tables in Sql Server

I recently created a sql server database which was huge and so I wanted to find out individual sizes of the tables. So, with the help of few suggestions on the internet I ended up writing a script that displays the size of individual tables in KB, MB and the number of rows those tables have.

Here’s the script that I wrote.

  1. SELECT
  2.     t.NAME AS TableName,
  3.     s.Name AS SchemaName,
  4.     p.rows AS RowCounts,
  5.     SUM(a.total_pages) * 8 AS TotalSpaceKB,
  6.     SUM(a.used_pages) * 8 AS UsedSpaceKB,
  7.     SUM(a.total_pages) * 8 / 1024 AS TotalSpaceMB,
  8.     SUM(a.used_pages) * 8 / 1024 AS UsedSpaceMB
  9. FROM
  10.     sys.tables t
  11.       INNER JOIN
  12.     sys.indexes i ON t.OBJECT_ID = i.object_id
  13. INNER JOIN
  14.     sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
  15. INNER JOIN
  16.     sys.allocation_units a ON p.partition_id = a.container_id
  17. LEFT OUTER JOIN
  18.     sys.schemas s ON t.schema_id = s.schema_id
  19. WHERE
  20.     t.NAME NOT LIKE 'dt%'
  21.     AND t.is_ms_shipped = 0
  22.     AND i.OBJECT_ID > 255
  23. GROUP BY
  24.     t.Name, s.Name, p.Rows
  25. ORDER BY
  26.     t.Name

 

And here is a screen shot of the results produced when run on Adventure Works database.

image

I have got an asp.net page with a number of anchor links pointing to different sections of the page. Now I problem is that since the page is an asp.net page and has buttons and / or possibly other controls that performs postbacks - the anchor position is lost during postbacks. Now this can be an irritating problem as I don't want my users having to click on the anchor link or to scroll to that location. Asp.net actually have an option to persist scroll locations during postbacks but though it works it has issues like bookmarking will not work.

To avoid the above problem, I have a simple solution that will persist the anchor and it requires the use of javascript and a hidden field to store the location of the anchor. I have couple of javascript functions - one that updates the anchor location in the hidden field and another one that set the hash property of window.location object to the value stored in the hidden field. The code is self explanatory, so I won't go into the details of explaining it. One thing to note is that I have a set the OnClientClick property of the button (or any control that postbacks) to javascript method that updates the hash / anchor location in the hidden field. Here is the code on how to achieve this.

  1. <asp:Button ID="b1" runat="server" OnClientClick="UpdateHash()" OnClick="b1_Click" />
  2. <asp:HiddenField ID="hf1" runat="server" />

 

JavaScript
  1.     <script type="text/javascript" src="http://code.jquery.com/jquery-1.6.min.js"></script>
  2. <script type="text/javascript">
  3.     function UpdateHash() {
  4.         $("#hf1").val(window.location.hash);
  5.     }
  6.  
  7.     function LoadHash() {
  8.         var hash = $("#hf1").val();
  9.         if (hash != "" && hash != "undefined") {
  10.             window.location.hash = hash;
  11.         }
  12.     }
  13.  
  14.     window.onload = LoadHash;
  15. </script>

March 15, 2014

Disable Browser Cache using IIS

In the previous post, I showed how to disable browser caching of a asp.net page and application using asp.net code. In this article, I will show how to disable caching using IIS. Again, note that, there should be a good enough reason to disable browser caching as it will impact performance for repeat visitors.

To disable caching, I will add the necessary caching directives in the response headers. To start with open IIS, select the site or the virtual directory and then click on “HTTP Response Headers” under IIS subheading.

 image

Then, from the Actions pane, click on Add. A prompt will open up. Type in the values and click OK.

image

Click Add again to enter the Pragma directive.

image

And Add another one for Expires.

image

The Response Headers section should appear like below now.

image

 

That’s it – caching will now be disabled for the application on the browser.

Disable Browser Cache in asp.net

So, I have an asp.net application and I want to disable browser caching. Well, to start with, we should have a good reason not to cache the application - caching is there for improving page loading speed. Okay, once there is a good enough reason to not to allow client side caching, we can do so by setting proper response headers in the page. These headers are

Cache-Control : no-cache
Cache-Control: s-maxage=0
Cache-Control : no-store
Cache-Control: must-revalidate
Expires : date time in the past

Now, we can either set these values either at the page level or at the application level. Doing it at the page level is easy - just run the code from the Page_Load event. Doing it at the application level is a bit difficult. If you are using the same master page for the whole site or have extended the Page class and created pages using the extended Page class then you can place the code in the appropriate Page_Load event. Note that, you can also set site / application wide response headers using IIS.

Here is the code to disable browser caching using asp.net.

  1. private void DisableCache()
  2. {
  3.     Response.Cache.SetCacheability(HttpCacheability.NoCache); //Cache-Control : no-cache, Pragma : no-cache
  4.     Response.Cache.SetExpires(DateTime.Now.AddDays(-1)); //Expires : date time
  5.     Response.Cache.SetNoStore(); //Cache-Control :  no-store
  6.     Response.Cache.SetProxyMaxAge(new TimeSpan(0, 0, 0)); //Cache-Control: s-maxage=0
  7.     Response.Cache.SetValidUntilExpires(false);
  8.     Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);//Cache-Control:  must-revalidate
  9. }

 

Here is the Response headers view in Firefox when the page is run.

image

March 11, 2014

I was working on a site with a few input fields and one of those would accept xml. When I ran the code, it failed with with the message "A Potentially dangerous Request.Form was detected." Usually, I would set ValidateRequest to false when these kind of errors occur and validate on the backend but I realised it does not work in .NET 4 anymore. Well, at least, not without changing the web.config file.

So, I added the following section (requestValidateMode) in web.config and ran the page and it worked fine.

  1. <system.web>
  2.   <compilation debug="false" targetFramework="4.0"/>
  3.   <httpRuntime requestValidationMode="2.0"/>
  4. </system.web>

Display raw XML in html page

I was working on a page where I had to display raw XML to an asp.net page and surprisingly it turned out to be quite challenging. Seriously, how hard can it be. I remember displaying xml by encoding it but that's not really an option in my scenario.

XML control – did not work

I tried using the  asp.net XML control but it did not work. The control renders xml without displaying the raw xml. I could see the xml displayed in the source code of the browser but it would not appear in the browser.

Label & Literal control – did not work

Then I tried using the Label and Literal control but it did not display any content from the xml. The xml appeared in the source code but the browser could not interpret it. However, the controls can display xml once the xml is encoded.

<Pre> , <code>html elements – did not work

Then I tried using the <pre> and <code> elements but there was no improvement. The browser still would not display the xml. The <pre> tag basically can display xml once it is encoded.

TextArea element – finally it worked

Finally, I used the textarea element and it worked.  The problem with textarea is that it is editable and it has other display features like border and resize options. Fortunately, these properties can be modified using css. So, here is the code to display xml in a textarea. I have used dummy xml for the snippet.

Front-end
  1. <!DOCTYPE html>
  2.  
  3. <html xmlns="http://www.w3.org/1999/xhtml">
  4. <head runat="server">
  5.     <title></title>
  6.     <style>
  7.         .tbox { width:80%; height:80px; border:0; overflow:visible; resize:none; outline:none; }
  8.     </style>
  9. </head>
  10. <body>
  11.     <form id="form1" runat="server">
  12.     <div>
  13.         <asp:TextBox ID="t1" runat="server" ReadOnly="true" CssClass="tbox" TextMode="MultiLine"></asp:TextBox>
  14.     </div>
  15.     </form>
  16. </body>
  17. </html>

 

And here is the back end code to get the xml.

Back end
  1. protected void Page_Load(object sender, EventArgs e)
  2. {
  3.     DisplayXml();
  4. }
  5.  
  6. private void DisplayXml()
  7. {
  8.     string xml = "<data><test id=\"1\">some text</test><test id=\"1\">some text</test><test id=\"1\">some text</test><test id=\"1\">some text</test><test id=\"1\">some text</test><test id=\"1\">some text</test><test id=\"1\">some text</test><test id=\"1\">some text</test><test id=\"1\">some text</test><test id=\"1\">some text</test><test id=\"1\">some text</test><test id=\"1\">some text</test><test id=\"1\">some text</test></data>";
  9.     t1.Text = xml;                   
  10. }

 

Now run the page and it should just work. With the height and width of the text area, set to something that is reasonable in your application.

March 6, 2014

Get Height & Width of Uploaded Image

I have an asp.net FileUpload control that is used to upload images and now I need to check the dimensions (height, width) of the image from code behind. So, how can I go about that.

To solve this problem, I can use the System.Drawing.Image class and System.IO.Stream class to get height and width of the image. To do so, let’s add the FileUpload control on designer.

<asp:FileUpload ID="fu1" runat="server" />

 

Next, on the code-behind, I have a method that retrieves the uploaded file stream, loads an image from the stream and then obtains the dimension of the image. Note that I have skipped validation for the image on the FileUpload control and have assumed that a valid image is uploaded.

Code Snippet
  1. private string GetImageDimension()
  2. {
  3.     System.IO.Stream stream = fu1.PostedFile.InputStream;
  4.     System.Drawing.Image image = System.Drawing.Image.FromStream(stream);
  5.  
  6.     int height = image.Height;
  7.     int width = image.Width;
  8.  
  9.     return "Height: " + height + "; Width: " + width;
  10. }

I am using Entity Framework Code First approach but I am receiving the error “The model backing the ‘ModelContext' context has changed since the database was created. Consider using Code First Migrations to update the database”. What does this mean?

Basically, the above error can occur when we have enabled and added a migration and updated a database and after that we have changed the model for the application. If the model has changed, Migrations process will need to be re-run before we can run the application. Read on Enable Migrations on how to use the Migrations in Code First Approach. At this stage, add a new Migration and update the database and then re-run adding the new update.

While using Code First Migrations, we can also add data to the database by using the Seed method in the Configuration.cs file. The Seed method contains the data context as the parameter and would initialise the data sets and use the SaveChanges method to save all the changes back to the database,

Here is the code for Seed method.

Configuration.cs
  1. protected override void Seed(MvcEntity.Models.EmployeeModelContext context)
  2. {
  3.     //  This method will be called after migrating to the latest version.
  4.  
  5.     //  You can use the DbSet<T>.AddOrUpdate() helper extension method
  6.     //  to avoid creating duplicate seed data.       
  7.  
  8.     var departments = new List<Department>
  9.     {
  10.         new Department{ DepartmentName="HR", StartDate=new DateTime(2010,4,1)},
  11.         new Department{ DepartmentName="IT", StartDate=new DateTime(2010,1,1)},
  12.         new Department{ DepartmentName="Sales", StartDate=new DateTime(2010,10,1)}
  13.     };
  14.  
  15.     var employees = new List<Employee>
  16.     {
  17.         new Employee{EmailAddress="john@hotmail.com", FirstName="John", LastName="Smith", DateJoined=new DateTime(2014,1,1)
  18.             , DepartmentId=departments.Single(d => d.DepartmentName == "HR").DepartmentId, IsActive=true},
  19.         new Employee{EmailAddress="ken@hotmail.com", FirstName="Ken", LastName="Marsh", DateJoined=new DateTime(2014,1,1)
  20.             , DepartmentId=departments.Single(d => d.DepartmentName == "IT").DepartmentId, IsActive=true},
  21.         new Employee{EmailAddress="shaun@hotmail.com", FirstName="Shaun", LastName="Lin", DateJoined=new DateTime(2014,1,1)
  22.             , DepartmentId=departments.Single(d => d.DepartmentName == "Sales").DepartmentId, IsActive=true},
  23.     };
  24.  
  25.     departments.ForEach(c => context.Departments.AddOrUpdate(d => d.DepartmentName, c));
  26.     employees.ForEach(c => context.Employees.AddOrUpdate(e => e.LastName, c));
  27.  
  28.     context.SaveChanges();
  29. }

 

In the method, I created 2 Lists of Employee and Department objects. Important to note how I set the DepartmentId on the Employee. The DepartmentId is not created as yet but I am querying to get the ids. Also, towards the end, I am calling the AddOrUpdate method that determines if the object has changed by checking for the specified property. For Department, I am checking for DepartmentName and for Employee, I am checking for LastName.

It’s important to note that when the migration is run first time, all data specified in the Seed method will be added. On subsequent migrations, only updated value will be updated or new values will be inserted.

The Code First approach allows for a feature called Migrations that allows the developer to keep a history of the changes to the model and allows the changes to be applied to the database. To enable migrations, few commands need to be applied from the  Package Manager Console.

To open Package Manager Console, go to Tools > NuGet Package Manager > Package Manager Console. Run the command “Enable-Migrations”. Alternatively, I can run “Enable-Migrations –EnableAutomaticMigrations”. The Automatic Migrations makes it easy as we do not need a code file for each change.  A folder called “Migrations” is created in the solution and it contains a Configuration.cs file and a datetime_MigrationName.cs file.  The Configuration class lets us configure how Migrations work for the context. We can leave the default for now. The other file contains the changes that will be deployed to the database.

image

The default implementation for the Configuration class is below. It’s important to note there is a Seed method that allows data to be entered in the database.

Configuration.cs
  1. namespace MvcEntity.Migrations
  2. {
  3.     using System;
  4.     using System.Data.Entity;
  5.     using System.Data.Entity.Migrations;
  6.     using System.Linq;
  7.  
  8.     internal sealed class Configuration : DbMigrationsConfiguration<MvcEntity.Models.EmployeeModelContext>
  9.     {
  10.         public Configuration()
  11.         {
  12.             AutomaticMigrationsEnabled = true;
  13.         }
  14.  
  15.         protected override void Seed(MvcEntity.Models.EmployeeModelContext context)
  16.         {
  17.             //  This method will be called after migrating to the latest version.
  18.  
  19.             //  You can use the DbSet<T>.AddOrUpdate() helper extension method
  20.             //  to avoid creating duplicate seed data. E.g.
  21.             //
  22.             //    context.People.AddOrUpdate(
  23.             //      p => p.FullName,
  24.             //      new Person { FullName = "Andrew Peters" },
  25.             //      new Person { FullName = "Brice Lambson" },
  26.             //      new Person { FullName = "Rowan Miller" }
  27.             //    );
  28.             //
  29.         }
  30.     }
  31. }

Once migrations is enabled, run the command “Add-Migration”. This will prompt for a name for the migration. Enter a name and hit Enter. This will scaffold the migration. For further changes to the model before deploying to the database, run the command “Add-Migration MigrationName”.

Finally run the command “Update-Database” and this will apply the changes. Here is a screen shot of how this would appear.

image

Reference: Shahed Kazi at AspNetify.com