2LeggedSpider

Coffee break

Posted in ASP.NET, Coffee Break, jquery, Microsoft, MVC by Sumit Thomas on March 2, 2012
Tagged with: , ,

Serializing a PartialView as JSON in ASP.NET MVC

Posted in ASP.NET by Sumit Thomas on November 5, 2009

[tweetmeme style=”compact”]In certain situations you might want to make an AJAX request to load a Partial View (UserControl) and display in a web page. It was quite easy to accomplish that using AJAX.NET Update Panels. Though jQuery doesn’t have any Update Panels of its own, it is quite easy to accomplish the same. In this post, I will try to make an AJAX request to fetch a UserControl as JSON and display it on the screen. Alright, so follow me…

1) Create a Partial View name PostList as follows…

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Post>>" %>
<table border="0" width="100%">
    <thead>
        <tr>
            <th>
                Post ID
            </th>
            <th>
                Title
            </th>
            <th>
                Description
            </th>
            <th>
                Created On
            </th>
        </tr>
    </thead>
    <tbody>
        <%foreach (MyMVCTrials.Models.Post p in Model)
          { %>
        <tr>
            <td>
                <%=p.PostID.ToString() %>
            </td>
            <td>
                <%=p.Title %>
            </td>
            <td>
                <%=p.Description %>
            </td>
            <td>
                <%=p.CreatedOn %>
            </td>
        </tr>
        <%} %>
    </tbody>
</table>

2) Create a Entity class named Post as follows…

    public class Post
    {
        public int PostID { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public string CreatedOn { get; set; }
    }

3) Create a private method in the Controller class, say PostController, to prepare a List of Posts and return it.

        private IList<Post> GetPosts()
        {
            IList<Post> posts = new List<Post>();

            for (int i = 1; i <= 10; i++)
            {
                Post post = new Post();
                post.PostID = i;
                post.Title = String.Format("My Post Title #{0}", i.ToString());
                post.Description = String.Format("My Description {0}", i.ToString());
                post.CreatedOn = DateTime.Now.ToLongDateString();
                posts.Add(post);
            }
            return posts;
        }

4) Create a private method in your Controller which will execute the PartialView and return a JSON string of the view.

        private JsonResult SerializeControl(string controlPath, object model)
        {
            ViewPage page = new ViewPage();
            ViewUserControl ctl = (ViewUserControl)page.LoadControl(controlPath);
            page.Controls.Add(ctl);
            page.ViewData.Model = model;
            page.ViewContext = new ViewContext();
            System.IO.StringWriter writer = new System.IO.StringWriter();
            System.Web.HttpContext.Current.Server.Execute(page, writer, false);
            string outputToReturn = writer.ToString();
            writer.Close();
            return this.Json(outputToReturn.Trim());
        }

5) Create the following Action Methods in your Controller

        //Returns the View that will display the List of Posts based on an AJAX call.
        public ActionResult Index()
        {
            return View();
        }

        //Returns the serialized JSON string of the partial view, PostList
        public JsonResult PostList()
        {
            System.Threading.Thread.Sleep(3000);
            return SerializeControl("~/Views/Shared/PostList.ascx", GetPosts());
        }

6) And finally, in our Index View Page, add the following…

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<script type="text/javascript">
    $(document).ready(function() {
        $("#loadPosts").click(function() {
            $("#postList").html("Loading Posts....");
            $.getJSON("/Home/PostList", function(data) {
                if (data) {
                    $("#postList").html(data);
                }
            });

        });
    });
</script>

<input type="button" id="loadPosts" value="Load Posts!" />
<div id="postList" />
</asp:Content>

When you run the application, here is how it will look like…

On clicking the button
Loading Posts

Final result!
Posts Loaded

Scott Hanselman talks about MVC 1.0 and NerdDinner.com at Mix09

Posted in ASP.NET, ASPNETMVC, C#, Microsoft, SQL by Sumit Thomas on March 22, 2009

A really great presentation by Scott Hanselman demonstrating how he created NerdDinner.com using MVC 1.0. In this 70 minutes presentation, Scott demonstrates how we can build a real Web site with ASP.NET, ASP.NET AJAX, Authentication, Authorization, MVC, Microsoft SQL Server and jQuery. Long video, but really worth it.

CodePlex Project: http://nerddinner.codeplex.com

Tagged with: , ,

QSF7QCCHZC4Q

Posted in ASP.NET by Sumit Thomas on December 17, 2007

Upload files to UNC share using ASP.NET

Posted in ASP.NET, C# by Sumit Thomas on May 28, 2007

