„Dieser Blog Post ist Teil der Serie „Cloud Computing mit Windows Azure“, alle bisher erschienenen Artikel finden Sie im ersten Posting der Serie!“
In diesem Teil wollen wir uns um das Datenmodell kümmern, welches auch in ASP.NET als Datenquelle mit Datenbindung verwendet werden kann. Zu Beginn müssen wir in die “WebRole.cs” Code in die “OnStart”-Methode einfügen. Dies ist notwendig, damit die Konfigurationseinstellungen gelesen werden. Der Hintergrund ist nämlich das der Windows Azure Storage Client auch mit anderen Projekttypen zusammen arbeiten kann. Hierfür wird folgende Region eingefügt:
#region Role Definition
CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
{
configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
RoleEnvironment.Changed += (sender, arg) =>
{
if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>().Any
((change) => (change.ConfigurationSettingName == configName)))
{
if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
{
RoleEnvironment.RequestRecycle();
}
}
};
});
#endregion
Nun erstellen wir eine neue Klasse vom Typ “FotoAlbumDataSource”. Als erster werden die beiden Datenkontexte, “ImagesContext” und “FotoalbumContext” angelegt. Ferner wird auch noch ein “CloudStorageAccount” und ein “CloudBlobClient” benötigt. Im Konstruktor wird der “CloudStorageAccount” aus der Konfiguration geladen. Diese wurde bereits in einem früheren Post angelegt und trägt den Namen “DevStore”. Nun generiert man sich den CloudBlobClient, die Kontexte und erstellt den TableClient. Mit den TableClient werden nun die Tabellen erstellt, sofern diese noch nicht vorhanden sind.
public class FotoAlbumDataSource
{
private ImagesContext imagesContext = null;
private FotoalbumContext albumContext = null;
private CloudBlobClient blobClient = null;
private CloudStorageAccount account = null;
public FotoAlbumDataSource()
{
account = CloudStorageAccount.FromConfigurationSetting("DevStore");
blobClient = account.CreateCloudBlobClient();
imagesContext = new ImagesContext(account.TableEndpoint.ToString(), account.Credentials);
albumContext = new FotoalbumContext(account.TableEndpoint.ToString(), account.Credentials);
CloudTableClient client = account.CreateCloudTableClient();
client.CreateTableIfNotExist(ImagesContext.TableName);
client.CreateTableIfNotExist(FotoalbumContext.TableName);
}
Nun ist es auch notwendig, das Bilder in einem Container upgeloaded werden können. Hierfür erstellen wir eine Methode “CreatePublicBlob”. Hierbei wird ein neuer Container im Blob Storage mit einem bestimmten Namen erstellt. Zu Beginn fragen wir diesen Container ab und erstellen diesen, sofern der Container nicht bereits vorhanden ist. Danach werden noch die Zugriffseinstellungen mittels “BlobContainerPersmissions” gesetzt. Hierbei wird “PublicAccess” gewählt. Diese Regeln werden dann dem Container zugewiesen.
public void CreatePublicBlob(string name)
{
CloudBlobContainer blobContainer = blobClient.GetContainerReference(name);
blobContainer.CreateIfNotExist();
BlobContainerPermissions permissions = new BlobContainerPermissions();
permissions.PublicAccess = BlobContainerPublicAccessType.Container;
blobContainer.SetPermissions(permissions);
}
In weiterer Folge soll es auch möglich sein, Bilder in einem Container einzufügen. Hierfür brauchen wir eine Funktion, welche den Dateinamen, den Container, den Content-Type und den Stream bekommt. Zu beginn erstellen wir einen neuen Dateinamen mithilfe einer GUID, damit der selbe Dateiname nicht öfter vorkommen kann. Dann wird dem Container der Stream mit der Methode “UploadFromStream” eingefügt. Ferner müssen auch noch die Properties gesetzt werden. Als Rückgabewert verwenden wir nun den Pfad der Datei.
public string AddImage(string fileName, string blobContainer, string contentType, Stream content)
{
string ext = Path.GetExtension(fileName);
string filename = Guid.NewGuid().ToString() + ext;
CloudBlobContainer container = blobClient.GetContainerReference(blobContainer);
CloudBlob blob = container.GetBlobReference(filename);
blob.UploadFromStream(content);
blob.Properties.ContentType = contentType;
blob.SetProperties();
return string.Format("{0}/{1}/{2}", account.BlobEndpoint.AbsoluteUri, blobContainer, filename);
}
Damit man auch Daten aus der Datenquelle abfragen kann, erstellen wir eine Funktion welche einen Select auf die Images ausführt. Hierbei müssen diese jedoch den Album-Key haben, damit diese auch tatsächlich zum Album gehören. doch ist hier Vorsicht geboten, wenn man die “Where”-Funktion verwendet. Wurde die Tabelle nämlich noch nicht benutzt, so würde hier eine Exception geworfen, da “Album” für die Entität nicht bekannt ist. Daher muss vorher überprüft werden, ob sich Entitäten in der Tabelle befinden. Dies geschieht mit einer Hilfsmethode “ContainsImages”, wo das erste Element der Tabelle abgefragt wird. Wenn dieses null ist, wird false zurück geliefert und es kann kein Vergleich erstellt werden.
public IEnumerable<ImageEntity> Select(string key)
{
CloudTableQuery<ImageEntity> result;
if (ContainsImages())
{
result = (from r in imagesContext.Fotos
where r.Album == key
select r).AsTableServiceQuery<ImageEntity>();
}
else
{
result = (from c in imagesContext.Fotos
select c).AsTableServiceQuery<ImageEntity>();
}
return result.Execute();
}
private bool ContainsImages()
{
ImageEntity ent = imagesContext.Fotos.FirstOrDefault();
return ent != null;
}
Nun sollen noch die Alben abgefragt werden. Dies gestaltet sich wesentlich einfacher als die vorherige Methode. Hierbei werden alle Entitäten aus der Tabelle “Albums” abgefragt.
public IEnumerable<FotoalbumEntity> Albums()
{
var results = (from c in albumContext.Albums
select c).AsTableServiceQuery<FotoalbumEntity>();
return results.Execute();
}
Der Vollständigkeit halber sollen auch noch Methoden fürs Löschen, Einfügen und erstellen von Alben angegeben werden. Hier muss man die Entität “attachen” und dann die Aktion auf jene durchführen. Wichtig ist auch noch, dies am Ende zu speichern.
public void Delete(ImageEntity item)
{
imagesContext.AttachTo(ImagesContext.TableName, item, "*");
imagesContext.DeleteObject(item);
imagesContext.SaveChanges();
}
public void Insert(ImageEntity item)
{
imagesContext.AddObject(ImagesContext.TableName, item);
imagesContext.SaveChanges();
}
public void CreateAlbum(FotoalbumEntity album)
{
albumContext.AddObject(FotoalbumContext.TableName, album);
albumContext.SaveChanges();
}
Im nächsten Schritt können wir uns auch bereits der ASP.NET Seite widmen.

Mario Meir-Huber
Web: www.meirhuber.de
Twitter: www.twitter.com/mario_mh