Thursday, November 5, 2009

How to use standard FileUpload in AJAX-enabled web applications

 

I would like to note that this article is not about the ability to upload files to the server without the postback. There are a lot of articles on this topic, just type "AJAX FileUpload" in any search engine and you'll get many examples. However with AJAX they actually have little in common, because the XMLHttpRequest does not support asynchronous uploading of files to the server, they are rather a variety of imitations, for example, using hidden IFRAME element. Nevertheless I want to emphasize that the article is not about that but about the standard FileUpload control.

There are two problems you might encounter when using it on UpdatePanel.

Problem 1
If the postback is caused by a control which lies on the UpdatePanel, the FileUpload is always empty when it come to the server, regardless whether a file has been selected or not.
Example:

<asp:UpdatePanel ID="UpdatePanel1" runat=server>
<ContentTemplate>
<asp:FileUpload ID="FileUpload1" runat=server />
<asp:Button ID="btnUpload" runat=server Text="Upload" OnClick="btnUpload_Click"/>
</ContentTemplate>
</asp:UpdatePanel>

Solution


As XMLHttpRequest does not allow to send files asynchronously, they have to be submitted in a common manner. This problem is well described around, it is solved by registration of the control that has to submit the form as a postback trigger (in the above example it is btnUpload button).

<asp:UpdatePanel ID="UpdatePanel1" runat=server>
<ContentTemplate>
<asp:FileUpload ID="FileUpload1" runat=server />
<asp:Button ID="btnUpload" runat=server Text="Upload 2" OnClick="btnUpload_Click"/>
</ContentTemplate>
<Triggers>
<asp:PostBackTrigger ControlID="btnUpload" />
</Triggers>
</asp:UpdatePanel>


Problem 2


FileUpload does not work if it is loaded not on the initial page load but appears only after asynchronous update of the page part.


Example (pnlUpload panel is invisible in the beginning and is shown after clicking on btnShowFileUpload button):



<asp:UpdatePanel ID="UpdatePanel1" runat=server>
<ContentTemplate>
<asp:Button ID="btnShowFileUpload" runat=server Text="Show File Upload" OnClick="btnShowFileUpload_Click"/>
<asp:Panel ID="pnlUpload" runat=server Visible="False">
<asp:FileUpload ID="FileUpload1" runat=server />
<asp:Button ID="btnUpload" runat=server Text="Upload" OnClick="btnUpload_Click"/>
</asp:Panel>
</ContentTemplate>
<Triggers>
<asp:PostBackTrigger ControlID="btnUpload" />
</Triggers>
</asp:UpdatePanel>

.......................

protected void btnShowFileUpload_Click(object sender, EventArgs e)
{
pnlUpload.Visible = true;
}

Solution


The problem is caused by the requirement that for the normal work of FileUpload the form should have enctype="multipart/form-data". Usually, it is set in overriden OnPreRender method of FileUpload control.

protected internal override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
HtmlForm form = this.Page.Form;
if ((form != null) && (form.Enctype.Length == 0))
{
form.Enctype = "multipart/form-data";
}
}

Although during asynchronous postback this code is also executed but the form is not updated. That is why it is required to set the form content type explicitly during the first page load, for example, in the Page_Load event handler of the page or a control where FileUpload is placed.

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
this.Page.Form.Enctype = "multipart/form-data";
}

In case if this task is repeated in a few places you may do a simple control derived from FileUpload with overriden OnLoad method and use it.

public class CustomFileUpload : FileUpload
{
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);

if (!Page.IsPostBack)
this.Page.Form.Enctype = "multipart/form-data";
}
}


Source article

Monday, October 19, 2009

Async FileUpload control for AJAX pages

With the new release of Ajax Control Toolkit (v 3.0.30930) released specifically for .NET 3.5 SP1 (with Visual Studio 2008 SP1), there are couple of new controls.  One of them is the AsyncFileUpload control.

Thanks to the codeplex community which keeps getting better and better with time, the Ajax Control Toolkit has grown into one of our largest community contributed controls for ASP.NET with about 43 controls that help in accomplishing rich user experiences in ASP.NET Websites.

The AsyncFileUpload is one simple way of accomplishing what I had written earlier using PostbackTrigger, the regular FileUpload control etc.,  To be able to use the AsyncFileUpload Control, you must have the latest version of AjaxControlToolkit installed.  The other pre-requisites are obviously NET 3.5 SP1 and Visual Studio 2008 SP1 (or the free Visual Web Developer Express Edition)