[tweetmeme style=”compact”]SCENARIO 1: Your ASP.NET website should upload files to a File Server accessible via an UNC share

SOLUTION

  1. Create a Local User Account in the Web server with Username say “TestUser” and Password say “Secret” of your choice
  2. Create a Local User Account in File server with the same Username “TestUser” and Password “Secret” as the one created in the Web server.
  3. In Web.config set the impersonation to true for the above Local User Account as follows…
    
    

    And your upload script will be something like this…

                    if ((FileUpload1.PostedFile != null) &amp;&amp; (FileUpload1.PostedFile.ContentLength &gt; 0))
                    {
                        string fileName = System.IO.Path.GetFileName(FileUpload1.PostedFile.FileName);
                        string folderPath = @"\\MyUNCShare\MyFolder\";
    
                        string locationToSave = folderPath + "\\" + fileName ;
                        try
                        {
                            FileUpload1.PostedFile.SaveAs(locationToSave );
                            Response.Write("The file has been uploaded.");
                        }
                        catch (Exception ex)
                        {
                            Response.Write("Error: " + ex.Message);
                        }
                    }
                    else
                    {
                        Response.Write("Please select a file to upload.");
                    }
    
    

    Run the code and test the upload and it should work.

    SCENARIO 2:
    Now this is fine for a demo. But what if I want to setup Windows authentication for my application but restrict the authenticated users of the application from directly accessing the UNC share to copy files? Any uploads to the UNC share should be done only using the Local User Account that I created earlier.

    To solve this issue do the following…

    1) Change the identity impersonate tag in Web.config to

    <identity impersonate="true" />

    , assuming that you have enabled Windows authentication in IIS as well.

    2) Change the impersonation at runtime to the Local User Account, upload the file and then undo the impersonation. To do this use the following code…

    
    using System.Security.Principal;
    using System.Runtime.InteropServices;
    
    namespace FileUploadUNCShare
    {
        public partial class _Default : System.Web.UI.Page
        {
    
            public const int LOGON32_LOGON_INTERACTIVE = 2;
            public const int LOGON32_PROVIDER_DEFAULT = 0;
    
            WindowsImpersonationContext impersonationContext;
    
            [DllImport("advapi32.dll")]
            public static extern int LogonUserA(String lpszUserName,
                String lpszDomain,
                String lpszPassword,
                int dwLogonType,
                int dwLogonProvider,
                ref IntPtr phToken);
            [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern int DuplicateToken(IntPtr hToken,
                int impersonationLevel,
                ref IntPtr hNewToken);
    
            [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern bool RevertToSelf();
    
            [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
            public static extern bool CloseHandle(IntPtr handle);
    
            private bool ImpersonateUser(String userName, String domain, String password)
            {
                WindowsIdentity tempWindowsIdentity;
                IntPtr token = IntPtr.Zero;
                IntPtr tokenDuplicate = IntPtr.Zero;
    
                if (RevertToSelf())
                {
                    if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
                        LOGON32_PROVIDER_DEFAULT, ref token) != 0)
                    {
                        if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                        {
                            tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                            impersonationContext = tempWindowsIdentity.Impersonate();
                            if (impersonationContext != null)
                            {
                                CloseHandle(token);
                                CloseHandle(tokenDuplicate);
                                return true;
                            }
                        }
                    }
                }
                if (token != IntPtr.Zero)
                    CloseHandle(token);
                if (tokenDuplicate != IntPtr.Zero)
                    CloseHandle(tokenDuplicate);
                return false;
            }
    
            private void UndoImpersonation()
            {
                impersonationContext.Undo();
            }
    
            protected void Page_Load(object sender, EventArgs e)
            {
    
            }
    
            protected void Button1_Click(object sender, EventArgs e)
            {
                if (ImpersonateUser("Test_Share", "", "@Dell123"))
                {
    
                    if ((FileUpload1.PostedFile != null) &amp;&amp; (FileUpload1.PostedFile.ContentLength &gt; 0))
                    {
                        string fileName = System.IO.Path.GetFileName(FileUpload1.PostedFile.FileName);
                        string folderPath = @"\\MyUNCShare\MyFolder\";
    
                        string locationToSave = folderPath + "\\" + fileName;
                        try
                        {
                            FileUpload1.PostedFile.SaveAs(locationToSave);
                            Response.Write("The file has been uploaded.");
                        }
                        catch (Exception ex)
                        {
                            Response.Write("Error: " + ex.Message);
                        }
                    }
                    else
                    {
                        Response.Write("Please select a file to upload.");
                    }
    
                    UndoImpersonation();
                }
                else
                {
                    Response.Write("Failed");
                }
    
            }
        }
    }
    

    This will ensure that the impersonation you need to upload the file does not interfere with the Application level impersonation you may want to use.

    Hope it is useful!

    Cheers!

    ref: http://support.microsoft.com/kb/306158

Tagged with: , ,

Container-Managed Persistence

Posted in ASP.NET, C# by Sumit Thomas on February 28, 2006

[tweetmeme style=”compact”]The most fascinating part in developing ASP.NET applications for me is how you can leverage different design models relatively easily, compared to other platforms. Coming from a ASP background, I was excited when I created my first 3-tier application in ASP.NET. I’ve been interested in architectures ever since. The n-tier architecture adopted in most of the Microsoft’s sample applications such as IBuySpy, is one of the commonly used models and I’ve used it successfully in my applications. It is what we call a Component-Managed Persistence model, where the component needs to know how to make calls to the persistence layer such as SQL Server and also what are the parameters required for a transaction with the persistence layer. So in a sense the business layer is tightly coupled with the under lying persistence layer.

I came across this book “ASP.NET E-commerce Programming: Problem – Design – Solution” by Kevin Hoffman a long time back. Though I bought the book, i really didn’t understand the Container-Managed Persistence model described in the book. I had tough time trying to download the code associated with the book as the book was no longer supported on www.wrox.com. Anyway, I managed to download the code after several hours of surfing and googling the web. I spent a lot od time trying to understand how the architecture works and I finally managed to understand how brilliant it is. I was however surprised to find that there ain’t much reviews or talk about this book anywhere. Anyway, I would like to thank Kevin Hoffman for this wonderful book.

So what is Container-Managed Persistence?

Quoting from the book: “Container-Managed Persistence is a design pattern whereby business objects have no direct knowledge of where their data came from and how it will be persisted” The business objects are pure business objects and are never tighly coupled with any persistence layer.

After trying several sample applications with the CMPServices library and the associated libraries that formed the part of the architecture, there was one issue that I wasn’t comfortable with in the CMPServices library. The PersistableObjectSet.cs class uses an internal DataSet for handling the resultset from the database. Now, I being a strong advocate of using DataReaders in ASP.NET application was not really comfortable with it. So, I decided to try my hands on tweaking the CMPServices library to make DataReader as the default data handling object and also provide the developer with an option to choose the data object – DataSet, DataTable or DataReader he/she wants to use in the application.

I made few additions to the CMPServices library to achieve what I said. Now to start off I created an Enum CMPDataObjectType as follows

public enum CMPDataObjectType
	{
		/// 
		/// DataSet
		/// 
		DataSet = 1,
		/// 
		/// DataTable
		/// 
		DataTable = 2,
		/// 
		/// DataReader
		/// 
		DataReader = 3
	}

The enum has three fields, representing the Data object types that we are going to support in the CMPServices library. The actual PerisistableObjectSet class in the CMPServices library is as follows

public class PersistableObjectSet : PersistableObject
	{
		protected DataSet internalData;

		public PersistableObjectSet()
		{
			internalData = new DataSet();	
		}

		public virtual void FinalizeData()
		{
			PersistableObjectSet.FinalizeData( internalData );
		}

		public static void FinalizeData(DataSet scratchData )
		{

		}

		public DataSet ResultSet
		{
			get 
			{
				return internalData;
			}
			set 
			{
				internalData = value;
			}
		}
	}

As you can see it has an internal DataSet which is used to hold the records returned from the database. Now we need to add support for DataReader and DataTable in this class. So I modified the class as follows

public class PersistableObjectSet : PersistableObject
	{

		/// 
		/// The internal DataSet of the PersistableObjectSet
		/// 
		protected DataSet objectDataSet;
		/// 
		/// The internal DataReader of the PersistableObjectSet
		/// 
		protected IDataReader objectDataReader;
		/// 
		/// The internal DataTable of the PersistableObjectSet
		/// 
		protected DataTable objectDataTable;

		/// 
		/// CMPDataObjectType
		/// 
		protected CMPDataObjectType cmpDataObjectType;

		/// 
		/// Default constructor
		/// 
		public PersistableObjectSet()
		{
			
		}

		/// 
		/// Gets/Sets the value of the internal DataSet of the PersistableObjectSet
		/// 
		public DataSet DataSet
		{
			get
			{
				return objectDataSet;
			}
			set
			{
				objectDataSet = value;
			}
		}

		/// 
		/// Gets/Sets the value of the internal DataReader of the PersistableObjectSet
		/// 
		public IDataReader DataReader
		{
			get
			{
				return objectDataReader;
			}
			set
			{
				objectDataReader = value;
			}
		}


		/// 
		/// Gets/Sets the value of the internal DataTable of the PersistableObjectSet
		/// 
		public DataTable DataTable
		{
			get
			{
				return objectDataTable;
			}
			set
			{
				objectDataTable = value;
			}
		}

		/// 
		/// The CMPDataObjectType refers to the Datatype that will be used for Data retrieval.
		/// There are 3 CMPDataObjectTypes - DataSet, DataTable and DataReader.
		/// DataReader is the default one and it is recommended to use it for any kind of data retrieval.
		/// DataTable and DataSet must be used only for special data maniuplations.
		/// DataSet should be used only for special requirements like serialization/deserialization, caching etc.
		/// 
		public CMPDataObjectType DataObjectType
		{
			get
			{
				if( cmpDataObjectType == 0 )
				{
					cmpDataObjectType = CMPDataObjectType.DataReader;
				}
				return cmpDataObjectType;
			}
			set
			{
				cmpDataObjectType = value;
			}
		}

		/// 
		/// This method provides a format for child classes to implement data manipulation methods.
		/// If any additional work needs to be done on the retrieved data, this method can be 
		/// implemented as a standard place for data finalisation to take place.
		/// 
		/// If you are using a DataReader you SHOULD call this method in your business logic to
		/// close the Connection object.
		/// 
		public virtual void FinaliseData()
		{
			if( cmpDataObjectType == CMPDataObjectType.DataSet )
			{
				PersistableObjectSet.FinaliseData( objectDataSet );
			}
			else if( cmpDataObjectType == CMPDataObjectType.DataReader )
			{
				PersistableObjectSet.FinaliseData( objectDataReader );
			}
			else if( cmpDataObjectType == CMPDataObjectType.DataTable )
			{
				PersistableObjectSet.FinaliseData( objectDataTable );
			}
		}

		/// 
		/// This method is called by the FinaliseData() overload in the business logic to do
		/// any additional work with the DataSet. 
		/// 
		/// DataSet
		public static void FinaliseData( DataSet tempData )
		{
			tempData.Dispose();
		}

		/// 
		/// This method is called by the FinaliseData() overload in the business logic to do
		/// any additional work with the DataTable. 
		/// 
		/// DataTable
		public static void FinaliseData( DataTable tempData )
		{
			tempData.Dispose();
		}

		/// 
		/// This method is called by the FinaliseData() overload in the business logic to do
		/// any additional work with the DataReader. 
		/// 
		/// IDataReader/SqlDataReader
		public static void FinaliseData( IDataReader tempData )
		{
			tempData.Close();
			tempData.Dispose();
		}

	}

So basically I have added a property DataObjectType which is used to set the type of data object we are going to use. By default it is DataReader. Each data types will have their own FinaliseData method. For the DataReader we make sure that the object is closed in order to close its connection object.

We also need to do couple of changes to the SqlPersistenceContainer class, as we now have three types of data object types to handle.

Since we use the data object only while retrieving the data, we modify the Select method as follows

		/// 
		/// This method performs the Select operation. It executes a stored procedure and places any return or output values
		/// back onto the instance of the PersistableObject that was provided. If the object instance can be cast to a PersistableObjectSet, then the
		/// container will attempt to assign the output or return value to a Data object within the PersistableObjectSet.
		/// 
		/// Persistable object
		public override void Select( PersistableObject selectObject )
		{
			try
			{
				CommandMapping commandMap	= containerMap.SelectCommand;
				SqlCommand selectCommand	= BuildCommandFromMapping( commandMap );
				AssignValuesToParameters( commandMap, ref selectCommand, selectObject );
				if(selectCommand.Connection.State == ConnectionState.Closed)
					selectCommand.Connection.Open();

				if( selectObject is PersistableObjectSet )
				{
					PersistableObjectSet objectSet = (PersistableObjectSet)selectObject;
					
					AssignResultSetToObjectSet( commandMap, selectCommand, ref selectObject );
					AssignOutputValuesToInstance( commandMap, selectCommand, ref selectObject );
					//selectCommand.Connection.Close();
				}
				else
				{
					selectCommand.ExecuteNonQuery();
					selectCommand.Connection.Close();
					AssignOutputValuesToInstance( commandMap, selectCommand, ref selectObject );
				}
				//selectCommand.Connection.Dispose();
				//selectCommand.Dispose();
			}
			catch (Exception dbException)
			{
				throw new Exception("Persistance (Select) Failed for PersistableObject", dbException );
			}
		}

We have remaned AssignResultSetToDataSet to AssignResultSetToObjectSet to give it a more generic name. The AssignResultSetToObjectSet method is as follows

private void AssignResultSetToObjectSet( CommandMapping commandMap, SqlCommand sqlCommand, ref PersistableObject persistObject )
		{
			SqlDataAdapter sqlDa = null;
			PersistableObjectSet objectSet = (PersistableObjectSet)persistObject;
			if( objectSet.DataObjectType == CMPDataObjectType.DataSet )
			{
				sqlDa = new SqlDataAdapter( sqlCommand );
				objectSet.DataSet = new DataSet();
				sqlDa.Fill ( objectSet.DataSet );
				sqlCommand.Connection.Close();
				sqlCommand.Connection.Dispose();
				sqlCommand.Dispose();
			}
			else if( objectSet.DataObjectType == CMPDataObjectType.DataReader )
			{
				SqlDataReader objReader = sqlCommand.ExecuteReader( CommandBehavior.CloseConnection );
				objectSet.DataReader = objReader;
			}
			else if( objectSet.DataObjectType == CMPDataObjectType.DataTable )
			{
				sqlDa = new SqlDataAdapter( sqlCommand );
				objectSet.DataTable = new DataTable();
				sqlDa.Fill ( objectSet.DataTable );
				sqlCommand.Connection.Close();
				sqlCommand.Connection.Dispose();
				sqlCommand.Dispose();
			}
		}

We create the instance of the select data object type and fetch the data using it. So, thats all the changes we do to the CMPServices library.

Now lets see how we use it. I created a simple contacts management application and here is a sample of a function in the Business layer. Since I am sure I am not going to change the underlying datasource, I populate the data to a strongly-typed collection object which I will then use in my presentation layer. I have a function called GetContacts and I have three versions of the function to support the data object type under consideration.

For DataReader (default)

public static Contacts GetContacts()
            {
                  SqlPersistenceContainer spc = new SqlPersistenceContainer( CMPConfigurationHandler.ContainerMaps["SherstonContacts"] );
                  ContactSet contactSet         = new ContactSet();

                  spc.Select( contactSet );

                  Contacts contactList         = new Contacts();

                  while( contactSet.DataReader.Read() )
                  {
                        IDataReader row               = contactSet.DataReader;
                        Contact contact               = new Contact();
                        contact.ContactId             = Convert.ToInt32( row["ContactId"] );
                        contact.ContactName           = row["ContactName"].ToString();
                        contact.Email                 = row["Email"].ToString();

                        contactList.Add( contact );
                  }

                  ///It is imperative that you call the FinaliseData method for DataReader as this will
                  ///automatically close it’s connection object. Note that it is called after the DataReader's values
                  ///are retrieved as DataReader's require the connection object to be open unlike DataSet/DataTable.

                  contactSet.FinaliseData();
                  return contactList;
            }

For DataSet

	    public static Contacts GetContacts()
            {
                  SqlPersistenceContainer spc = new SqlPersistenceContainer( CMPConfigurationHandler.ContainerMaps["SherstonContacts"] );
                  ContactSet contactSet         = new ContactSet();

                  //Setting the DataObjectType of the contactSet object to DataSet
                  contactSet.DataObjectType     = CMPDataObjectType.DataSet;

                  spc.Select( contactSet );

                  Contacts contactList         = new Contacts();

                  ///For DataSet and DataTable the FinaliseData method should be called before extracting the values
                  ///as the manipulation with the data would have occured if there is an overriden FinaliseData method 
                  ///in the ContactSet class

                  contactSet.FinaliseData();

                  foreach( DataRow row in contactSet.DataSet.Tables[0].Rows )
                  {
                        Contact contact               = new Contact();
                        contact.ContactId             = Convert.ToInt32( row["ContactId"] );
                        contact.ContactName           = row["ContactName"].ToString();
                        contact.Email                 = row["Email"].ToString();

	                contactList.Add( contact );
                  }

                  return contactList;
            }

For DataTable

	  public static Contacts GetContacts()
         {
                 SqlPersistenceContainer spc = new SqlPersistenceContainer( CMPConfigurationHandler.ContainerMaps["SherstonContacts"] );
                  ContactSet contactSet         = new ContactSet();

                  //Setting the DataObjectType of the contactSet object to DataTable
                  contactSet.DataObjectType     = CMPDataObjectType.DataTable;

                  spc.Select( contactSet );

                  Contacts contactList         = new Contacts();


                  ///For DataSet and DataTable the FinaliseData method should be called before extracting the values
                  ///as the manipulation with the data would have occured if there is an overriden FinaliseData method 
                  ///in the ContactSet class

                  contactSet.FinaliseData();

                  foreach( DataRow row in contactSet.DataTable.Rows )
                  {
                        Contact contact               = new Contact();
                        contact.ContactId             = Convert.ToInt32( row["ContactId"] );
                        contact.ContactName           = row["ContactName"].ToString();
                        contact.Email                 = row["Email"].ToString();

                        contactList.Add( contact );
                  }

                  return contactList;

            }

So here it is a modified CMPServices library with support for DataReader and DataTable 🙂

Technorati: , ,

Displaying RSS feeds in ASP.NET

Posted in ASP.NET by Sumit Thomas on February 22, 2006

[tweetmeme style=”compact”]The XML control is one of the least used controls in ASP.NET. To be honest I haven’t used it much myself. I combined my little knowledge in XSL with the XML control to create a simple RSS reader. Here is the code for the WebForm

.rssContainer
{
border: 1px dotted #000000;
padding: 3px;
font-family: Arial, Verdana, Geneva;
font-size: 11px;
width: 100%;
}
#header
{
background-color: #f7f7f7;
border: 1px solid #000000;
}
#header h2
{
color: #333333;
}
#header .description
{
font-size: 14px;
font-weight: bold;
}



void Page_Load(object source, System.EventArgs e)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("https://2leggedspider.wordpress.com/feed/");
rssFeed.Document = xmlDoc;
rssFeed.TransformSource = rss.xsl;
}




    
    
    



