Saturday, September 18, 2010

View state in ASP.NET

In my last post, I explained the life cycle of a page in ASP.NET. My main purpose was to explain how view state relates to page's life cycle. What is view state supposed to do? View state is responsible for persisiting state of an ASP.NET page and its controls across postbacks. Some developers might think they need to store every state data related to a control in view state. This is not true. For example, the properties that have been declared in the HTML source of the page, do not need to be persisted across postbacks. If your recall from my last post, in page's life cycle, the first stage is instantiation which builds up the control hierarchy. It's where the properties that are defined declaratively, will be assigned to the control in the control hierarchy. Thus, developers do not need to persist such properties. What needs to be persisted in view state is the state that changes programmatically. For instance, if the state of a control is changed in a Button control's click event, it will need to be persisted in view state. Otherwise, the change will be lost through the life cycle of the page.

As an example, suppose you have a page containing a Label control and two Button controls. The Label's BackColor property is declaratively set to Beige. The first Button changes the BackColor property of the Label control to Red. The second Button control only posts the page back. Now, let's walk through the page's life cycle when the page first loads, when the first Button is clicked and when the second one is clicked.

When the page loads, the instantiation occurs and the Label control's BackColor property is set to Beige. Since it is not a postbacl, load view state and save view state stages will not execute. The page will be rendered and the output is a Label with a beige background color.

Now you click the first Button control. The instantiation sets the Label's background color to Beige. Load view state makes no changes, because no save view state happened in the previous page load. After the load event, raise postback event happens which changes the Label's background color to Red. The next stage is save view state. It's when the BackColor property of the Label control will be persisted, because it's a programmatic change. At the end, the result is rendered and sent back to the client's browser.

Now you click the second Button control which posts the page back. The instantiation stage loads the BackColor property of the Label control and sets it to Beige. In load view state stage, the state that was saved in the previous stage, is loaded which means the Label control's BackColor property is set to Red. Then save view state happens exactly as the previous page load. The page is rendered and is transmitted to the browser.

Suppose the BackColor property of the Label control was not persisted. This means the change made by clicking the first Button control wouldn't be loaded after clicking the second Button control and it would be lost. You can try this out by setting the EnableViewState property of the Label control to false. You will notice that after clicking the second Button control, the change is lost and the background color of the Label control is set back to Beige.

There is something I need to point out here. There are certain controls that persist their state even when EnableViewState is set to false. MSDN explains it this way. This behaviour occurs because ViewState of a control is only one of the methods that are used to persist a control's attributes across requests. In TextBox, CheckBox and RadioButton controls, attributes that are not normally posted to the server through the GET and POST methods are handled by ViewState. Attributes that are normally posted to the server are handled by the IPostBackDataHandler interface.

Wednesday, September 15, 2010

ASP.NET page's life cycle

Today I decided to discuss one of the most misconcepted features in ASP.NET; ViewState. I started to write about it, then I realized I’d better create a separate post about ASP.NET page’s life cycle. Because understanding view state depends on how accurately you know page’s life cycle. So not to mix up things, I decided to explain page’s life cycle first. Later I will refer to view state. Well, before I go on, let me explain some terms you may hear when you study in this area. One of the terms that may often be heard is IIS pipeline. According to MSDN, IIS pipeline is a state machine consisiting of the states below:

BEGIN_REQUEST
AUTHENTICATE_REQUEST
AUTHORIZE_REQUEST
RESOLVE_REQUEST_CACHE
MAP_REQUEST_HANDLER
ACQUIRE_REQUEST_STATE
PRE_EXECUTE_REQUEST_HANDLER
EXECUTE_REQUEST_HANDLER
RELEASE_REQUEST_STATE
UPDATE_REQUEST_CACHE
LOG_REQUEST
END_REQUEST


