Windows Azure – 4 dalis
Publikuota: Cloud Computing
Šioje dalyje mes panaudosime prieš tai sukonfigūruotą lokalią BLOB saugyklą. Kaip pavyzdį aš pateiksiu ASP.NET puslapį, kuriame galima pridėti naują failą į objektinę BLOB saugyklą, atvaizduoti esamus failus, juos parsisiųsti bei ištrinti. Po ilgų svarstymų, aš nusprendžiau apvilkti visas operacijas su Windows Azure į repozitorijaus (angl. repository) projektavimo šabloną.
BLOB pagrindai
BLOB saugykla – tai viena iš Windows Azure objektinių saugyklų, kuri yra skirta binarinių duomenų saugojimui. BLOB saugykla yra sudaryta iš konteinerių – katalogų analogo failų sistemoje. Būtent konteineriuose mes saugome BLOBus (duomenis). BLOBuose fiziškai saugomi ne tik duomenys, bet ir metaduomenys bei atitinkama unikali HTTP nuoroda (ID analogas).
BLOBus galima pasiekti dviem būdais: naudojant pastarąją nuorodą ir REST HTTP operacijas, arba specialų .NET API (jis toliau ir bus nagrinėjamas). Abiems atvejais vietoje ID naudojama nuoroda (Uri formatu).
„Hello World“ projekto pakeitimai
Už pagrindą aš pasiėmiau 2 dalyje aprašytą „Hello World“ Windows Azure ASP.NET aplikaciją. Kadangi darbui su objektinėmis saugyklomis mums reikės nurodyti Windows Azure prisijungimo duomenis, tam HelloWorldCloud projekte reikia nueiti į nustatymus ir pridėti naują prisijungimo eilutę, kurią aš pavadinau StorageConnectionString:
Atkreipkite dėmesį, kad laikinai mes naudojame ne realius Windows Azure prisijungimo duomenis, bet lokalią saugyklą. Kitas svarbus momentas – Web rolės klasės aprašymas. Kadangi Windows Azure BLOB saugykla nepriklauso nuo.NET vykdymo aplinkos (skaitykit nuo Microsoft.WindowsAzure.ServiceRuntime), reikia HelloWorldWeb projekte sukurti Web rolės klasę ir joje nusakyti kaip reaguoti į konfigūracijos failo pakeitimus. Žemiau pateiktas kodas yra nukopijuotas iš Windows Azure SDK, tikiuosi ateityje Microsoft sugalvos patogesnį sprendimą:
public class WebRole : RoleEntryPoint { public override bool OnStart() { DiagnosticMonitor.Start("DiagnosticsConnectionString"); // This code sets up a handler to update CloudStorageAccount instances when their corresponding // configuration settings change in the service configuration file. CloudStorageAccount.SetConfigurationSettingPublisher((settingName, configSetter) => { // Provide the configSetter with the initial value configSetter(RoleEnvironment.GetConfigurationSettingValue(settingName)); RoleEnvironment.Changed += (sender, arg) => { if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>() .Any(change => (change.ConfigurationSettingName == settingName))) { // The corresponding configuration setting has changed, propagate the value if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(settingName))) { // In this case, the change to the storage account credentials in the // service configuration is significant enough that the role needs to be // recycled in order to use the latest settings. (for example, the // endpoint has changed) RoleEnvironment.RequestRecycle(); } } }; }); // For information on handling configuration changes // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357. RoleEnvironment.Changing += (sender, arg) => { // If a configuration setting is changing if (arg.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange)) { // Set e.Cancel to true to restart this role instance arg.Cancel = true; } }; return base.OnStart(); } }
Puslapio sukūrimas
Kadangi puslapyje mes operuosime failais, apibrėžkime pagalbinę klasę FileMetaData, kurioje saugosime failo pavadinimą, turinio tipą bei failo nuorodą BLOBo saugykloje (turi būti unikali):
public class FileMetaData { public Uri Uri { get; set; } public string FileName { get; set; } public string ContentType { get; set; } }
Dabar apibrėšime repozitorijaus interfeisą su mums reikalingomis operacijomis:
public interface IFileRepository { IEnumerable<FileMetaData> List(); byte[] Get(Uri uri); void Insert(FileMetaData metaData, byte[] file); void Delete(Uri uri); }
Aptarkime kiekvieno metodo paskirtį:
- metodas List skirtas pateikti BLOB saugykloje saugomų failų sąrašą (be tų failų duomenų)
- metodas Get gauna nurodyto failo duomenis
- metodas Insert įterpia į BLOB saugyklą failą kartu su jo metaduomenimis
- metodas Delete ištrina nurodytą failą iš BLOB saugyklos
Nesigilinant į IFileRepository realizaciją, pateiksiu Web puslapio kodą:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="HelloWorldWeb._Default" %> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Failų sąrašas</title> </head> <body> <form id="form" runat="server"> <h1>Failai</h1> Pridėti naują <asp:FileUpload ID="FileUpload" runat="server" /> <asp:Button runat="server" Text="Pridėti" OnClick="UploadFile" /> <asp:ListView ID="Files" runat="server"> <LayoutTemplate> <ul> <li id="itemPlaceHolder" runat="server" /> </ul> </LayoutTemplate> <ItemTemplate> <li> <a href='<%# Eval("Uri") %>'> <%# Eval("FileName") %> </a> <asp:LinkButton runat="server" Text="[x]" OnCommand="DeleteFile" CommandArgument='<%# Eval("Uri") %>' /> </li> </ItemTemplate> </asp:ListView> </form> </body> </html>
Kaip matote, puslapyje tėra failo pridėjimo elementas bei sąrašas jau pridėtų failų su galimybe ištrinti. Failų pavadinimas yra atvaizduojamas kaip nuoroda, kad galima būtų jį parsisiųsti paprastu paspaudimu. C# pusė atrodo taip:
public partial class _Default : Page { private readonly IFileRepository repository = new FileRepository("files", "StorageConnectionString"); protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { ListFiles(); } } protected void UploadFile(object sender, EventArgs e) { if (FileUpload.HasFile) { var file = FileUpload.FileBytes; var metaData = new FileMetaData { FileName = FileUpload.PostedFile.FileName, ContentType = FileUpload.PostedFile.ContentType }; repository.Insert(metaData, file); ListFiles(); } } protected void DeleteFile(object sender, CommandEventArgs e) { repository.Delete(new Uri(e.CommandArgument.ToString())); ListFiles(); } private void ListFiles() { Files.DataSource = repository.List(); Files.DataBind(); } }
Repozitorijaus dėka, šis ASP.NET puslapis neturi jokio supratimo apie Windows Azure panaudojimą.
FileRepository įgyvendinimas
Žemiau pateiktą FileRepository realizaciją aš pabandžiau maksimaliai paaiškinti komentarų pagalba. Atskirai norėtųsi tik paminėti FileRepository konstruktorių: jis priima du argumentus – BLOB konteinerio pavadinimą (leistinos tik mažosios raidės bei skaičiai) ir prisijungimo prie BLOB saugyklos eilutės pavadinimą iš mūsų konfigūracijos failo.
public class FileRepository : IFileRepository { private readonly CloudBlobContainer blobContainer; public FileRepository(string container, string connectionString) { // aprašome mūsų BLOB klientą var storageAccount = CloudStorageAccount.FromConfigurationSetting(connectionString); var blobClient = storageAccount.CreateCloudBlobClient(); // nustatome viešą prieigą prie duomenų var permissions = new BlobContainerPermissions(); permissions.PublicAccess = BlobContainerPublicAccessType.Container; // pagal nurodytą vardą gauname egzistuojantį konteinerį arba sukuriame naują blobContainer = blobClient.GetContainerReference(container); blobContainer.CreateIfNotExist(); blobContainer.SetPermissions(permissions); } public IEnumerable<FileMetaData> List() { // gauname informaciją apie prieinamus BLOBus var blobItems = blobContainer.ListBlobs(); var metaData = new List<FileMetaData>(); foreach (var blobItem in blobItems) { // gauname nuorodą į BLOBą... var blob = blobContainer.GetBlobReference(blobItem.Uri.ToString()); // ... ir jo meta duomenis blob.FetchAttributes(); // sukuriame objektą atvaizdavimui metaData.Add(new FileMetaData { Uri = blob.Uri, FileName = blob.Metadata["FileName"], ContentType = blob.Properties.ContentType }); } return metaData; } public byte[] Get(Uri uri) { // parsisiunčiame duomenis return blobContainer.GetBlockBlobReference(uri.ToString()).DownloadByteArray(); } public void Insert(FileMetaData metaData, byte[] file) { // sukuriame naują BLOBą var blob = blobContainer.GetBlobReference(Guid.NewGuid().ToString()); // siunčiame failo duomenis... blob.UploadByteArray(file); // ... bei nurodome meta duomenis blob.Metadata["FileName"] = metaData.FileName; blob.SetMetadata(); blob.Properties.ContentType = metaData.ContentType; blob.SetProperties(); } public void Delete(Uri uri) { // gauname nuorodą į BLOBą... var blob = blobContainer.GetBlobReference(uri.ToString()); // ir bandome jį ištrinti blob.DeleteIfExists(); } }
Kitoje dalyje…
Parodysiu kaip panaudoti realią Windows Azure BLOB saugyklą.
Atgal į: Windows Azure – 4 dalis
Kur norite publikuoti?