The code as you can see is very simple. We create a XmlDocument object and open the feed using it. Then we pass the document to the XML control. You would also notice that we are passing an XSL source to the XML control through it’s TransformSource property. The XSL does all the formatting of the feed data. Lets look at the XSL code now.








<table class="rssContainer">
<tr>
<td>
<h2>
<a href="{link}" target="_blank">
</a>
</h2>
<div class="description">
</div>
</td>
</tr>
<tr>
<td>

</td>
</tr>
</table>


<a href="{link}" target="_blank"></a>  - 
  

<br /><i>
</i>
<hr />




The XSL code is pretty simple as you can see. Well I definetely will consider this option when I need to display any kind of XML content again.

Technorati: , ,
Tagged with: ,

Edit Web.config at run-time

Posted in ASP.NET, C# by Sumit Thomas on February 21, 2006

[tweetmeme style=”compact”]I had an argument with one of my friends recently on his statement that Web.config cannot be edited at run-time. My counter statement was if it is a XML file and if you have write permission on it then you can do it. Here is the code to do the same…

public class ConfigManager
{
 //The file path of Web.config
 static string configFilePath =
 HttpContext.Current.Server.MapPath("~/web.config");
  
 /// Returns the Web.config as XmlDocument
 private static XmlDocument GetWebConfig()
 {
 XmlDocument xmlDoc = new XmlDocument();
 xmlDoc.Load( configFilePath );
 return xmlDoc;
 }