You can download the pre-requisites from the respective links above.  For downloading the AjaxControlToolkit, visit the CodePlex site.  You can download just the binary files or the Source files as well, if you require to modify.  The Script Files is useful if you want to just work with the client side scripts and not use the server controls.

Once you have downloaded, you would need to add them to Visual Studio or VWD.

1. Open Visual Studio and create a new webapplication or website.  Click to open the ToolBox

2. Right Click and select “Add Tab”

3. Provide a name say “Ajax Control Toolkit”

4. Right Click the newly created tab and select “Choose Items”

5. Click on the “Browse” button in the file dialog that opens and browse to the place where you downloaded the AjaxControlToolkit binaries

6. Typically I would put them under C:\Program Files\Microsoft ASP.NET for consistency.

7. Select the AjaxControlToolkit.dll and it would list all the new controls.

8. Click “Ok” to add all the controls.

9. You should now see under the newly created toolbox tab these controls.

Once you are done with above, create a simple Default.aspx page in the application you created and drop the Script Manager control into your webform.  Next add an UpdatePanel with ContentTemplate.  Inside the ContentTemplate, add the AsyncFileUpload control into the webform as well as a button and 2 labels for the uploading and displaying messages respectively.  The markup looks something like below

<form id="form1" runat="server">
   <div>
       <asp:ScriptManager ID="ScriptManager1" runat="server">
       </asp:ScriptManager>
       <asp:Image ID="img1" runat="server" ImageUrl="~/Images/spin2.png" />
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
           <ContentTemplate>
               <cc1:AsyncFileUpload ID="AsyncFileUpload1" runat="server" UploaderStyle="Modern" ThrobberID="img1"  />
       <br />
       <asp:Button ID="btnUpload" runat="server" Text="Upload"
           onclick="btnUpload_Click"   />
           <br />
           <asp:Label ID="Label1" runat="server" /> 
           <br />
           <br />
         </ContentTemplate>
       </asp:UpdatePanel>
       <br />
       <asp:Label ID="Label2" runat="server" />
   </div>
   </form>

Also, you can see that I have added an asp:Image pointing to a spin image that is specified as the ID for ThrobberID in the AsyncFileUpload definition.  This is optional but nice to have since this would display the throbber icon while uploading takes time.

Once you are done, you would need to define the action in the codebehind or in the script

protected void Page_Load(object sender, EventArgs e)
      {
          Label2.Text = DateTime.Now.ToString();
      }

      protected void btnUpload_Click(object sender, EventArgs e)
      {
          AsyncFileUpload1.SaveAs(Server.MapPath((AsyncFileUpload1.FileName)));
          Label1.Text = "You uploaded " + AsyncFileUpload1.FileName;
      }

Notice, the Label in the Page_Load event is just to indicate that indeed the operation happened asynchronously since the time that is displayed initially doesn’t change once you click on Upload button. 

Try running this and you will find that the whole operation happens asynchronously without a full page reload.  Note that, you would need to still put the AsyncFileUpload control inside UpdatPanel for this behaviour.  Otherwise, it would behave like a regular postback control

Wednesday, September 23, 2009

How To: Change Instance Name Of SQL Server

Recently I change the network name of one of my servers at work, because the box changed its job from a virtual machine server to the database server. Everything was going great until I decided to setup the server for replication and received the following error message.

New Publication Wizard
——————————

SQL Server replication requires the actual server name to make a connection to the server. Connections through a server alias, IP address, or any other alternate name are not supported. Specify the actual server name, ‘old_name’. (Replication.Utilities)

——————————
OK
——————————

So with a little hunting and SQL queries I found out that SQL Server doesn’t use the network name, it only excepts that as an alias. My SQL Server instance was still named “old_name”. I found that out by running these two queries:

  1. sp_helpserver
  2. select @@servername

So in order to get the network name and the SQL Server instance name back in sync I had do these steps:

  1. Run this in Microsoft SQL Server Management Studio:
    1. sp_dropserver 'old_name'
    2. go
    3. sp_addserver 'new_name','local'
    4. go
  2. Restart SQL Server service. I prefer the command prompt for this, but you can just as easily do it in Services under the Control Panel
    net stop mssqlserver
    net start mssqlserver

