Kas čia? Šio puslapio pagalba gali išsaugoti įrašą tolimesniam naudojimui, arba parodyti savo draugams per socialinius tinklus. Pranešimą apie įrašą galima nusiųsti ir el. paštu.

Kur norite publikuoti?

Nusiųsk draugui el. paštu

E-mail It
2010-01-20

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:

azure14

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ą.

Patiko (0)


Atgal į: Windows Azure – 4 dalis