 /// Checks for the appSettings node in Web.config
 /// Updates the value for the given key if the key
 /// already exists or creates a new node for the
 /// given key and value combination if it is not present
 public static void CreateAppSetting( string key, string val )
 {
 XmlDocument xmlDoc = GetWebConfig();
 XmlNode xmlNode = xmlDoc.SelectSingleNode("//appSettings");
   
 if( xmlNode == null )
 {
  throw new Exception("appSettings node not found!");
 }

 string nodeFormat = string.Format("//add[@key='{0}']", key) );

 XmlElement xmlElement =
( (XmlElement) xmlNode.SelectSingleNode( nodeFormat );
 try
 {   
  if( xmlElement != null )
  {
   xmlElement.SetAttribute( "value", val );
  }
  else
  {
   xmlElement = xmlDoc.CreateElement( "add" );
   xmlElement.SetAttribute( "key", key );
   xmlElement.SetAttribute( "value", val );
   xmlNode.AppendChild( xmlElement );
  }
  SaveWebConfig( xmlDoc );
 }
 catch( Exception ex )
 {
  throw new Exception( ex.Message );
 }

 }

 /// Saves the changes to the Web.config file
 private static void SaveWebConfig( XmlDocument xmlDoc )
 {
  try
  {
  XmlTextWriter writer =
 new XmlTextWriter( configFilePath, null );
  writer.Formatting = Formatting.Indented;
  xmlDoc.WriteTo( writer );
  writer.Flush();
  writer.Close();
  }
  catch( Exception ex )
  {
  throw new Exception( ex.Message );
  }
 }
}//end of class

