Silverlight 2 - Nahratie súboru na server

Publikoval Michal Kočí dňa 5.5.2008 o 23:53 v kategórii Silverlight

Silverlight 2 sa hodí v prípade, že chcete na server odoslať jeden alebo viac súborov. V tomto príspevku ukážem, ako na server odoslať práve jeden súbor a ako ho na servery uložiť na disk.

Ak chcete, aby Vaši užívatelia mohli na server nahrávať súbory, scenár bude pravdepodobne taký, že po nalistovaní súboru užívateľom hneď, alebo po vykonaní nejakej užívateľskej akcie (napríklad stlačení tlačidla) súbor predáte serveru v podobe HTTP požiadavky.

Nalistovanie súboru

Na formulár teda umiestníte:

  • UploadButton - tlačítko na nalistovanie súboru
  • SelectButton - tlačítko na odoslanie súboru
  • FileNameTextBlock - popisok s názvom súboru
  • StatusTextBlock - popisok s aktuálnym stavom

Váš formulár môže vyzerať nasledovne (XAML sem nedávam, lebo sa mi zase raz nepodarilo ho farebne naformátovať):

Do kódu formulára pridáte premennú typu OpenFileDialog s názvom dialog. Kód potom bude vyzerať nasledovne:

using System;
using System.Windows;
using System.Windows.Controls;
using System.IO;
using System.Net;
 
namespace FileUploadClient
{
    public partial class Page : UserControl
    {
        OpenFileDialog dialog;
 
        public Page()
        {
            InitializeComponent();
 
            dialog = new OpenFileDialog();
            dialog.EnableMultipleSelection = false;
 
            this.SelectButton.Click += new RoutedEventHandler(SelectButton_Click);
            this.UploadButton.Click += new RoutedEventHandler(UploadButton_Click);
        }
 
        void UploadButton_Click(object sender, RoutedEventArgs e)
        {
        }
 
        void SelectButton_Click(object sender, RoutedEventArgs e)
        {
        }
    }
}

Ošetrenie kliknutia na tlačítko Nalistovať

Keď užívateľ klikne na tlačítko nalistovať, tak sa mu má zobraziť dialóg na nalistovanie súboru. Tento sme zinicializovali v konštruktore a to tak, že sme nepovolili výber viacerých súborov. Takže ak užívateľ vyberie súbor, potom jeho názov vypíšeme do pripraveného popisku. Ošetrenie udalosti vyzerá nasledovne:

void SelectButton_Click(object sender, RoutedEventArgs e)
{
    if (dialog.ShowDialog() == DialogResult.OK)
    {
        FileNameTextBlock.Text = dialog.SelectedFile.Name;
    }
}

Ošetrenie kliknutia na tlačítko Nahrať

Po kliknutí na tlačítko nahrať treba vytvoriť webovú požiadavku a jej obsah naplniť obsahom súboru. Cez URL na ktorý požiadavka smeruje (generický handler, ktorý bude naprogramovaný nižšie) odošleme aj názov súboru.

Vytvorenie požiadavky je trochu komplikovanejšie a to preto, lebo zapísanie dát do obsahu požiadavky sa deje asynchrónne. Takže v ošetrení udalosti vytvoríme webovú požiadavku a zavoláme metódu BeginGetRequestStream, ktorej predáme názov metódy asynchronného callbacku - v našom prípade OnRequestStream:

void UploadButton_Click(object sender, RoutedEventArgs e)
{
    if (dialog.SelectedFile != null)
    {
        string fileName = dialog.SelectedFile.Name;
        HttpWebRequest request = (HttpWebRequest) WebRequest.Create(
            new Uri("http://localhost:57091/FileUpload.ashx?N=" + fileName));
        request.Method = "POST";
        request.ContentType = "application/x-www-form-urlencoded";
        request.BeginGetRequestStream(OnRequestStream, request);
    }
    else
    {
        StatusTextBlock.Text = "Musíte najskôr vybrať súbor";
    }
}

V callback metóde zavoláme metódu EndGetRequestStream a do objektu typu Stream, ktorý nám táto metóda vráti skopírujeme obsah súboru, ktorý si užívateľ praje nahrať na server. Následne tiež asynchrónne zavoláme vykonanie webovej požiadavky zavolaním metódy BeginGetResponse a ako callback funkciu jej predáme metódu OnResponse:

private void OnRequestStream(IAsyncResult ar)
{
    HttpWebRequest request = (HttpWebRequest) ar.AsyncState;
    Stream writeStream = request.EndGetRequestStream(ar);
 
    using(Stream readStream = dialog.SelectedFile.OpenRead())
    {
        byte[] content = new byte[(int)readStream.Length];
        readStream.Read(content, 0, content.Length);
        writeStream.Write(content, 0, content.Length);
 
        readStream.Close();
    }
 
    writeStream.Close();
 
    request.BeginGetResponse(OnResponse, request);
}

V callback metóde získame odpoveď na našu webovú požiadavku a skontrolujeme, či požiadavka bola úspešná:

private void OnResponse(IAsyncResult ar)
{
    HttpWebRequest request = (HttpWebRequest) ar.AsyncState;
    HttpWebResponse response = (HttpWebResponse) request.EndGetResponse(ar);
 
    if (ar.IsCompleted && response.StatusCode == HttpStatusCode.OK)
    {
        StatusTextBlock.Text = "Prenos ukončený";
    }
}

Serverová strana

Na strane servera je práca jednoduchá. Vytvoríme si generický handler a pri prišlej požiadavke uložíme dáta. Tento handler môže vyzerať nasledovne:

using System;
using System.Collections;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
using System.IO;
 
namespace FileUploadServer
{
    public class FileUpload : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            string fileName = "~/Temp/temp.txt";
            if(context.Request.QueryString["N"] != null)
            {
                fileName = string.Format("~/Temp/{0}", context.Request.QueryString["N"]);
            }
            fileName = context.Server.MapPath(fileName);
 
            context.Response.ContentType = "text/plain";
            context.Response.Write("OK");
 
            SaveFile(fileName, context.Request.InputStream);
        }
 
        private bool SaveFile(string fileName, System.IO.Stream stream)
        {
            using(FileStream writeStream = File.Open(fileName, FileMode.Create))
            {
                byte[] buffer = new byte[(int) stream.Length];
                stream.Read(buffer, 0, buffer.Length);
                writeStream.Write(buffer, 0, buffer.Length);
                writeStream.Close();
            }
 
            return true;
        }
 
        public bool IsReusable
        {
            get
            {
                return true;
            }
        }
    }
}

Záverom

Záverom len skoro tradične dodám, že by bolo vhodné ošetriť všetky možné stavy, ktoré môžu nastať, napríklad korektne ošetriť v handlery možné dôvody zlyhania a tieto signalizovať naspäť volajúcemu, kontrolovať veľkosť odosielaného súboru, kontrolovať či súbor je v správnom formáte a od správneho užívateľa a podobne. Tento príspevok si však kládol za cieľ najmä ukázať aké je jednoduché naimplementovať odoslanie súboru na server zo Silverlight formulára a preto všetky kontroly nechá na láskavého čitateľa, ktorý mi tradične odpustí všetky nedostatky vzniknuté snahou o jednoduchosť.

Mohlo by ťa tiež zaujímať

Páčil sa ti príspevok?

Zdieľaj príspevok alebo si ho odlož na neskôr

Sleduj ma

Ak nechceš premeškať príspevky ako je tento, sleduj ma na Twitteri, alebo ak máš RSS čítačku, môžeš sledovať môj RSS kanál.