Then after that is done run this again, to make sure everything is changed:

  1. sp_helpserver
  2. select @@servername

I don’t understand why SQL Server uses it’s own name versus the network name, might be due to the fact you can have multiple SQL Server instances install on one machine. It wasn’t too hard to change and probably stems from the days when SQL Server was known as Sybase, all in all, I learned something new and it only took 30 minutes of my day to fine the answer.

From: Source

Friday, July 24, 2009

Excel TIP: New lines in an Excel cell

I just wanted to find out how to enter a new line in an Excel cell.

Answer is to use Alt+Enter to create a new line. Additionally when you do that, Excel automatically enables text wrap for the cell.

Summary
----------
Alt+Enter : Enter new line in a cell
F2: Edit a cell

Monday, June 29, 2009

Resolving “A network-related or instance-specific error occurred while establishing a connection to SQL Server…”

SQL Server 2005 Error:“A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified) ”
Things to check:1. Make sure your database engine is configured to accept remote connections• Start > All Programs > SQL Server 2005 > Configuration Tools > SQL Server Surface Area Configuration• Click on Surface Area Configuration for Services and Connections• Select the instance that is having a problem > Database Engine > Remote Connections• Enable local and remote connections• Restart instance
2. Check the SQL Server service account• If you are not using a domain account as a service account (for example if you are using NETWORK SERVICE), you may want to switch this first before proceeding
3. If you are using a named SQL Server instance, make sure you are using that instance name in your connection strings in your ASweb P.NET application• Usually the format needed to specify the database server is machinename\instancename• Check your connection string as well

<connectionStrings>

<add name=”SampleConnectionString” connectionString=”Data Source=machinename\instancename;Initial Catalog=AdventureWorks;Integrated Security=SSPI;Min Pool Size=5;Max Pool Size=60;Connect Timeout=30″ providerName=”System.Data.SqlClient”/>

</connectionStrings>



4.You may need to create an exception on the firewall for the SQL Server instance and port you are using• Start > Run > Firewall.cpl• Click on exceptions tab• Add the sqlservr.exe (typically located in C:\Program Files (x86)\Microsoft SQL Server\MSSQL.x\MSSQL\Binn), and port (default is 1433)• Check your connection string as well
5. If you are using a named SQL Server instance, make sure you are using that instance name in your connection strings
6. Check SQLBrowser; check that it is running. You may also need to create an exception in your firewall for SQLBrowser.
7. Check that you have connectivity to the SQL Server. Note what you are using to connect: machine name, domain name or IP address? Use this when checking connectivity. For example if you are using myserver• Start > Run > cmd•netstat -ano findstr 1433•telnet myserver 1433•ping -a myserver
Check what ports are IP addresses are being returned.
Alternative:If you still can’t get any connection, you may want to create a SQL account on the server, a corresponding SQL user on the database in question, and just use this username/password combo in your web application.

Source: http://www.sqlmusings.com/2009/03/11/resolving-a-network-related-or-instance-specific-error-occurred-while-establishing-a-connection-to-sql-server/

Wednesday, May 27, 2009

How to convert NameValueCollection to a (Query) String

Most ASP.NET developers know that you can get a key/value pair string from the Request.QueryString object (via the .ToString() method). However that functionality isn’t the same for a generic NameValueCollection object (of which Request.QueryString is derived from).


So how do you take a NameValueCollection object and get a nicely formatted key/value pair string? (i.e. “key1=value1&key2=value2“) … Here’s a method I wrote a while ago:



  1. /// <summary>
  2. /// Constructs a QueryString (string).
  3. /// Consider this method to be the opposite of "System.Web.HttpUtility.ParseQueryString"
  4. /// </summary>
  5. /// <param name="nvc">NameValueCollection</param>
  6. /// <returns>String</returns>
  7. public static String ConstructQueryString(NameValueCollection parameters)
  8. {
  9. List<String> items = new List<String>();

  10. foreach (String name in parameters)
  11. items.Add(String.Concat(name, "=", System.Web.HttpUtility.UrlEncode(parameters[name])));

  12. return String.Join("&", items.ToArray());
  13. }

Just in case you didn’t know about the System.Web.HttpUtility.ParseQueryString method, it’s a quick way of converting a query (key/value pairs) string back into a NameValueCollection.

From : http://blog.leekelleher.com/2008/06/06/how-to-convert-namevaluecollection-to-a-query-string/