The application should have required permissions on Web.config to edit it, otherwise the code will throw an access denied error.

Technorati: , ,
Tagged with: ,

DataSet or DataReader?

Posted in ASP.NET, C# by Sumit Thomas on February 14, 2005

I’ve been developing websites in ASP.NET for quite a while now. During my initial projects in ASP.NET I like many others liberally used DataSets whenever possible and hardly went for DataReaders. Now the reason I didn’t prefer DataReaders was because i often forget to close it’s connection object and then I receive a “all pooled connections were in use and max pool size was reached…” error from the SQL Server after some trial runs. Silly reason uh! Now, I know why the error occured but the lazy me wanted a option where I don’t have to worry about these issues.

Then one fine day I felt an invisible slap on my head and I began to seriously consider best practices, performance, robust architecure etc.. seriously. I guess my old programming habits in ASP were reluctant to let me go. But something unusual happened, I won!

Now back to the real issue. DataSets are really powerful and easy to use. But when it comes to developing performant websites, DataSets should never be an option. DataReaders are fast and I mean really fast when compared to a DataSet or for that matter a DataTable. Eventhough DataReaders are fast, there was one fact which worried me. DataReaders need a open connection object while retrieving data. Now would it be a problem if I try to read a large number of records, say more than 10,000 using a DataReader as it needs the open connection to execute? Well, yes if you don’t close the connection object as soon as you are done with it.