When a request is received by IIS, it goes through the state machine until it completes. In IIS 7.0, developers can register their own codes to be executed in any of these steps. This introduces another term. The codes that can be plugged into IIS pipeline to be executed, are called HTTP Modules. It means you can manipulate what happens during the execution of these steps programmatically by creating HTTP modules. At the end of the pipeline, there is another unit called HTTP Handler whose duty is to handle and retrieve the resource that has been requested in the URL by the browser. Every resource known to IIS is mapped and handled by a handler in configuration. For example, when you install ASP.NET on a machine running IIS, it will configure IIS to hand over aspx file requests to ISAPI assembly. You can create your own custom HTTP handler and configure IIS to allow your handler to handle the requests regarding a specific file type. This way you can configure your server to handle any file requests with specific extensions, even those that do not physically exist on the server, such as http://www.myserver.com/myfile.dummy.

I think I need to mention a difference between processing stages in IIS 6.0 and IIS 7.0. If a request is made in IIS 7.0 integrated mode, it goes through the same stages as in IIS 6.0. However these stages include some additional application events, such as MapRequestHandler and PostLogRequest. In fact the main difference is how ASP.NET is integrated with IIS server. In version 6.0 of IIS, there are two request processing pipelines; one for native code ISAPI filters and the other is for managed code components. In version 7.0 of IIS, ASP.NET is integrated with IIS server. This means there is one unified request processing pipeline for all requests. This is an advatnages for ASP.NET developers because, for example, they can handle requests for HTML or ASP pages and make them pass through the same authentication process as ordinary ASPX pages would.

Ok, after defining those tems, it's time to talk about the big deal. I have found dozens of web pages explaining page’s life cycle in ASP.NET on the internet. I think the one that beautifully explains what actually happens, is an image I found in MSDN:



You can see the name and the order of the methods and events that occur during the life cycle of a page. The order of occuring is top down, and from left to right. The list above is a detailed list of the events and methods. I'm going to only discuss those that are more related to view state.

1-Instantiation

Regarding page’s life cycle, the first stage is Instantiation. As you may remember, the last unit in the request processing pipeline is a HTTP handler. Every HTTP handler object has a ProcessRequest method. The life cycle of the page starts by invoking this method in the HTTP handler. It generates the page’s control hierarchy. It’s a control tree which is created by an autogenerated class that is created by ASP.NET runtime when a page is first visited after being created or being modified and saved. If you use a code behind programming model, this autogenerated class will inherit from your page’s associated class which in turn, derives from Page class. If you use inline programming model and use <script> tages directly in your page’s source, this autogenerated class will inherit from Page class. Then the class will be compiled and both the class and its compiled assembly will be saved in temporary ASP.NET folder. This will prevent redundant compilation upon each page request.
This class generates the page’s control hierarchy by parsing the page’s source, converting HTML markup of the page to Literal controls, and translating ASP.NET server controls to appropriate codes.

Let me give you an example to make it clear. Suppose you have a page with the source shown below:

<html>
<body>
    <p>Here is some text</p>
    <form id="form1" runat="server">
    <asp:Label ID="NameLabel" runat="server" Text="Name:"></asp:Label>
    <asp:TextBox runat="server" ID="NameTextBox"></asp:TextBox>
    <asp:Button ID="SendButton" runat="server" Text="Send" />
    </form>
</body>
</html>

The autogenerated class for this page could be something like this:


        LiteralControl lc1 = new LiteralControl(@"<html>\r\n<body>\r\n<p>Here is some text</p>\r\n");
        LiteralControl lc2 = new LiteralControl(@"\r\n<\body>\r\n<\html>");
       
        HtmlForm form1 = new HtmlForm();
        form1.ID = "form1";
        form1.Method = "post";

        Label l1 = new Label();
        l1.ID = "NameLabel";
        l1.Text = "Name:";

        TextBox tb1 = new TextBox();
        tb1.ID = "NameTextBox";

        Button bt1 = new Button();
        bt1.ID = "SendButton";
        bt1.Text = "Send";

        form1.Controls.Add(l1);
        form1.Controls.Add(tb1);
        form1.Controls.Add(bt1);

        Page.Controls.Add(lc1);
        Page.Controls.Add(form1);
        Page.Controls.Add(lc2);

