Friday 20 April 2012

Download and upload a file to the server through silverlight Application

In this article, we are going to learn how to work with Networking in SilverLight.

Networking

Silverlight also allows us connect to remote machine or services, download and upload files, all these stuffs are done using WebClient class that exists into System.Net namespace.

How to download file and displaying progress status?

To demonstrate this example, we shall create a xaml file and following is my code.

Code
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel>
<TextBlock x:Name="TextBlock1" Margin="10" Foreground="Blue"/>
<TextBlock x:Name="TextBlock2" Margin="10" />
<ProgressBar x:Name="ProgressBar1" Margin="10" Height="25" />
<Button Click="Button_Click" Content="Start downloading file" Height="25" Width="150"/>
<ScrollViewer Height="150" Width="300">
<TextBlock x:Name="TextBlock3" Margin="10" />
</ScrollViewer>
</StackPanel>
</Grid>
In the above code snippet, we have three TextBoxes, a ProgressBar and a Button control. On click of the Button, we shall write our code to download the file. At the time of download we shall show the progress using ProgressBar control, % complete in the and amount of data left in the TextBlock2.
Once the download is complete, we should show the success message in TextBlock1. The content of the file downloaded is shown in the TextBlock3 that is in tern into ScrollViewer control.
Code behind
private void Button_Click(object sender, RoutedEventArgs e)
{
WebClient client = new WebClient();
Uri uri = new Uri("http://feeds.feedburner.com/ItfundacomTutorialsFeed", UriKind.RelativeOrAbsolute);
client.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.OpenReadAsync(uri);
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
ProgressBar1.Value = e.ProgressPercentage;
TextBlock2.Text = e.ProgressPercentage + "% done " + e.BytesReceived + " bytes received and " + e.TotalBytesToReceive + " bytes still needed.";
}
void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
TextBlock1.Text = "Download completed";
using (Stream s = e.Result)
{
StreamReader reader = new StreamReader(s);
TextBlock3.Text = reader.ReadToEnd();
s.Close();
}
}
else
{
TextBlock3.Text = e.Error.ToString();
}
}
In the code behind,
Button_Click method
In this method, we have instantiated the WebClient class. We have also specified a file to download; in this case we are trying to download a RSS feed data. We can also download any local file from server provided that is inside the ClientBin folder.
Next we have set the OpenReadCompleted event and DownloadProgressChanged event of the web client class. At last we have called OpenReadAsync method by passing the uri to download that basically starts downloading the file asynchronously.
client_DownloadProgressChanged method
This method fires when the file download starts. In this method we have set the value of the ProgressBar control to the progress percentage property of the DownloadProgressChangedEventArgs and then we have also set the TextBlock2 text to the % complete, bytes received and bytes left to download.
client_OpenReadCompleted method
This method fires when the file download is complete. In this method we have first checked for error, if it is not we are getting the result of the download and reading to the stream and setting TextBlock3 text to the content of downloaded file. If there is an error, we are writing error.
Output

How to upload a file to the server in Silverlight?

Uploading file in Silverlight is not so straightforward. There is no way to upload a File on Silverlight the way we do in ASP.NET. Let’s create a sample page to upload a file to the server.
In this demo we are going to create
1. Xaml file
2. .ashx file (generic handler) file
The idea here is to get the file to upload from user, convert it into stream and send to the generic hander. The generic handler receives that stream and writes the content to the file on the server.
Code
<StackPanel>
<Button x:Name="upload1" Click="upload1_Click" Margin="20" Content="Select file to upload ..." Width="150" />
<TextBlock x:Name="TextBlock1" Margin="20" />
</StackPanel>
In the above code snippet, we have a button and a TextBlock. On the click of the button, we are calling upload1_click method.
Code behind
private void upload1_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog()
{
Multiselect = false
};if ((bool)dialog.ShowDialog())
{
UriBuilder ub = new UriBuilder("http://localhost:7370/UploadFile.ashx");
ub.Query = "file=" + dialog.File.Name;
WebClient client = new WebClient();
client.OpenWriteCompleted += (inputStream, arguments) =>
{
using (Stream stream = dialog.File.OpenRead())
{
using (Stream output = arguments.Result)
{
byte[] bytes = new byte[4096];
int bytesToRead = 0;
while ((bytesToRead = stream.Read(bytes, 0, bytes.Length)) != 0)
{
output.Write(bytes, 0, bytesToRead);
}
stream.Close();
output.Close();
}
}
};
client.OpenWriteAsync(ub.Uri);
TextBlock1.Text = "File uploaded successfully !";
}
else
{
TextBlock1.Text = "Please select the file to upload ....";
}
}
In the above code snippet, we have used OpenFileDialog class that exists into System.Windows.Controls namespace to open the select file dialog box. We have explicitly set the Multiselect property to false so that user will not be able to select multiple file to upload.
Once user selects the file and click on Open button, ShowDialog method returns true else false. In case user has selected the file and clicked on Open button, we are
1. Framing the URI of the .ashx (generic handler file) with name of the selected file as querystring.
2. Instantiated the WebClient class.
3. Handled the OpenWriteCompleted event and using lamda expression defining the code that runs when this event fires. In this code block we are reading the selected file in the stream and writing to the output stream. In code block you can see that we are creating array of bytes with size as 4096 that is the default maximum size of the file that can be uploaded. In case you want to allow bigger file, change the bytes array size.
4. At last we are calling OpenWriteAsync method by passing the uri of the generic handler (.ashx) that actually opens and starts writing data to the handler and when it completes the OpenWriteCompleted event fires and start writing the selected file to the output stream. This method calls the generic handler because of Uri into OpenWriteAync method.
Now create a generic hanlder (UploadFile.ashx) into the Silverlight web project. Below is the code for my generic handler.

Code snippet
public void ProcessRequest(HttpContext context)
{
string file = context.Request.QueryString["file"];
string uploadPath = context.Server.MapPath("~/UserData/");
using (FileStream stream = File.Create(uploadPath + file))
{
byte[] bytes = new byte[4096]; // assuming the file size will not be more than 4 MB, the default size of the request
int bytesToRead = 0;
while ((bytesToRead =
context.Request.InputStream.Read(bytes, 0, bytes.Length)) != 0)
{
stream.Write(bytes, 0, bytesToRead);
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
In the above code snippet, we are first retrieving the file name being passed from the querystring. Next we are using FileStream to create a file based on the file name being passed here (note that we are also passing the folder name – UserData where our files gets uploaded, we must have write permission to this folder).
Next we are reading the input steam into array of bytes and writing to the file.
Output

UploadFile.ashx

No comments :