I came across this link A Speed Freak’s Guide to Retrieving Data in ADO.NET by Craig Davis and it clearly explains the advantage of using DataReader over DataSet or DataTable. But are DataSets a complete no no when it comes to ASP.NET? Well not really. If you have checked the IBuySpy portal’s architecure, the use of strongly-typed DataSet makes a lot of sense. Since the data is cached most of the time and rarely updated, the performance issue is not really a huge threat. More over it is more easier to handle the large XML file that defines the portals structure using the strongly-typed DataSet.

So does that mean that as long as you cache the DataSet it is fine to use them? Well I would still go for DataReaders. You cannot cache a DataReader object but you can cache the data you receive from DataReader. We can create a class with public properties that mirrors the table structure, iterate  through the records in the DataReader, populate the relevant data to the object instance of the custom class and then add it preferably to a strongly-type collection or an ArrayList, which can be cached. Obviously we need to enter few extra lines of code to do this but its worth the effort as we have performance in mind.

DataReaders should therefore be the first choice when it comes to data access in ASP.NET. DataSets could be used if you don’t worry about the performance factor or if there is situation where DataSet is the only option, which in my opinion is very unlikely.

Technorati: , ,

Generating a dynamic bar graph using ASP.NET and C#

Posted in ASP.NET, C# by Sumit Thomas on November 21, 2004