As you can see, the properties that have been set declaratively in the page’s source, have been assigned in code too.

2-Initialization

The next stage is initialization. After the control hierarchy is built, init method occurs recursively on the controls. This method is called in bottom-up order. This means, init method of child controls happens befor init method of the container control. This makes the Page control the last one to invoke init method.
Well, so far, the control hierarchy has been created and the controls’ properties that are set declaratively, have been assigned.

3-Load View State

The next stage is Load View State. This stage occurs only when the page is posted back. At this stage, the state data that was saved in previous page visits will be loaded. Also, view state is validated at this stage.

4-Load Postback Data

The next stage is Load Postback Data. Like the previous stage, this stage occurs when the page is posted back. Load postback data happens for controls that implement IPostBackDataHandler interface. The page checks the data in form fields that have been posted back in HTTP header and finds the data related to the controls that implements IPostBackDataHandler interface and invoked the controls’ LoadPostData method. This will populate the control’s state with the posted back data.

The best example for this is the TextBox control. When you enter a string into the TextBox and post the page back, what happens is the browser requests the same page, passing the form field values (including the TextBox's new value) in HTTP headers. If you want to see the process in action, you can enable tracing on your web page with a TextBox and a Button control and enter something into the TextBox and post the page back by clicking the Button control. If you check the tracing information, in Form Collection section, you will see the new value entered into the TextBox control.

As you can see, this stage has nothing to do with view state. One of the most common misconceptions about controls and postback values is that some developers believe view state is somehow responsible for controls remembering their postback values while, in fact, these value are retrieved from form fields and are handed over to those controls that implements IPostBackDataHandler interface.

Something else worth mentioning is the two types of postback events. Controls like Button that cause postback automatically, implement IPostBackEventHandler interface. This is raised event. On the other hand, there are controls like TextBox whose value may change by the user, while they don’t raise any events after the change. These controls implements IPostBackDataHandler interface. This is changed event.

5-Load

The next stage is Load. At this stage, view state has been loaded and controls are in a consistent state.

6-Raise Postback Events

The next stage is Raise Postback Events. As I explained before, some controls implements IPostBackDataHandler interface. Their events regarding any changes in them will be invoked at this time. For example, a TextBox’s TextChanged event or a DropDownList’s SelectedIndexChanged event. Also, for those controls like Button that implement IPostBackEventHandler interface, corresponding event will fire at this stage.

7- Save View State

The next stage is Save View State. At this time of page’s life cycle, view state is constructed. It consists of the state data that must be persisted across postbacks. This is done by calling SaveViewState method of the controls in the control hierarchy. The result is serialized into base-64 encoded string. It is in the next stage where this value is persisted in a hidden form field called __VIEWSTATE.

8-Render

The next stage is Render. At this time, the actuall HTML that must be sent to the client’s browser is generated by using the control hierarchy and posted back data. This is accomplished by calling each control’s RenderControl method.

These stages are not the only stages in page’s life cycle. But regarding view state, they take a higher priority to be explained. Now that I have discussed page’s life cycle, I can explain view state in my next post. Until then, happy coding!

Saturday, September 11, 2010

Execute a synchronous method asynchronously

Delegates are abstraction of one or more functions. They can be used as general function pointers, callbacks, events and threads. One of the areas where delegates can be useful is when you need to call a synchronous method asynchronously to boost the performance. In order to do so, you will need to define a delegate with the same signature as that of the method you want to execute. By defining that delegate, you will have access to two additional method called BeginInvoke and EndInvoke which can be used in asynchronous programming. For example, say we have a method that takes in two parameters and calculates their product. In real life, the execution of such a method wouldn’t take so long. Thus, to simulate a situation where you execute a long-running method, I called Sleep method of Thread class which makes the current thread suspend for a specified amount of time. Here is the code:

public int CalculateProduct(int number1, int number2)
{
      Thread.Sleep(10000);
      return number1 * number2;
}

This method will roughly take 10 seconds to finish. So if you execute it synchronously, the application will stop responding until the job is done. But if you execute it using a delegate’s BeginInvoke method, you could still do some more tasks in the meantime. The delegate could be something like this:

public delegate int CalculateDelegate(int number1, int number2);

I suppose you want to use this approach in a Windows Forms application. On the form, there is a button control and a label control. You run the method asynchronouly and set the value of the label control to the result of the method execution. you can add the code below to the click event handler of the button control.

int val1= 5;
int val2 = 3;
int result;
CalculateDelegate myDel = new CalculateDelegate(CalculateProduct);
IAsyncResult res = myDel.BeginInvoke(val1, val2, null, null);

//You can do some more things here

result = myDel.EndInvoke(res);

When you run BeginInvoke, a new thread is created and the job is handed over to it. This method has the same paramters of the method you assigned to the delegate plus two additional parameters. The first one is a AsyncCallback delegate which is a reference to a method you would want to be executed whenever the asynchronous execution is completed. The second parameter is a custom object that is used to pass data to the callback method. If you run BeginInvoke, you will notice that execution is not blocked upon running it. It returns immediately. The method returns an IAsyncResult which is used to check the completion of the task. In fact, there are several ways to check if the task has completed or not:

• Using EndInvoke method
• Polling
• Using AsyncWaitHandle object
• Using callback method

You can use EndInvoke method to block execution until the asynchronous method completes. Right after you run this method, the execution halts and waits for the asynchronous method to return. So you can be sure that the code you put after EndInvoke runs while the asynchronous method has returned.

You can also use polling. The BeginInvoke method returns an IAsyncResult object. You can check it constantly (for example in a while loop) to see if the asynchronous execution has completed. The IAsyncResult has a property of type Boolean called IsComplete. When the asynchronous call completes, it is set to true.

IAsyncResult has a property of type WaitHandle called AsyncWaitHandle. You can use its WaitOne method to block execution until the WaitHandle object is signaled. Then you can use EndInvoke method to finish the task.

The last approach is to use a callback method. BeginInvoke method takes in a parameter of type AsyncCallback. It’s a delegate that references a method which can be called upon completion of the asynchronous method. You can also send custom data to it using the next parameter which is of type Object.

When the execution completes, you can access the result of the method execution by running EndInvoke method. Its only parameter is the return object of the BeginInvoke method which is of type IAsyncResult and its return type is the same as that of the actual method you ran asynchronously.

Monday, September 6, 2010

Control caching based on custom information

In order to use VaryByCustom attribute of OutputCache directive, you must override a method in Global.asax file. Here is a sample code:

public override string GetVaryByCustomString(HttpContext context, string custom)
{
      if (custom == "UserBased" && User.Identity.IsAuthenticated)
      {
            return User.Identity.Name;
      }
      return base.GetVaryByCustomString(context, custom);
}

Then you can set VaryByCustom attribute to “UserBased”. In this example, an instance of the cache will be created for the page based on the user’s identity and username.

Export data to a CSV file

If you have your data in a DataTable object and want to export it in CSV format, you could use this sample code. I suppose that you already have a method called GetData that returns the DataTable.

DataTable dt = GetData();
HttpContext context = HttpContext.Current;
context.Response.Clear();
context.Response.ContentType = "text/csv";
context.Response.AddHeader("Content-Disposition", "attachment; filename=csvfile.csv");
context.Response.ContentEncoding = Encoding.UTF8;
for (int i = 0; i < dt.Columns.Count; i++)
{
      if(i > 0)
            context.Response.Write(",");
      context.Response.Write(dt.Columns[i].ColumnName);
}
context.Response.Write(Environment.NewLine);
foreach(DataRow row in dt.Rows)
{
      for(int i = 0; i < dt.Columns.Count; i++)
      {
            if(i > 0)
                  context.Response.Write(",");
            context.Response.Write(row[i].ToString());
      }
      context.Response.Write(Environment.NewLine);
}
context.Response.End();

Using FtpWebRequest object to upload files to a Ftp Server

There are two main classes you can use to gain access to a remote Ftp Server in your ASP.NET web application, FtpWebResponse and FtpWebRequest. Here is a sample code that uses a FileUpload control to upload a file to the remote server:

FtpWebRequest wReq = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://myftpsrver.com/" + FileUpload1.FileName));
wReq.UseBinary = true;
wReq.Method = WebRequestMethods.Ftp.UploadFile;
wReq.Credentials = new NetworkCredential("admin", "mypass");
FileInfo fi = new FileInfo(FileUpload1.PostedFile.FileName);
byte[] bytes = new byte[fi.Length];
FileStream fs = fi.OpenRead();
fs.Read(bytes, 0,(int) fi.Length);
fs.Close();
Stream rs = wReq.GetRequestStream();
rs.Write(bytes, 0, bytes.Length);
rs.Close();
FtpWebResponse wResp = (FtpWebResponse)wReq.GetResponse();
Label1.Text = "Code: " + wResp.StatusCode.ToString() + ", Description: " + wResp.StatusDescription;

Sunday, September 5, 2010

How to make use of Filter property of Response object

Response object has a property called Filter. Not surprisingly, you can use it to filter the response data and manipulate it. First, you need to define a class that derives from Stream class. You then need to implement the required methods and properties. In this case, you will need Read, Write and Flush methods to be implemented. If you use ‘Implement abstract class’ feature, all the abstract properties and methods will be placed in the code with a throw statement. You will need to remove the default throw statement from Flush method. Otherwise you will get an error message at run time. Here is a sample class:

public class ResponseFilter: Stream
{
      Stream baseStream;
      public ResponseFilter(Stream responseStream)

      {
            if (responseStream == null)
            {
                  throw new ArgumentNullException("ResponseStream");
            }
            baseStream = responseStream;
      }
      public override void Write(byte[] buffer, int offset, int count)
      {
            string text = Encoding.UTF8.GetString(buffer, offset, count);
            text = text.Replace("old_text", "new_text");
            buffer = Encoding.UTF8.GetBytes(text);
            baseStream.Write(buffer, 0, buffer.Length);
      }
      public override int Read(byte[] buffer, int offset, int count)
      {
            return baseStream.Read(buffer, offset, count);
      }
}

In the handler method of the Page’s Load event, Filter property needs to be set to an instance of the newly created class by passing in the Filter property to the constructor:

protected void Page_Load(object sender, EventArgs e)
{
      Response.Filter = new ResponseFilter(Response.Filter);
}

In this example, all occurances of the string "old_text" will be replaced with "new_text". It's not a very sophisticated example, but it shows how you can filter the response and modify the stream.

Create and use a custom configuration section in web.config

If you want to have a custom configuration section like the one defined below, you will have to define a class to handle it. The class needs to derive from ConfigurationSection.

<mySettings myval1="customvalue1" myval2="customvalue2" myval3="customvalue3"/>

Also you will have to define its structure in the configSections of the web.config:

<configuration>
      <configSections>
            <section name="mySettings" type="myNameSpace.mySettings"/>
      </configSections>
...
</configuration>


Note that the configSections, if defined, has to be the first child element of configuration element in the web.config file. The class can be defined this way:

public class mySettings: System.Configuration.ConfigurationSection
{
      [ConfigurationProperty("myval1", IsRequired=true)]
      public string myval1
      {
            get{return this["myval1"].ToString();}
            set{this["myval1"] = value;}
      }


      [ConfigurationProperty("myval2", IsRequired = true)]
      public string myval2
      {
            get{return this["myval2"].ToString();}
            set{this["myval2"] = value;}
      }

      [ConfigurationProperty("myval3", IsRequired = true)]
      public string myval3
      {
            get{return this["myval3"].ToString();}
            set{this["myval3"] = value;}
      }
}

Saturday, September 4, 2010

Object Oriented Programming

C# is an Object Oriented language. Even if it is not pure Object Oriented like Eiffel or SmallTalk, it was designed mainly for Objected Oriented programming. Ok, what is Object Oriented programming?
In Object Oriented Programming or OOP, we map identities in real world to objects and model the actions as methods. What takes priority in OOP is the object, as opposed to the actions related to it.
In OOP, there are a couple of concepts that we might ignore as programmers most of the time, while having a solid grasp of what these concepts are, is imporatning to create robust OOP application.

Level of abstraction:
In real life, we try to reduce the number or the complexity of things we deal with. It means we work at a specific level of details. In OOP terminology, this is called the level of abstraction. If you want to turn on the TV and watch a program, you are not going to have to open the TV set or reprogram the electronic chips in it, even if your expertise is assmebling television sets. This means you abstract away the details you don't want to get involved in.

Classification:
We classify almost everything to reduce the number of things we have to remember. If you are asked to use a brand new mobile phone, in spite of being unfamiliar with that particular phone, you will still be able to perform the basic operations on it, because at the end of the day, it's a mobile phone and you are likely to have already operated one. The new type of mobile phone shares most of the properties of other mobile phones. So we can say the phone inherits the common properties and actions from a general phone.
In C#, classification has been implemented by Inheritance. A class can derives from another one. This way, it inherits the properties and methods of the base class. The first class is a child of the second class (the parents class). The parent class can have several child classes, while each class can only have one parent class.
You may wonder how we benefit from Inheritance. In terms of OOP in C#, Inheritance introduces these benefits:
  • It reduces the amount of typing. If you have several classes that have some properties in common, you can create a base class defining the common properties and behaviors, then derive the other classes from the base class.
  • It facilitates reusability. Well, you shouldn't reinvent the wheel. Starting a software from the scratch is a pain in the neck, while you could use already existing components. By using Inheritance, you can adapt existing classes to your program while leaving the internals of the classes intact.
  • Updates will be integrated with much less hassle. If you change a base class, the change will be reflected in all child classes as well.
Polymorphism:
Late binding or polymorphism is the ability to decide the type at run time. This concept is so important that if a language supports Objects but not polymorphism is called Object Base (such as Ada).
Suppose you have a base class and a sub class that inherits from it.

public class baseClass
{
      int prop1;
      int prop2;
      public int Prop1{get{return prop1;}set{prop1 = value;}}
      public int Prop2{get{return prop2;}set{prop2 = value;}}
      public virtual int Operation()
      {
            return Prop1 * Prop2;
      }
}

public class subClass : baseClass
{
      public override int Operation()
      {
            return Prop1 * Prop2 / 2;
      }
}
 
...
 
public void Test()
{
      baseClass b;
      b = new subClass();
      b.Prop1 = 4;
      b.Prop2 = 3;
      int result = b.Operation();
}
 
In method Test, object b is a reference to baseClass while it actually contains an object of type subClass. So, to the compiler, it is a baseClass, while at run time, polymorphism will let you take the appropriate type. The method Operation is a virtual method, which means it can be overriden in the sub classes.
If you run this code, the result will be 6, not 12. That's polymorphism! At run time, the most appropriate type was chosen, which was baseClass and its method was executed. Of course, if you don't override the method and hide the method by using the keyword 'new', the result will be different. This happens because you break the chain of hierarchy by using 'new'. You can check it out by debugging and stepping into the method.

Covariance and Contravariance

In C#, there are two terms defined regarding delegates; Covariance and Contravariance. These two concepts exapand the set of methods that you can assign to a delegate. They still maintain type-safeness. I’d better clarify it using an example. Suppose that you have these classes:

public class P1
{

}
 public class C1 : P1
{

}

public class P2
{

}

public class C2 : P2
{

}

And you have a delegate defined this way:

public delegate P1 myDelegate(C2 c2);

If you intend to use this delegate, you will have to assign a method with a same signature. For example:

public P1 myMethod(C2 c2)
{

}

But not only can you use any method with a return type of P1, but any child class of P1 (in this case C1) in the chain of hierarchy. This is called Covariance.
On the other hand, you can use any method with a paramater of type C2 or any super type of C2 (in this case P2). This is called Contravariance.

Friday, September 3, 2010

Access the control that has invoked a method in JavaScript

Suppose that you have a function in Javascript that can be invoked by several controls. In order to access the actual control that has invoked the method, you can use the code shown here:

<input id="Button1" type="button" value="button" onclick="myfunc();"/>

function myfunc()
{
      window.event.srcElement.style.color = 'red';
}

In this example, if you click the button (or any other buttons with their onclick set to 'myfunc'), its forecolor will change to red.

Access a control in a web user control from within JavaScript

Suppose that you have a page that contains a web user control that, in turn, includes a Button control. If you want to access the button properties or methods, you can expose a property in the user control that returns the property or the method result. To use it in JavaScript, use the syntax shown below:

<script language="javascript" type="text/javascript">
function myFunction()
{
      var btnid = '<%= WebUserControl1.ButtonClientID %>';
      document.getElementById(btnid).style.color= 'green';
}
</script>

The code assumes that there is a property named ButtonClientID defined in the web user control.

public string ButtonClientID
{
      get
      {
            return Button1.ClientID;
      }
}

User selectable Themes

In order to let user select a theme, for example defined as values in a DropDowList control, you need to first override PreInit method of the page and then access the control using Request.Form syntax.

protected override void OnPreInit(EventArgs e)
{
      this.Master = Request.Form[this.Master.FindControl("DropDownList1").UniqueID];
}

It's important to note that you cannot access the DropDownList control at this stage of the page life cycle. That is why you need to resort to Form collection and FindControl method.

Handle events in Master and Content pages

If you have a web control on a master page and intend to access it on a content page, you can do so by exposing the control as a public property. This way you can register a handler for the control which is actually a property, in the content page.
Another way is to define your custom delegate and use it to define your custom event in the master page. Then in your content page, you can register a handler for the master page event as the code below shows:

protected void Page_Load(object sender, EventArgs e)
{
      this.Master.selectionChangeEvent += Content_Changed;
}

public void Content_Changed(object sender, TypeSelectionEventArgs args)
{
      Label1.Text = "Content changed to " + args.SelectedType.ToString();
}

You will need to define @MasterType directive in your content page. Also, you will more likely have your own custom data that needs to be transferred through this procedure. You can define your own Enums and Classes and pass it to your delegate to accomplish the job.

Wednesday, September 1, 2010

Multiple File Uploads

If you want to add multiple File Upload controls on demand, you will need a Javascript code to add the controls. The form could look like this:

<form id="form1" runat="server" enctype="multipart/form-data">

Here is a sample Javascript code that accomplishes the job:

<script type="text/javascript">
function addFileUploadBox()
{
      if(! document.getElementById || !document.createElement)
      {
            return false;
      }
      var uploadArea = document.getElementById("upload-area");
      if(!uploadArea)
      {
            return;
      }
      var newLine = document.createElement("br");
      uploadArea.appendChild(newLine);
      var newLine = document.createElement("br");
      uploadArea.appendChild(newLine);
      var newUploadBox = document.createElement("input");
      newUploadBox.type = "file";
      newUploadBox.size = "60";
      if(!addFileUploadBox.lastAssignedId)
            addFileUploadBox.lastAssignedId = 100;
      newUploadBox.setAttribute("id","FileField" +    addFileUploadBox.lastAssignedId);
      newUploadBox.setAttribute("name","FileField" + addFileUploadBox.lastAssignedId);
      uploadArea.appendChild(newUploadBox);
      addFileUploadBox.lastAssignedId++;
}
</script>

In code behind, you need to iterate through the Files property of the Request object. It is an HttpFileCollection:

HttpFileCollection uploads = HttpContext.Current.Request.Files;
for (int i = 0; i < uploads.Count; i++)
{
      if (uploads[i].ContentLength > 0)
      {
            string c = Path.GetFileName(uploads[i].FileName);
            try
            {
                  string path = MapPath("uploads/") + c;
                  FileField.PostedFile.SaveAs(path);
            }
            catch{}
      }
}