public async Task<IHttpActionResult> GetPhotoModel(string id) { var cache = RedisCache.Connection.GetDatabase(); var repo = new RedisRepository(cache); //Get a single item from the cache based on its ID var photo = await repo.GetPhotoByIDAsync(id); if (null == photo) { //Not in the cache. Retrieve from storage. string connectionString = SettingsHelper.LocalStorageConnectionString; string owner = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value; var storageRepo = new StorageRepository(connectionString); photo = await storageRepo.GetPhotoFromTableAsync( DAL.Azure.StorageConfig.PhotosBlobContainerName, owner, id); if (null == photo) { //Not found in cache or storage. } else { //Update the cache using the cache aside pattern. await repo.AddPhotoToUserCacheAsync(photo); } } if (null != photo) { return Ok(photo); } else { return NotFound(); } }
internal static async Task CreateThumbnailAsync(StorageRepository repo, string fileName, TextWriter log) { using (var memStream = await repo.GetBlob(StorageConfig.PhotosBlobContainerName, fileName)) { MemoryStream thumbnail = null; try { thumbnail = PhotoEditor.ProcessImage(memStream); await repo.UploadBlobAsync(thumbnail, StorageConfig.ThumbnailsBlobContainerName, fileName); } catch (Exception oops) { await log.WriteAsync(oops.Message); throw oops; } finally { if (null != thumbnail) { thumbnail.Dispose(); } } } }
public async Task<IHttpActionResult> Get() { var cache = RedisCache.Connection.GetDatabase(); var repo = new RedisRepository(cache); string owner = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value; var items = await repo.GetPhotosForUserAsync(owner); //Do this so we can get the count List<IPhotoModel> typedItems = new List<IPhotoModel>(items); if(typedItems.Count == 0) { //Nothing in cache... head off to storage. var storageRepo = new StorageRepository(SettingsHelper.LocalStorageConnectionString); var photos = await storageRepo.GetPhotosFromTableAsync( DAL.Azure.StorageConfig.TableName, owner); foreach (var photo in photos) { //TODO: Find a MUCH better algorithm than // iterating every item and calling // Redis 3 times in a row for each // item. This is PAINFUL. await repo.AddPhotoToCachesAsync(photo); } items = photos; } return Ok(items); }
internal static async Task ReplicateBlobAsync(PhotoModel model, TextWriter log) { //The source connection string needs to be in AppSettings using the //storage account name. var sourceConnectionString = ConfigurationManager.AppSettings[model.StorageAccountName]; //The target connection string is the local region's storage account var targetConnectionString = SettingsHelper.LocalStorageConnectionString; //Copy from the upload container to the photos container, // potentially across storage accounts await log.WriteLineAsync("sourceConnectionString: " + sourceConnectionString); await log.WriteLineAsync("targetConnectionString: " + targetConnectionString); var storageRepo = new StorageRepository(sourceConnectionString); var container = await storageRepo.ReplicateBlobAsync( targetConnectionString, StorageConfig.UserUploadBlobContainerName, StorageConfig.PhotosBlobContainerName, model.ServerFileName, log); //Monitor the copy operation and wait for it to finish //before proceeding await storageRepo.MonitorCopy(container, model.ServerFileName, log); }
public async Task<IHttpActionResult> Get() { var cache = RedisCache.Connection.GetDatabase(); var repo = new RedisRepository(cache); var items = await repo.GetAllPhotosAsync(); List<IPhotoModel> typedItems = new List<IPhotoModel>(items); if(typedItems.Count == 0) { //Pull from storage. This is a cross-partition query, // and will be slower than using Redis. var storageConnectionString = SettingsHelper.LocalStorageConnectionString; var storageRepo = new StorageRepository(storageConnectionString); typedItems = await storageRepo.GetLatestFromTableStorageAsync(); if(typedItems.Count > 0) { foreach (var item in typedItems) { //Add to cache as cache-aside pattern await repo.AddPhotoToAllUsersCacheAsync(item); } items = typedItems; } } return Ok(items); }
internal static async Task SaveToTableStorageAsync(PhotoModel p, TextWriter log) { var storageConnectionString = SettingsHelper.LocalStorageConnectionString; var repo = new StorageRepository(storageConnectionString); var result = await repo.SaveToTableStorageAsync(DAL.Azure.StorageConfig.TableName, p); await log.WriteLineAsync("Save to table HTTP result: " + result); }
// This function will get triggered/executed when a new message is written // on an Azure Queue called queue. public static async Task ProcessQueueMessage( [QueueTrigger("uploadqueue")] string message, TextWriter log) { log.WriteLineAsync(message).Wait(); var m = message.Split(','); await log.WriteAsync("Message received: " + m); var model = new PhotoModel { ID = m[0], ServerFileName = m[1], StorageAccountName = m[2], Owner = m[3], OwnerName = m[4], BlobURL = m[5], OriginRegion = m[6] }; //Copy blob from source to destination await log.WriteAsync("Replicating blob..."); await Helpers.ReplicateBlobAsync(model, log); try { //Change the blob URL to point to the new location! await log.WriteAsync("Getting blob URIs"); string storageConnectionString = SettingsHelper.LocalStorageConnectionString; var repo = new StorageRepository(storageConnectionString); model.BlobURL = repo.GetBlobURI(model.ServerFileName, StorageConfig.PhotosBlobContainerName).ToString(); model.ThumbnailURL = repo.GetBlobURI(model.ServerFileName, StorageConfig.ThumbnailsBlobContainerName).ToString(); //Create thumbnail await log.WriteAsync("Creating thumbnail"); await Helpers.CreateThumbnailAsync(repo, model.ServerFileName, log); //Store in table storage await log.WriteAsync("Saving to table storage"); await Helpers.SaveToTableStorageAsync(model, log); //Add to Redis cache await log.WriteAsync("Saving to Redis"); await Helpers.SaveToRedisAsync(model, log); } catch (Exception oops) { await log.WriteLineAsync(oops.Message); } }
public static async Task ProcessBroadcastQueue( [QueueTrigger("broadcastqueue")] string message, TextWriter log) { //Send a queue message to each storage account registered //in AppSettings prefixed with "Storage" foreach (string key in ConfigurationManager.AppSettings.Keys) { if (key.ToLower().StartsWith("storage")) { //This is a storage configuration var repo = new StorageRepository(ConfigurationManager.AppSettings[key]); await repo.SendQueueMessageAsync(message); } } }
public IHttpActionResult Get(string extension) { Regex rg = new Regex(@"^[a-zA-Z0-9]{1,3}$"); if(!rg.IsMatch(extension)) { throw new HttpResponseException(System.Net.HttpStatusCode.BadRequest); } string connectionString = SettingsHelper.LocalStorageConnectionString; var account = CloudStorageAccount.Parse(connectionString); StorageRepository repo = new StorageRepository(account); //Get the SAS token for the container. Allow writes for 2 minutes var sasToken = repo.GetBlobContainerSASToken(); //Get the blob so we can get the full path including container name var id = Guid.NewGuid().ToString(); var newFileName = id + "." + extension; string blobURL = repo.GetBlobURI( newFileName, DAL.Azure.StorageConfig.UserUploadBlobContainerName).ToString(); //This function determines which storage account the blob will be //uploaded to, enabling the future possibility of sharding across //multiple storage accounts. var client = account.CreateCloudBlobClient(); var response = new StorageResponse { ID = id, StorageAccountName = client.BaseUri.Authority.Split('.')[0], BlobURL = blobURL, BlobSASToken = sasToken, ServerFileName = newFileName }; return Ok(response); }
/// <summary> /// Notify the backend that a new file was uploaded /// by sending a queue message. /// </summary> /// <param name="value">The name of the blob to be processed</param> /// <returns>Void</returns> public async Task Post(CompleteRequest item) { string owner = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value; //Get the owner name field string ownerName = ClaimsPrincipal.Current.FindFirst("name").Value; //Replace any commas with periods ownerName = ownerName.Replace(',', '.'); string message = string.Format( "{0},{1},{2},{3}, {4}, {5}, {6}", item.ID, item.ServerFileName, item.StorageAccountName, owner, ownerName, item.BlobURL, SettingsHelper.CurrentRegion); //Send a queue message to the local storage account //The local web job will pick it up and broadcast to //all storage accounts in appSettings prefixed with "Storage" var repo = new StorageRepository(SettingsHelper.LocalStorageConnectionString); await repo.SendBroadcastQueueMessageAsync(message); }