[tweetmeme style=”compact”]Back in the days of ASP, web developers had to rely on third party components to dynamically create images on a web page. In ASP, we would use colored tables to display a bar graph. But wouldn’t it be great if we could generate a dynamic graph by ourselves instead of relying on some third-party components. Well, the .NET framework allows us to do just that and more.

Consider a scenario where we had to display a graph representing the sales of a company from say 2000-2004. We need to generate a dynamic bar graph using the data provided to us. Let me take you through the step-by-step process to accomplish the task.

I am using Notepad and .NET framework 1.0. Why notepad? Well, I believe it’s the best way to learn .NET or for that matter any programming language and also the code is very clean.

The two classes, which we need to generate images on the fly, are System.Drawing.Bitmap and System.Drawing.Graphics. The Bitmap class is used to represent an instance of an image and the Graphics class can be used to draw lines, curves and other geometric shapes.

Be sure to check about these two classes and their methods from http://msdn.microsoft.com

So lets get started. Open Notepad and type the following two lines



We will be using these two namespaces in our application.

The method we will write to generate the graph is called ‘GenerateBarGraph’

The initial structure of the code will look like this


Bar graph generated using ASP.NET and C#


protected void GenerateBarGraph(
string graphTitle,
ArrayList xValues,
ArrayList yValues,
int barWidth,
int barSpaceWidth,
int graphHeight)
{
//Our code to generate bar graph will come here
}
private void Page_Load(object sender, System.EventArgs e)
{

}


<img src="" />


The parameters passed to the GenerateBarGraph method are as follows

graphTitle : The title of the graph
xValues : The values in the x-axis
yValues : The values in the y-axis
barWidth : The width of each bar
barSpaceWidth : The space between each bars
graphHeight : The height of the graph(excluding the title and x-values)

Change the GenerateBarGraph method as follows

