using Microsoft.Azure.CosmosDB.Table; using Microsoft.Azure.Storage; using Serilog; using System; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Threading.Tasks; using webapi.Domain.Events; using webapi.Domain.SeedWork; namespace webapi.Infrastructure.Repositories { public class BaseAzureRepository: IBaseRepository where T : Entity { private static CloudStorageAccount CreateStorageAccountFromConnectionString(string storageConnectionString) { CloudStorageAccount storageAccount; try { storageAccount = CloudStorageAccount.Parse(storageConnectionString); } catch (FormatException) { Console.WriteLine("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the application."); throw; } catch (ArgumentException) { Console.WriteLine("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the sample."); Console.ReadLine(); throw; } return storageAccount; } protected readonly CloudTable _table; protected readonly ILogger _log; private readonly EventsHandlerFactory _eventsFactory; public BaseAzureRepository(ILogger log, string storageConnectionString, EventsHandlerFactory eventsFactory) { _log = log; _eventsFactory = eventsFactory; //string storageConnectionString = ConfigurationManager.ConnectionStrings["AzureProdConnectionString"].ConnectionString; //AppSettings.LoadAppSettings().StorageConnectionString; // Retrieve storage account information from connection string. CloudStorageAccount storageAccount = CreateStorageAccountFromConnectionString(storageConnectionString); // Create a table client for interacting with the table service CloudTableClient tableClient = storageAccount.CreateCloudTableClient( new TableConnectionPolicy() { UseDirectMode = false }); // new TableClientConfiguration()); var tableName = typeof(T).Name; System.Attribute[] attrs = Attribute.GetCustomAttributes(typeof(T)); if (attrs != null && attrs.Any()) { var tableAttr = (attrs.FirstOrDefault() as TableAttribute); if (tableAttr != null) tableName = tableAttr.Name; } // Create a table client for interacting with the table service var table = tableClient.GetTableReference(tableName); if (table.CreateIfNotExists()) { //Console.WriteLine("Created Table named: {0}", tableName); } else { //Console.WriteLine("Table {0} already exists", tableName); } this._table = table; } public async Task DeleteEntityAsync(T deleteEntity) { try { if (deleteEntity == null) { throw new ArgumentNullException("deleteEntity"); } if (deleteEntity.DomainEvents != null) { foreach (var evt in deleteEntity.DomainEvents) { //Process event _eventsFactory.ResolveAndRun(evt); } } TableOperation deleteOperation = TableOperation.Delete(deleteEntity); TableResult result = await _table.ExecuteAsync(deleteOperation); // Get the request units consumed by the current operation. RequestCharge of a TableResult is only applied to Azure CosmoS DB //if (result.RequestCharge.HasValue) //{ // Console.WriteLine("Request Charge of Delete Operation: " + result.RequestCharge); //} } catch (StorageException e) { //Console.WriteLine(e.Message); //Console.ReadLine(); throw e; } } public async Task SaveChanges(T entity, bool skipEntitySaving = false) { try { if (entity.DomainEvents != null) { foreach (var evt in entity.DomainEvents) { //Process event _eventsFactory.ResolveAndRun(evt); } } if(skipEntitySaving) { return entity; } _log.Information($"Start SaveChanges"); TableOperation insertOrMergeOperation = TableOperation.InsertOrMerge(entity); _log.Information($"Execute the operation."); TableResult result = await _table.ExecuteAsync(insertOrMergeOperation); _log.Information($"End SaveChanges"); // Get the request units consumed by the current operation. RequestCharge of a TableResult is only applied to Azure Cosmos DB //if (result.RequestCharge.HasValue) //{ // Console.WriteLine("Request Charge of InsertOrMerge Operation: " + result.RequestCharge); //} return result.Result as T; } catch (StorageException e) { _log.Error($"Error SaveChanges StorageException {e.Message} {e.StackTrace} {e.InnerException}", e.Message); throw e; } catch (Exception e) { _log.Error($"Error SaveChanges Exception {e.Message} {e.StackTrace} {e.InnerException}", e.Message); throw e; } } public void BatchOperation(T entity) { Console.WriteLine("******************** Start Batch Operation ********************"); var batchOperation = new TableBatchOperation(); for (var i = 2; i < 52; i++) { // I will create and add users and send them as one batch to the table. //var batchUser = new User("Karlsbad", "Admin_" + i) //{ // EMail = "alugili@gmail.com", // LastLogin = DateTimeOffset.UtcNow //}; batchOperation.Add(TableOperation.InsertOrMerge(entity)); // batchUser)); } // Executing the operations or adding the users. _table.ExecuteBatch(batchOperation); Console.WriteLine("******************** End Batch Operation ********************"); } public void ConcurrencyDemoDefaultPessimistic(CloudTable cloudTable) { Console.WriteLine("**************************** Start Demonstrate pessimistic concurrency ****************************"); //// Add new user to table. //var firstUser = new User("Karlsruhe", "Operator") //{ // EMail = "alugili@gmail.com", // LastLogin = DateTimeOffset.UtcNow //}; //var insertOrReplaceOperation = TableOperation.InsertOrReplace(firstUser); //cloudTable.Execute(insertOrReplaceOperation); //Console.WriteLine("Entity added. Original ETag = {0}", firstUser.ETag); //// Someone else has changed the first user! //var updatedFirstUser = new User("Karlsruhe", "Operator") //{ // EMail = "bassam.alugili@hotmail.de", // LastLogin = DateTimeOffset.UtcNow //}; //insertOrReplaceOperation = TableOperation.InsertOrReplace(updatedFirstUser); //cloudTable.Execute(insertOrReplaceOperation); //Console.WriteLine("Entity updated. Updated ETag = {0}", updatedFirstUser.ETag); //// Try updating first user. Etag is cached within firstUser and passed by default //firstUser.LastLogin = DateTimeOffset.UtcNow; //insertOrReplaceOperation = TableOperation.Merge(firstUser); //try //{ // Console.WriteLine("Trying to update Original entity"); // cloudTable.Execute(insertOrReplaceOperation); //} //catch (StorageException ex) //{ // if (ex.RequestInformation.HttpStatusCode == (int)HttpStatusCode.PreconditionFailed) // { // Console.WriteLine("Error: Entity Tag is changed!"); // } // else // { // throw; // } //} Console.WriteLine("**************************** End Demonstrate pessimistic concurrency ****************************"); } } }