protected void GenerateBarGraph(
string graphTitle,
ArrayList xValues,
ArrayList yValues,
int barWidth,
int barSpaceWidth,
int graphHeight)
{
int graphTitleHeight=20; // Height in pixels utilized by the title in the graph
int itemsHeight=35; // Height in pixels utilized by the items in the x-axis

/*
The Graph’s width is calculated by adding the width of a bar and the space between
two bars multiplied by the total values in the x-axis plus the space between two bars
*/
int graphWidth= (barWidth + barSpaceWidth) * xValues.Count + barSpaceWidth;

/*
The maximum height that a bar can attain needs to be found from the y-values passed
as parameter
*/
int maxBarHeight=0;

//Total height of the image is calculated
int totalGraphHeight = graphHeight + graphTitleHeight + itemsHeight;

//Create an instance of Bitmap class with the given width and height
Bitmap barBitmap=new Bitmap(graphWidth, totalGraphHeight);

/*
Graphics class does not have a constructor and hence we call its static method
FromImage and pass the Bitmap object to it
*/
Graphics barGraphics= Graphics.FromImage(barBitmap);

/*
Using the Graphics object we fill the image of given dimensions with light gray color
*/

barGraphics.FillRectangle(
new SolidBrush(Color.WhiteSmoke),
0,
0,
graphWidth,
totalGraphHeight);

/*
We create an instance of Font class available in System.Drawing. We will be using this
to display the title of the graph.
*/
Font titleFont=new Font("Verdana",14, FontStyle.Bold);

/*
Use the Graphics object’s DrawString method to draw the title at the specified location
*/
barGraphics.DrawString(
graphTitle,
titleFont,
new SolidBrush(Color.Red),
(graphWidth / 2) - graphTitle.Length * 5,
totalGraphHeight - itemsHeight);


//////////////Code to generate bars will come here/////////////////

/*
Save the image to the web server’s D: drive. We use the PNG format to make it look
crisp.
*/
barBitmap.Save("D:\\bargraph.png",ImageFormat.Png);

//Dispose off the Graphics and Bitmap objects
barGraphics.Dispose();
barBitmap.Dispose();
}

Change the Page_Load method as follows

private void Page_Load(object sender, System.EventArgs e)
{
ArrayList _years=new ArrayList();
_years.Add("2000");
_years.Add("2001");
_years.Add("2002");
_years.Add("2003");
_years.Add("2004");

ArrayList _sales=new ArrayList();
_sales.Add(270500);
_sales.Add(211930);
_sales.Add(223300);
_sales.Add(343000);
_sales.Add(424750);

GenerateBarGraph("ABC Ltd. Sales (2000-2004)",_years, _sales, 50, 25, 400);
}

Change the source of the IMG tag used in our aspx page as follows

<img />

Now, if you run this page you will see an image displayed on the browser with the title “ABC Ltd. Sales (2000-2004)” displayed in red at the bottom

If you notice in the Page_Load method, we have passed two ArrayLists to the GenerateBarGraph method and also the other previously mentioned parameters. We will be using these two ArrayLists to display the bars.

Now replace //////////////Code to generate bars will come here///////////////// in GenerateBarGraph method with the following code.

/*
Find the highest value in the yValues ArrayList and set it as the maximum height of the bar
*/
foreach(int _value in yValues)
if(_value > maxBarHeight) maxBarHeight=_value;

//barXPos will store the x position of a bar
int barXPos = barSpaceWidth;
int barHeight;

Font itemsFont=new Font("Verdana",9, FontStyle.Bold);
Font valuesFont=new Font("Verdana", 7, FontStyle.Italic);

Random rnd=new Random();

for(int i=0;i  Gives the bar height in percentage with respect to
the maximum bar height set by us

((((int)yValues[i]* 100 / maxBarHeight) )* graphHeight)/100 will give the bar height in
pixels
*/
barHeight=((((int)yValues[i]* 100 / maxBarHeight) )* graphHeight)/100;

//Draw the bar with the set brush, x and y positions, width and height
barGraphics.FillRectangle(
barBrush,
barXPos,
graphHeight-barHeight,
barWidth,
barHeight);

//Draw the x-value along the x-axis
barGraphics.DrawString(
xValues[i].ToString(),
itemsFont,
barBrush,
barXPos,
graphHeight);

//Draw the respective y value on top of the bar
barGraphics.DrawString(
yValues[i].ToString(),
valuesFont,
barBrush,
barXPos,
(graphHeight-barHeight)-itemsHeight);

//Change the x position of the next bar
barXPos += (barWidth + barSpaceWidth);
}

If you now run the aspx page you will notice the bar graph representing the sales of a company from 2000-2004. If you refresh the page you will see that each bar will have a new color.

The Graphics API provided by the .NET framework is very extensive and what we have seen gives us a useful startup. Do take time to understand the classes and its methods used in this article.

Technorati: , ,
Tagged with: , ,