This commit is contained in:
Jef King 2017-06-07 14:31:41 -07:00
Родитель 5a17c5ae66 94b0aca9ec
Коммит a69be13462
37 изменённых файлов: 5897 добавлений и 24 удалений

22
.gitattributes поставляемый Normal file
Просмотреть файл

@ -0,0 +1,22 @@
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

Просмотреть файл

@ -0,0 +1,106 @@
namespace King.Azure.Integration.Test.Data
{
using King.Azure.Data;
using NUnit.Framework;
using System;
using System.Linq;
using System.Threading.Tasks;
[TestFixture]
public class AzureStorageResourcesTests
{
private readonly string ConnectionString = "UseDevelopmentStorage=true;";
[Test]
public async Task TableNames()
{
var name = 'a' + Guid.NewGuid().ToString().ToLowerInvariant().Replace('-', 'a');
var storage = new TableStorage(name, ConnectionString);
var created = await storage.CreateIfNotExists();
var resources = new AzureStorageResources(ConnectionString);
var tables = await resources.TableNames();
Assert.IsTrue(tables.Contains(name));
}
[Test]
public async Task Tables()
{
var name = 'a' + Guid.NewGuid().ToString().ToLowerInvariant().Replace('-', 'a');
var storage = new TableStorage(name, ConnectionString);
var created = await storage.CreateIfNotExists();
var resources = new AzureStorageResources(ConnectionString);
var tables = await resources.Tables();
var exists = (from t in tables
where t.Name == name
select true).FirstOrDefault();
Assert.IsTrue(exists);
}
[Test]
public async Task QueueNames()
{
var name = 'a' + Guid.NewGuid().ToString().ToLowerInvariant().Replace('-', 'a');
var storage = new StorageQueue(name, ConnectionString);
var created = await storage.CreateIfNotExists();
var resources = new AzureStorageResources(ConnectionString);
var queues = await resources.QueueNames();
Assert.IsTrue(queues.Contains(name));
}
[Test]
public async Task Queues()
{
var name = 'a' + Guid.NewGuid().ToString().ToLowerInvariant().Replace('-', 'a');
var storage = new StorageQueue(name, ConnectionString);
var created = await storage.CreateIfNotExists();
var resources = new AzureStorageResources(ConnectionString);
var queues = await resources.Queues();
var exists = (from q in queues
where q.Name == name
select true).FirstOrDefault();
Assert.IsTrue(exists);
await storage.Delete();
}
[Test]
public async Task ContainerNames()
{
var name = 'a' + Guid.NewGuid().ToString().ToLowerInvariant().Replace('-', 'a');
var storage = new Container(name, ConnectionString);
var created = await storage.CreateIfNotExists();
var resources = new AzureStorageResources(ConnectionString);
var containers = await resources.ContainerNames();
Assert.IsTrue(containers.Contains(name));
}
[Test]
public async Task Containers()
{
var name = 'a' + Guid.NewGuid().ToString().ToLowerInvariant().Replace('-', 'a');
var storage = new Container(name, ConnectionString);
var created = await storage.CreateIfNotExists();
var resources = new AzureStorageResources(ConnectionString);
var containers = await resources.Containers();
var exists = (from c in containers
where c.Name == name
select true).FirstOrDefault();
Assert.IsTrue(exists);
}
}
}

Просмотреть файл

@ -0,0 +1,549 @@
namespace King.Service.Integration
{
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using King.Azure.Data;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using NUnit.Framework;
[TestFixture]
public class ContainerTests
{
private readonly string ConnectionString = "UseDevelopmentStorage=true;";
private readonly string ContainerName = 'a' + Guid.NewGuid().ToString().Replace("-", "");
#region Helper
private class Helper
{
public Guid Id
{
get;
set;
}
}
#endregion
[SetUp]
public void SetUp()
{
var storage = new Container(ContainerName, ConnectionString);
storage.CreateIfNotExists().Wait();
}
[TearDown]
public void TearDown()
{
var storage = new Container(ContainerName, ConnectionString);
storage.Delete().Wait();
}
[Test]
public async Task ConstructorAccount()
{
var name = 'a' + Guid.NewGuid().ToString().ToLowerInvariant().Replace('-', 'a');
var account = CloudStorageAccount.Parse(ConnectionString);
var storage = new Container(name, account);
var created = await storage.CreateIfNotExists();
Assert.IsTrue(created);
}
[Test]
public async Task CreateIfNotExists()
{
var name = 'a' + Guid.NewGuid().ToString().ToLowerInvariant().Replace('-', 'a');
var storage = new Container(name, ConnectionString);
var created = await storage.CreateIfNotExists();
Assert.IsTrue(created);
var blobClient = storage.Account.CreateCloudBlobClient();
var container = blobClient.GetContainerReference(name);
var permissions = await container.GetPermissionsAsync();
Assert.AreEqual(BlobContainerPublicAccessType.Off, permissions.PublicAccess);
}
[Test]
public async Task CreateIfNotExistsPublic()
{
var name = 'a' + Guid.NewGuid().ToString().ToLowerInvariant().Replace('-', 'a');
var storage = new Container(name, ConnectionString, true);
var created = await storage.CreateIfNotExists();
Assert.IsTrue(created);
var blobClient = storage.Account.CreateCloudBlobClient();
var container = blobClient.GetContainerReference(name);
var permissions = await container.GetPermissionsAsync();
Assert.AreEqual(BlobContainerPublicAccessType.Blob, permissions.PublicAccess);
}
[Test]
public async Task Exists()
{
var blobName = Guid.NewGuid().ToString();
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(blobName, Guid.NewGuid());
var exists = await storage.Exists(blobName);
Assert.IsTrue(exists);
}
[Test]
public async Task ExistsNo()
{
var blobName = Guid.NewGuid().ToString();
var storage = new Container(ContainerName, ConnectionString);
var exists = await storage.Exists(blobName);
Assert.IsFalse(exists);
}
[Test]
public async Task GetBlockReference()
{
var name = string.Format("{0}.bin", Guid.NewGuid());
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(name, new Helper());
var block = storage.GetBlockReference(name);
Assert.IsNotNull(block);
Assert.IsTrue(block.Exists());
}
[Test]
public async Task GetPageReference()
{
var random = new Random();
var bytes = new byte[1024];
random.NextBytes(bytes);
var name = string.Format("{0}.bin", Guid.NewGuid());
var storage = new Container(ContainerName, ConnectionString);
var blob = storage.Reference.GetPageBlobReference(name);
await blob.CreateAsync(1024);
await blob.UploadFromByteArrayAsync(bytes, 0, bytes.Length);
var page = storage.GetPageReference(name);
Assert.IsNotNull(page);
Assert.IsTrue(page.Exists());
}
[Test]
public async Task RoundTripObject()
{
var helper = new Helper()
{
Id = Guid.NewGuid(),
};
var blobName = Guid.NewGuid().ToString();
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(blobName, helper);
var returned = await storage.Get<Helper>(blobName);
Assert.IsNotNull(returned);
Assert.AreEqual(helper.Id, returned.Id);
var properties = await storage.Properties(blobName);
Assert.IsNotNull(properties);
Assert.AreEqual("application/json", properties.ContentType);
}
[Test]
public async Task RoundTripText()
{
var data = Guid.NewGuid().ToString();
var blobName = Guid.NewGuid().ToString();
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(blobName, data);
var returned = await storage.GetText(blobName);
Assert.IsNotNull(returned);
Assert.AreEqual(data, returned);
var properties = await storage.Properties(blobName);
Assert.IsNotNull(properties);
Assert.AreEqual("text/plain", properties.ContentType);
}
[Test]
public async Task JsonContentType()
{
var helper = new Helper()
{
Id = Guid.NewGuid(),
};
var blobName = Guid.NewGuid().ToString();
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(blobName, helper);
var returned = await storage.Properties(blobName);
Assert.IsNotNull(returned);
Assert.AreEqual("application/json", returned.ContentType);
}
[Test]
public async Task RoundTripBytes()
{
var random = new Random();
var bytes = new byte[1024];
random.NextBytes(bytes);
var blobName = Guid.NewGuid().ToString();
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(blobName, bytes);
var returned = await storage.Get(blobName);
Assert.IsNotNull(returned);
Assert.AreEqual(bytes.Length, returned.Length);
Assert.AreEqual(bytes, returned);
var properties = await storage.Properties(blobName);
Assert.IsNotNull(properties);
Assert.AreEqual("application/octet-stream", properties.ContentType);
}
[Test]
public async Task RoundTripStream()
{
var random = new Random();
var bytes = new byte[1024];
random.NextBytes(bytes);
var blobName = Guid.NewGuid().ToString();
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(blobName, bytes);
using (var returned = await storage.Stream(blobName) as MemoryStream)
{
var stored = returned.ToArray();
Assert.IsNotNull(stored);
Assert.AreEqual(bytes.Length, stored.Length);
Assert.AreEqual(bytes, stored);
}
}
[Test]
public async Task BytesDefaultContentType()
{
var random = new Random();
var bytes = new byte[1024];
random.NextBytes(bytes);
var blobName = Guid.NewGuid().ToString();
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(blobName, bytes);
var returned = await storage.Properties(blobName);
Assert.IsNotNull(returned);
Assert.AreEqual(bytes.Length, returned.Length);
Assert.AreEqual("application/octet-stream", returned.ContentType);
}
[Test]
public async Task BytesContentType()
{
var random = new Random();
var bytes = new byte[1024];
random.NextBytes(bytes);
var blobName = Guid.NewGuid().ToString();
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(blobName, bytes, "application/pdf");
var returned = await storage.Properties(blobName);
Assert.IsNotNull(returned);
Assert.AreEqual(bytes.Length, returned.Length);
Assert.AreEqual("application/pdf", returned.ContentType);
}
[Test]
public async Task Delete()
{
var helper = new Helper()
{
Id = Guid.NewGuid(),
};
var blobName = Guid.NewGuid().ToString();
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(blobName, helper);
await storage.Delete(blobName);
Assert.That(() => storage.Get<Helper>(blobName), Throws.TypeOf<StorageException>());
}
[Test]
public async Task List()
{
var random = new Random();
var bytes = new byte[16];
random.NextBytes(bytes);
var count = random.Next(1, 32);
var storage = new Container(ContainerName, ConnectionString);
for (var i = 0; i < count; i++)
{
var blobName = Guid.NewGuid().ToString();
await storage.Save(blobName, bytes);
}
var blobs = await storage.List();
Assert.AreEqual(count, blobs.Count());
}
[Test]
public async Task SnapShotPageBlob()
{
var random = new Random();
var bytes = new byte[1024];
random.NextBytes(bytes);
var name = string.Format("{0}.bin", Guid.NewGuid());
var storage = new Container(ContainerName, ConnectionString);
var blob = storage.Reference.GetPageBlobReference(name);
await blob.CreateAsync(1024);
await blob.UploadFromByteArrayAsync(bytes, 0, bytes.Length);
var snapshot = await storage.Snapshot(name);
Assert.IsTrue(snapshot.IsSnapshot);
var returned = storage.GetPageReference(snapshot.Name, snapshot.SnapshotTime);
Assert.IsNotNull(returned);
Assert.IsTrue(returned.IsSnapshot);
}
[Test]
public async Task SnapShotBlockBlob()
{
var random = new Random();
var bytes = new byte[16];
random.NextBytes(bytes);
var name = string.Format("{0}.bin", Guid.NewGuid());
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(name, bytes);
var snapshot = await storage.Snapshot(name);
Assert.IsTrue(snapshot.IsSnapshot);
var returned = storage.GetPageReference(snapshot.Name, snapshot.SnapshotTime);
Assert.IsNotNull(returned);
Assert.IsTrue(returned.IsSnapshot);
}
[Test]
public async Task SnapShoAndDelete()
{
var random = new Random();
var bytes = new byte[16];
random.NextBytes(bytes);
var name = string.Format("{0}.bin", Guid.NewGuid());
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(name, bytes);
var snapshot = await storage.Snapshot(name);
await storage.Delete(name);
}
[Test]
public async Task SnapShoAndDeleteSafe()
{
var random = new Random();
var bytes = new byte[16];
random.NextBytes(bytes);
var name = string.Format("{0}.bin", Guid.NewGuid());
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(name, bytes);
var snapshot = await storage.Snapshot(name);
Assert.That(() => storage.Delete(name, false), Throws.TypeOf<StorageException>());
}
[Test]
public async Task SnapshotNonExistant()
{
var blob = Guid.NewGuid().ToString();
var storage = new Container(ContainerName, ConnectionString);
Assert.IsNull(await storage.Snapshot(blob));
}
[Test]
public async Task DontLoseContentType()
{
var cache = "public, max-age=31536000";
var contentType = "text/guid";
var blobName = Guid.NewGuid().ToString();
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(blobName, Guid.NewGuid().ToString(), contentType);
await storage.SetCacheControl(blobName);
var returned = await storage.Properties(blobName);
Assert.IsNotNull(returned);
Assert.AreEqual(cache, returned.CacheControl);
Assert.AreEqual(contentType, returned.ContentType);
}
[Test]
public async Task DontLoseCacheControl()
{
var cache = "public, max-age=31536000";
var contentType = "text/guid";
var blobName = Guid.NewGuid().ToString();
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(blobName, Guid.NewGuid().ToString(), contentType);
await storage.SetCacheControl(blobName);
await storage.Save(blobName, Guid.NewGuid().ToString(), contentType);
var returned = await storage.Properties(blobName);
Assert.IsNotNull(returned);
Assert.AreEqual(cache, returned.CacheControl);
Assert.AreEqual(contentType, returned.ContentType);
}
[Test]
public async Task SetCacheControlDefault()
{
var cache = "public, max-age=31536000";
var blobName = Guid.NewGuid().ToString();
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(blobName, Guid.NewGuid().ToString());
await storage.SetCacheControl(blobName);
var returned = await storage.Properties(blobName);
Assert.IsNotNull(returned);
Assert.AreEqual(cache, returned.CacheControl);
}
[Test]
public async Task SetCacheControlZero()
{
var cache = "public, max-age=31536000";
var blobName = Guid.NewGuid().ToString();
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(blobName, Guid.NewGuid().ToString());
await storage.SetCacheControl(blobName, 0);
var returned = await storage.Properties(blobName);
Assert.IsNotNull(returned);
Assert.AreEqual(cache, returned.CacheControl);
}
[Test]
public async Task SetCacheControl()
{
var cache = "public, max-age=1000";
var blobName = Guid.NewGuid().ToString();
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(blobName, Guid.NewGuid().ToString());
await storage.SetCacheControl(blobName, 1000);
var returned = await storage.Properties(blobName);
Assert.IsNotNull(returned);
Assert.AreEqual(cache, returned.CacheControl);
}
[Test]
public async Task CopyToFrom()
{
var random = new Random();
var bytes = new byte[16];
random.NextBytes(bytes);
var from = string.Format("{0}.bin", Guid.NewGuid());
var to = string.Format("{0}.bin", Guid.NewGuid());
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(from, bytes);
var uri = await storage.Copy(from, to);
Assert.IsNotNull(uri);
var exists = await storage.Exists(to);
var data = await storage.Get(to);
Assert.AreEqual(bytes, data);
await storage.Delete(from);
await storage.Delete(to);
}
[Test]
public async Task Copy()
{
var random = new Random();
var bytes = new byte[16];
random.NextBytes(bytes);
var toContainerName = 'a' + Guid.NewGuid().ToString().Replace("-", string.Empty);
var toContainer = new Container(toContainerName, ConnectionString);
await toContainer.CreateIfNotExists();
var from = string.Format("{0}.bin", Guid.NewGuid());
var to = string.Format("{0}.bin", Guid.NewGuid());
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(from, bytes);
var uri = await storage.Copy(from, toContainer, to);
Assert.IsNotNull(uri);
var exists = await toContainer.Exists(to);
var data = await toContainer.Get(to);
Assert.AreEqual(bytes, data);
await storage.Delete(from);
await toContainer.Delete(to);
await toContainer.Delete();
}
[Test]
public async Task CopyContainerName()
{
var random = new Random();
var bytes = new byte[16];
random.NextBytes(bytes);
var toContainerName = 'a' + Guid.NewGuid().ToString().Replace("-", string.Empty);
var toContainer = new Container(toContainerName, ConnectionString);
await toContainer.CreateIfNotExists();
var from = string.Format("{0}.bin", Guid.NewGuid());
var to = string.Format("{0}.bin", Guid.NewGuid());
var storage = new Container(ContainerName, ConnectionString);
await storage.Save(from, bytes);
var uri = await storage.Copy(from, toContainerName, to);
Assert.IsNotNull(uri);
var exists = await toContainer.Exists(to);
var data = await toContainer.Get(to);
Assert.AreEqual(bytes, data);
await storage.Delete(from);
await toContainer.Delete(to);
await toContainer.Delete();
}
}
}

Просмотреть файл

@ -0,0 +1,23 @@
namespace King.Azure.Integration.Test.Data
{
using System;
using System.Threading.Tasks;
using King.Azure.Data;
using NUnit.Framework;
[TestFixture]
public class FileShareTests
{
private const string ConnectionString = "DefaultEndpointsProtocol=https;AccountName=kingdottest;AccountKey=DESdtrm9Rj+pOzS1XGIvnmuzMJN+mvOAlwy75CWJxWKPYmVNQyuSwhUG/UcAzb3/Q1c+pHdMxddvXBzDuwevxQ==;FileEndpoint=https://kingdottest.file.core.windows.net/";
[Test]
public async Task CreateIfNotExists()
{
var random = new Random();
var storage = new FileShare(string.Format("a{0}b", random.Next()), ConnectionString);
var created = await storage.CreateIfNotExists();
Assert.IsTrue(created);
}
}
}

Просмотреть файл

@ -0,0 +1,163 @@
namespace King.Service.Integration
{
using System;
using System.Linq;
using System.Threading.Tasks;
using King.Azure.Data;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Queue;
using Newtonsoft.Json;
using NUnit.Framework;
[TestFixture]
public class QueueTests
{
private const string ConnectionString = "UseDevelopmentStorage=true;";
private const string QueueName = "testing";
[SetUp]
public void SetUp()
{
var storage = new StorageQueue(QueueName, ConnectionString);
storage.CreateIfNotExists().Wait();
}
[TearDown]
public void TearDown()
{
var storage = new StorageQueue(QueueName, ConnectionString);
storage.Delete().Wait();
}
[Test]
public async Task CreateIfNotExists()
{
var name = 'a' + Guid.NewGuid().ToString().ToLowerInvariant().Replace('-', 'a');
var storage = new StorageQueue(name, ConnectionString);
var created = await storage.CreateIfNotExists();
Assert.IsTrue(created);
}
[Test]
public async Task ConstructorAccount()
{
var name = 'a' + Guid.NewGuid().ToString().ToLowerInvariant().Replace('-', 'a');
var account = CloudStorageAccount.Parse(ConnectionString);
var storage = new StorageQueue(name, account, TimeSpan.FromSeconds(34));
var created = await storage.CreateIfNotExists();
Assert.IsTrue(created);
}
[Test]
public async Task RoundTrip()
{
var storage = new StorageQueue(QueueName, ConnectionString);
var msg = new CloudQueueMessage(Guid.NewGuid().ToByteArray());
await storage.Send(msg);
var returned = await storage.Get();
Assert.AreEqual(msg.AsBytes, returned.AsBytes);
}
[Test]
public async Task RoundTripMsgAsObj()
{
var storage = new StorageQueue(QueueName, ConnectionString);
var msg = new CloudQueueMessage(Guid.NewGuid().ToByteArray());
await storage.Send((object)msg);
var returned = await storage.Get();
Assert.AreEqual(msg.AsBytes, returned.AsBytes);
}
[Test]
public async Task RoundTripObject()
{
var storage = new StorageQueue(QueueName, ConnectionString);
var expected = Guid.NewGuid();
await storage.Send(expected);
var returned = await storage.Get();
var guid = JsonConvert.DeserializeObject<Guid>(returned.AsString);
Assert.AreEqual(expected, guid);
}
[Test]
public async Task ApproixmateMessageCount()
{
var random = new Random();
var count = random.Next(1, 1000);
var storage = new StorageQueue(QueueName, ConnectionString);
for (var i = 0; i < count; i++)
{
await storage.Send(Guid.NewGuid());
}
var result = await storage.ApproixmateMessageCount();
Assert.AreEqual(count, result);
}
[Test]
public async Task ApproixmateMessageCountNone()
{
var storage = new StorageQueue(QueueName, ConnectionString);
var result = await storage.ApproixmateMessageCount();
Assert.AreEqual(0, result);
}
[Test]
public async Task Delete()
{
var storage = new StorageQueue(QueueName, ConnectionString);
var msg = new CloudQueueMessage(Guid.NewGuid().ToByteArray());
await storage.Send(msg);
var returned = await storage.Get();
await storage.Delete(returned);
}
[Test]
public async Task RoundTripMany()
{
var random = new Random();
var count = random.Next(1, 25);
var storage = new StorageQueue(QueueName, ConnectionString);
for (var i = 0; i < count; i++)
{
var msg = new CloudQueueMessage(Guid.NewGuid().ToByteArray());
await storage.Send(msg);
}
var returned = await storage.GetMany(count);
Assert.AreEqual(count, returned.Count());
}
[Test]
public async Task GetManyNegative()
{
var random = new Random();
var count = random.Next(1, 25);
var storage = new StorageQueue(QueueName, ConnectionString);
for (var i = 0; i < count; i++)
{
var msg = new CloudQueueMessage(Guid.NewGuid().ToByteArray());
await storage.Send(msg);
}
var returned = await storage.GetMany(-1);
Assert.AreEqual(1, returned.Count());
}
}
}

Просмотреть файл

@ -0,0 +1,870 @@
namespace King.Service.Integration
{
using King.Azure.Data;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
[TestFixture]
public class TableStorageTests
{
#region Members
private readonly string ConnectionString = "UseDevelopmentStorage=true;";
private ITableStorage storage = null;
#endregion
public class Helper : TableEntity
{
public Guid Id
{
get;
set;
}
}
[SetUp]
public void Init()
{
var table = "testing";
this.storage = new TableStorage(table, ConnectionString);
storage.CreateIfNotExists().Wait();
}
[TearDown]
public void Dispose()
{
storage.Delete().Wait();
}
[Test]
public async Task ConstructorAccount()
{
var name = 'a' + Guid.NewGuid().ToString().ToLowerInvariant().Replace('-', 'a');
var account = CloudStorageAccount.Parse(ConnectionString);
var storage = new TableStorage(name, account);
var created = await storage.CreateIfNotExists();
Assert.IsTrue(created);
}
[Test]
public async Task CreateIfNotExists()
{
var table = 'a' + Guid.NewGuid().ToString().ToLowerInvariant().Replace('-', 'a');
var storage = new TableStorage(table, ConnectionString);
var created = await storage.CreateIfNotExists();
Assert.IsTrue(created);
await storage.Delete();
}
[Test]
public async Task CreateIfNotExistsAlreadyExists()
{
var table = 'a' + Guid.NewGuid().ToString().ToLowerInvariant().Replace('-', 'a');
var storage = new TableStorage(table, ConnectionString);
var created = await storage.CreateIfNotExists();
Assert.IsTrue(created);
created = await storage.CreateIfNotExists();
Assert.IsFalse(created);
await storage.Delete();
}
[Test]
public async Task Create()
{
var table = 'a' + Guid.NewGuid().ToString().ToLowerInvariant().Replace('-', 'a');
var storage = new TableStorage(table, ConnectionString);
var created = await storage.Create();
Assert.IsTrue(created);
await storage.Delete();
}
[Test]
public async Task Delete()
{
var table = 'a' + Guid.NewGuid().ToString().ToLowerInvariant().Replace('-', 'a');
var storage = new TableStorage(table, ConnectionString);
var created = await storage.Create();
Assert.IsTrue(created);
await storage.Delete();
created = await storage.Create();
Assert.IsTrue(created);
await storage.Delete();
}
[Test]
public async Task Insert()
{
var entity = new TableEntity()
{
PartitionKey = "partition",
RowKey = "row",
};
var entities = new List<TableEntity>();
entities.Add(entity);
await storage.Insert(entities);
var returned = await storage.QueryByPartition<TableEntity>("partition");
Assert.IsNotNull(returned);
Assert.AreEqual(1, returned.Count());
var e = returned.First();
Assert.AreEqual(entity.PartitionKey, e.PartitionKey);
Assert.AreEqual(entity.RowKey, e.RowKey);
}
[Test]
public async Task InsertOrReplace()
{
var entity = new TableEntity()
{
PartitionKey = "partition",
RowKey = "row",
};
var entities = new List<TableEntity>();
entities.Add(entity);
await storage.InsertOrReplace(entity);
var returned = await storage.QueryByPartition<TableEntity>("partition");
Assert.IsNotNull(returned);
Assert.AreEqual(1, returned.Count());
var e = returned.First();
Assert.AreEqual(entity.PartitionKey, e.PartitionKey);
Assert.AreEqual(entity.RowKey, e.RowKey);
}
[Test]
public async Task InsertBatch()
{
var random = new Random();
var count = random.Next(1, 25);
var partition = Guid.NewGuid().ToString();
var entities = new List<TableEntity>(count);
for (var i = 0; i < count; i++)
{
var entity = new TableEntity()
{
PartitionKey = partition,
RowKey = Guid.NewGuid().ToString(),
};
entities.Add(entity);
}
await storage.Insert(entities);
var returned = await storage.QueryByPartition<TableEntity>(partition);
Assert.IsNotNull(returned);
Assert.AreEqual(count, returned.Count());
}
[Test]
public async Task InsertBatchMultiplePartitions()
{
var random = new Random();
var count = random.Next(1, 25);
var partition = Guid.NewGuid().ToString();
var entities = new List<TableEntity>(count);
for (var i = 0; i < count; i++)
{
var entity = new TableEntity()
{
PartitionKey = partition,
RowKey = Guid.NewGuid().ToString(),
};
entities.Add(entity);
if (i % 2 == 0)
{
partition = Guid.NewGuid().ToString();
}
}
await storage.Insert(entities);
var returned = await storage.Query<TableEntity>(new TableQuery<TableEntity>());
Assert.IsNotNull(returned);
Assert.AreEqual(count, returned.Count());
}
[Test]
public async Task InsertDictionaryBatch()
{
var random = new Random();
var count = random.Next(1, 25);
var partition = Guid.NewGuid().ToString();
var entities = new List<IDictionary<string, object>>(count);
for (var i = 0; i < count; i++)
{
var dic = new Dictionary<string, object>();
dic.Add(TableStorage.PartitionKey, partition);
dic.Add(TableStorage.RowKey, Guid.NewGuid());
dic.Add("Extraa", DateTime.UtcNow);
entities.Add(dic);
}
await storage.Insert(entities);
var query = new TableQuery();
query.Where(TableQuery.GenerateFilterCondition(TableStorage.PartitionKey, QueryComparisons.Equal, partition));
var returned = await storage.Query(query);
Assert.IsNotNull(returned);
Assert.AreEqual(count, returned.Count());
}
[Test]
public async Task InsertDictionaryBatchMultiplePartitions()
{
var random = new Random();
var count = random.Next(1, 25);
var partition = Guid.NewGuid().ToString();
var entities = new List<IDictionary<string, object>>(count);
for (var i = 0; i < count; i++)
{
var dic = new Dictionary<string, object>();
dic.Add(TableStorage.PartitionKey, partition);
dic.Add(TableStorage.RowKey, Guid.NewGuid());
dic.Add("Extraa", DateTime.UtcNow);
entities.Add(dic);
if (i % 2 == 0)
{
partition = Guid.NewGuid().ToString();
}
}
await storage.Insert(entities);
var returned = await storage.Query(new TableQuery());
Assert.IsNotNull(returned);
Assert.AreEqual(count, returned.Count());
}
[Test]
public async Task InsertOrReplaceDictionary()
{
var p = Guid.NewGuid().ToString();
var r = Guid.NewGuid().ToString();
var entity = new Dictionary<string, object>();
entity.Add(TableStorage.PartitionKey, p);
entity.Add(TableStorage.RowKey, r);
entity.Add("Id", Guid.NewGuid());
await storage.InsertOrReplace(entity);
var e = await storage.QueryByPartitionAndRow<Helper>(p, r);
Assert.IsNotNull(e);
Assert.AreEqual(entity[TableStorage.PartitionKey], e.PartitionKey);
Assert.AreEqual(entity[TableStorage.RowKey], e.RowKey);
Assert.AreEqual(entity["Id"], e.Id);
}
[Test]
public async Task InsertOrReplaceDictionaryPartitionRowGuid()
{
var p = Guid.NewGuid();
var r = Guid.NewGuid();
var entity = new Dictionary<string, object>();
entity.Add(TableStorage.PartitionKey, p);
entity.Add(TableStorage.RowKey, r);
entity.Add("Id", Guid.NewGuid());
await storage.InsertOrReplace(entity);
var e = await storage.QueryByPartitionAndRow<Helper>(p.ToString(), r.ToString());
Assert.IsNotNull(e);
Assert.AreEqual(entity[TableStorage.PartitionKey].ToString(), e.PartitionKey);
Assert.AreEqual(entity[TableStorage.RowKey].ToString(), e.RowKey);
Assert.AreEqual(entity["Id"], e.Id);
}
[Test]
public async Task InsertOrReplaceDictionaryNoRow()
{
var p = Guid.NewGuid().ToString();
var entity = new Dictionary<string, object>();
entity.Add(TableStorage.PartitionKey, p);
await storage.InsertOrReplace(entity);
var returned = await storage.QueryByPartition<TableEntity>(p);
Assert.IsNotNull(returned);
Assert.AreEqual(1, returned.Count());
var e = returned.FirstOrDefault();
Assert.AreEqual(entity[TableStorage.PartitionKey], e.PartitionKey);
}
[Test]
public async Task InsertOrReplaceDictionaryNoPartition()
{
var r = Guid.NewGuid().ToString();
var entity = new Dictionary<string, object>();
entity.Add(TableStorage.RowKey, r);
await storage.InsertOrReplace(entity);
var returned = await storage.QueryByRow<TableEntity>(r);
Assert.IsNotNull(returned);
Assert.AreEqual(1, returned.Count());
var e = returned.FirstOrDefault();
Assert.AreEqual(entity[TableStorage.RowKey], e.RowKey);
}
[Test]
public async Task QueryByPartition()
{
var random = new Random();
var count = random.Next(1, 25);
var entities = new List<Helper>();
var partition = Guid.NewGuid().ToString();
for (var i = 0; i < count; i++)
{
var h = new Helper()
{
PartitionKey = partition,
RowKey = Guid.NewGuid().ToString(),
Id = Guid.NewGuid(),
};
entities.Add(h);
}
await storage.Insert(entities);
var returned = await storage.QueryByPartition<Helper>(partition);
Assert.IsNotNull(returned);
Assert.AreEqual(count, returned.Count());
foreach (var r in returned)
{
var exists = (from e in entities
where e.RowKey == r.RowKey
&& e.Id == r.Id
select true).FirstOrDefault();
Assert.IsTrue(exists);
}
}
[Test]
public async Task QueryByRow()
{
var random = new Random();
var count = random.Next(1, 25);
var entities = new List<Helper>();
var rowKey = Guid.NewGuid().ToString();
for (var i = 0; i < count; i++)
{
var h = new Helper()
{
PartitionKey = Guid.NewGuid().ToString(),
RowKey = rowKey,
Id = Guid.NewGuid(),
};
entities.Add(h);
await storage.InsertOrReplace(h);
}
var returned = await storage.QueryByRow<Helper>(rowKey);
Assert.IsNotNull(returned);
Assert.AreEqual(count, returned.Count());
foreach (var r in returned)
{
var exists = (from e in entities
where e.RowKey == r.RowKey
&& e.Id == r.Id
select true).FirstOrDefault();
Assert.IsTrue(exists);
}
}
[Test]
public async Task QueryByPartitionAndRow()
{
var random = new Random();
var count = random.Next(1, 25);
var entities = new List<Helper>();
var partition = Guid.NewGuid().ToString();
for (var i = 0; i < count; i++)
{
var h = new Helper()
{
PartitionKey = partition,
RowKey = Guid.NewGuid().ToString(),
Id = Guid.NewGuid(),
};
entities.Add(h);
}
var z = new Helper()
{
PartitionKey = partition,
RowKey = Guid.NewGuid().ToString(),
Id = Guid.NewGuid(),
};
entities.Add(z);
await storage.Insert(entities);
var returned = await storage.QueryByPartitionAndRow<Helper>(z.PartitionKey, z.RowKey);
Assert.IsNotNull(returned);
Assert.AreEqual(z.Id, returned.Id);
}
[Test]
public async Task DeleteByPartition()
{
var random = new Random();
var count = random.Next(1, 25);
var entities = new List<Helper>();
var partition = Guid.NewGuid().ToString();
for (var i = 0; i < count; i++)
{
var h = new Helper()
{
PartitionKey = partition,
RowKey = Guid.NewGuid().ToString(),
Id = Guid.NewGuid(),
};
entities.Add(h);
}
await storage.Insert(entities);
await storage.DeleteByPartition(partition);
var returned = await storage.QueryByPartition<Helper>(partition);
Assert.IsNotNull(returned);
Assert.IsFalse(returned.Any());
}
[Test]
public async Task DeleteByPartitionPartitionNull()
{
await storage.DeleteByPartition(null);
}
[Test]
public async Task DeleteByPartitionAndRow()
{
var h = new Helper()
{
PartitionKey = Guid.NewGuid().ToString(),
RowKey = Guid.NewGuid().ToString(),
Id = Guid.NewGuid(),
};
await storage.InsertOrReplace(h);
await storage.DeleteByPartitionAndRow(h.PartitionKey, h.RowKey);
var returned = await storage.QueryByPartitionAndRow<Helper>(h.PartitionKey, h.RowKey);
Assert.IsNull(returned);
}
[Test]
public async Task DeleteEnity()
{
var h = new Helper()
{
PartitionKey = Guid.NewGuid().ToString(),
RowKey = Guid.NewGuid().ToString(),
Id = Guid.NewGuid(),
};
await storage.InsertOrReplace(h);
var result = await storage.Delete(h);
Assert.IsNotNull(result);
var returned = await storage.QueryByPartitionAndRow<Helper>(h.PartitionKey, h.RowKey);
Assert.IsNull(returned);
}
[Test]
public async Task DeleteEnities()
{
var random = new Random();
var count = random.Next(1, 25);
var entities = new List<ITableEntity>();
var partition = Guid.NewGuid().ToString();
for (var i = 0; i < count; i++)
{
entities.Add(new Helper()
{
PartitionKey = partition,
RowKey = Guid.NewGuid().ToString(),
Id = Guid.NewGuid(),
}
);
}
await storage.Insert(entities);
var result = await storage.Delete(entities);
Assert.AreEqual(count, result.Count());
foreach (var e in entities)
{
var returned = await storage.QueryByPartitionAndRow<Helper>(e.PartitionKey, e.RowKey);
Assert.IsNull(returned);
}
}
[Test]
public async Task DeleteMultipleBatches()
{
var random = new Random();
var count = random.Next(1, 25);
var partition = Guid.NewGuid().ToString();
var entities = new List<TableEntity>(count);
for (var i = 0; i < count; i++)
{
var entity = new TableEntity()
{
PartitionKey = partition,
RowKey = Guid.NewGuid().ToString(),
};
entities.Add(entity);
if (i % 2 == 0)
{
partition = Guid.NewGuid().ToString();
}
}
await storage.Insert(entities);
var result = await storage.Delete(entities);
Assert.AreEqual(count, result.Count());
var returned = await storage.Query(new TableQuery());
Assert.IsNotNull(returned);
Assert.AreEqual(0, returned.Count());
}
[Test]
public async Task DeleteEntitiesNone()
{
var result = await storage.Delete(new List<TableEntity>());
Assert.IsNull(result);
}
[Test]
public async Task QueryByPartitionPartitionNull()
{
var returned = await storage.QueryByPartition<Helper>(null);
Assert.IsNotNull(returned);
Assert.IsFalse(returned.Any());
}
[Test]
public async Task QueryByRowPartitionNull()
{
var returned = await storage.QueryByRow<Helper>(null);
Assert.IsNotNull(returned);
Assert.IsFalse(returned.Any());
}
[Test]
public async Task QueryByPartitionAndRowPartitionNullRowNull()
{
var returned = await storage.QueryByPartitionAndRow<Helper>(null, null);
Assert.IsNull(returned);
}
[Test]
public async Task DeleteByRow()
{
var random = new Random();
var count = random.Next(1, 25);
var rowKey = Guid.NewGuid().ToString();
for (var i = 0; i < count; i++)
{
var h = new Helper()
{
PartitionKey = Guid.NewGuid().ToString(),
RowKey = rowKey,
Id = Guid.NewGuid(),
};
await storage.InsertOrReplace(h);
}
await storage.DeleteByRow(rowKey);
var returned = await storage.QueryByRow<Helper>(rowKey);
Assert.IsNotNull(returned);
Assert.IsFalse(returned.Any());
}
[Test]
public async Task DeleteByRowRowNull()
{
await storage.DeleteByRow(null);
}
[Test]
public async Task QueryByPartitionGreaterThan1000()
{
var random = new Random();
var count = random.Next(1001, 1250);
var entities = new List<Helper>();
var partition = Guid.NewGuid().ToString();
for (var i = 0; i < count; i++)
{
var h = new Helper()
{
PartitionKey = partition,
RowKey = Guid.NewGuid().ToString(),
Id = Guid.NewGuid(),
};
entities.Add(h);
}
await storage.Insert(entities);
var returned = await storage.QueryByPartition<Helper>(partition);
Assert.IsNotNull(returned);
Assert.AreEqual(count, returned.Count());
foreach (var r in returned)
{
var exists = (from e in entities
where e.RowKey == r.RowKey
&& e.Id == r.Id
select true).FirstOrDefault();
Assert.IsTrue(exists);
}
}
[Test]
public async Task QueryGreaterThan1000()
{
var random = new Random();
var count = random.Next(1001, 1250);
var entities = new List<Helper>();
var partition = Guid.NewGuid().ToString();
for (var i = 0; i < count; i++)
{
var h = new Helper()
{
PartitionKey = partition,
RowKey = Guid.NewGuid().ToString(),
Id = Guid.NewGuid(),
};
entities.Add(h);
}
await storage.Insert(entities);
var query = new TableQuery();
query.Where(TableQuery.GenerateFilterCondition(TableStorage.PartitionKey, QueryComparisons.Equal, partition));
var returned = await storage.Query(query);
Assert.IsNotNull(returned);
Assert.AreEqual(count, returned.Count());
foreach (var r in returned)
{
var exists = (from e in entities
where e.RowKey == (string)r[TableStorage.RowKey]
select true).FirstOrDefault();
Assert.IsTrue(exists);
}
}
[Test]
public async Task Query()
{
var random = new Random();
var count = random.Next(1, 25);
var entities = new List<IDictionary<string, object>>();
var partition = Guid.NewGuid().ToString();
for (var i = 0; i < count; i++)
{
var dic = new Dictionary<string, object>();
dic.Add(TableStorage.PartitionKey, partition);
dic.Add(TableStorage.RowKey, Guid.NewGuid().ToString());
dic.Add("Id", Guid.NewGuid());
entities.Add(dic);
}
await storage.Insert(entities);
var query = new TableQuery();
query.Where(TableQuery.GenerateFilterCondition(TableStorage.PartitionKey, QueryComparisons.Equal, partition));
var returned = await storage.Query(query);
Assert.IsNotNull(returned);
Assert.AreEqual(count, returned.Count());
foreach (var r in returned)
{
var exists = (from e in entities
where (string)e[TableStorage.PartitionKey] == (string)r[TableStorage.PartitionKey]
&& (string)e[TableStorage.RowKey] == (string)r[TableStorage.RowKey]
&& (Guid)e["Id"] == (Guid)r["Id"]
&& !string.IsNullOrWhiteSpace((string)r[TableStorage.ETag])
&& DateTime.UtcNow.Date == ((DateTime)r[TableStorage.Timestamp]).Date
select true).FirstOrDefault();
Assert.IsTrue(exists);
}
}
[Test]
public async Task QueryFunction()
{
var random = new Random();
var count = random.Next(2, 25);
var entities = new List<IDictionary<string, object>>();
var partition = Guid.NewGuid().ToString();
for (var i = 0; i < count; i++)
{
var dic = new Dictionary<string, object>();
dic.Add(TableStorage.PartitionKey, partition);
dic.Add(TableStorage.RowKey, Guid.NewGuid().ToString());
dic.Add("Id", Guid.NewGuid());
entities.Add(dic);
}
for (var i = 0; i < 5; i++)//Invalid Range
{
var dic = new Dictionary<string, object>();
dic.Add(TableStorage.PartitionKey, Guid.NewGuid().ToString());
dic.Add(TableStorage.RowKey, Guid.NewGuid().ToString());
dic.Add("Id", Guid.NewGuid());
entities.Add(dic);
}
storage.Insert(entities).Wait();
var returned = await storage.Query<Helper>(i => i.PartitionKey == partition);
Assert.IsNotNull(returned);
Assert.AreEqual(count, returned.Count());
foreach (var r in returned)
{
var exists = (from e in entities
where r.RowKey == (string)e[TableStorage.RowKey]
&& r.PartitionKey == (string)e[TableStorage.PartitionKey]
select true).FirstOrDefault();
Assert.IsTrue(exists);
}
}
[Test]
public async Task QueryFunctionNone()
{
var entities = new List<IDictionary<string, object>>();
for (var i = 0; i < 5; i++)//Invalid Range
{
var dic = new Dictionary<string, object>();
dic.Add(TableStorage.PartitionKey, Guid.NewGuid().ToString());
dic.Add(TableStorage.RowKey, Guid.NewGuid().ToString());
dic.Add("Id", Guid.NewGuid());
entities.Add(dic);
}
storage.Insert(entities).Wait();
var returned = await storage.Query<Helper>(i => i.PartitionKey == Guid.NewGuid().ToString());
Assert.IsNotNull(returned);
Assert.AreEqual(0, returned.Count());
}
[Test]
public async Task QueryByPartitionDictionary()
{
var random = new Random();
var count = random.Next(1, 25);
var entities = new List<IDictionary<string, object>>();
var partition = Guid.NewGuid().ToString();
for (var i = 0; i < count; i++)
{
var dic = new Dictionary<string, object>();
dic.Add(TableStorage.PartitionKey, partition);
dic.Add(TableStorage.RowKey, Guid.NewGuid().ToString());
dic.Add("Id", Guid.NewGuid());
entities.Add(dic);
}
await storage.Insert(entities);
var returned = await storage.QueryByPartition(partition);
Assert.IsNotNull(returned);
Assert.AreEqual(count, returned.Count());
foreach (var r in returned)
{
var exists = (from e in entities
where (string)e[TableStorage.RowKey] == (string)r[TableStorage.RowKey]
&& (Guid)e["Id"] == (Guid)r["Id"]
select true).FirstOrDefault();
Assert.IsTrue(exists);
}
}
[Test]
public async Task QueryByRowDictionary()
{
var random = new Random();
var count = random.Next(1, 25);
var entities = new List<IDictionary<string, object>>();
var rowKey = Guid.NewGuid().ToString();
for (var i = 0; i < count; i++)
{
var dic = new Dictionary<string, object>();
dic.Add(TableStorage.PartitionKey, Guid.NewGuid().ToString());
dic.Add(TableStorage.RowKey, rowKey);
dic.Add("Id", Guid.NewGuid());
entities.Add(dic);
await storage.InsertOrReplace(dic);
}
var returned = await storage.QueryByRow(rowKey);
Assert.IsNotNull(returned);
Assert.AreEqual(count, returned.Count());
foreach (var r in returned)
{
var exists = (from e in entities
where (string)e[TableStorage.RowKey] == (string)r[TableStorage.RowKey]
&& (Guid)e["Id"] == (Guid)r["Id"]
select true).FirstOrDefault();
Assert.IsTrue(exists);
}
}
[Test]
public async Task QueryByPartitionAndRowDictionary()
{
var random = new Random();
var count = random.Next(1, 25);
var entities = new List<IDictionary<string, object>>();
var partition = Guid.NewGuid().ToString();
for (var i = 0; i < count; i++)
{
var dic = new Dictionary<string, object>();
dic.Add(TableStorage.PartitionKey, partition);
dic.Add(TableStorage.RowKey, Guid.NewGuid().ToString());
dic.Add("Id", Guid.NewGuid());
entities.Add(dic);
}
var rowKey = Guid.NewGuid().ToString();
var z = new Dictionary<string, object>();
z.Add(TableStorage.PartitionKey, partition);
z.Add(TableStorage.RowKey, rowKey);
z.Add("Id", Guid.NewGuid());
entities.Add(z);
await storage.Insert(entities);
var returned = await storage.QueryByPartitionAndRow(partition, rowKey);
Assert.IsNotNull(returned);
Assert.AreEqual(z["Id"], returned["Id"]);
}
}
}

Просмотреть файл

@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>King.Azure.Test Console Application</Description>
<VersionPrefix>2.1.0</VersionPrefix>
<TargetFramework>net462</TargetFramework>
<AssemblyName>King.Azure.Test</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>King.Azure.Test</PackageId>
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\King.Azure\King.Azure.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Runtime" Version="4.1.0" />
<PackageReference Include="System.Threading" Version="4.0.11" />
<PackageReference Include="System.Threading.Tasks" Version="4.0.11" />
<PackageReference Include="System.IO" Version="4.1.0" />
<PackageReference Include="System.Linq" Version="4.1.0" />
<PackageReference Include="System.Linq.Expressions" Version="4.1.0" />
<PackageReference Include="NSubstitute" Version="2.0.2" />
<PackageReference Include="NUnitLite" Version="3.6.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net462' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,19 @@
namespace King.Azure.Test
{
using NUnit.Common;
using NUnitLite;
using System;
using System.Reflection;
public class Program
{
public static void Main(string[] args)
{
var writter = new ExtendedTextWrapper(Console.Out);
new AutoRun(typeof(Program).GetTypeInfo().Assembly).Execute(args, writter, Console.In);
Console.WriteLine("Testing Completed.");
Console.Read();
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("King.Azure.Test")]
[assembly: AssemblyDescription("King.Azure Tests")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("King.Azure.Unit.Test")]
[assembly: AssemblyCopyright("Copyright © Jef King 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("2.0.0.1")]
[assembly: AssemblyFileVersion("2.0.0.1")]
[assembly: Guid("91edff1c-a9c5-4f92-b3e9-781651577d75")]

Просмотреть файл

@ -0,0 +1,29 @@
namespace King.Azure.Unit.Test.Data
{
using King.Azure.Data;
using NUnit.Framework;
[TestFixture]
public class AzureStorageResourcesTests
{
private readonly string ConnectionString = "UseDevelopmentStorage=true;";
[Test]
public void Constructor()
{
new AzureStorageResources(ConnectionString);
}
[Test]
public void IsIAzureStorageResources()
{
Assert.IsNotNull(new AzureStorageResources(ConnectionString) as IAzureStorageResources);
}
[Test]
public void IsAzureStorage()
{
Assert.IsNotNull(new AzureStorageResources(ConnectionString) as AzureStorage);
}
}
}

Просмотреть файл

@ -0,0 +1,37 @@
namespace King.Azure.Unit.Test.Data
{
using System;
using King.Azure.Data;
using Microsoft.WindowsAzure.Storage;
using NUnit.Framework;
[TestFixture]
public class AzureStorageTests
{
const string ConnectionString = "UseDevelopmentStorage=true";
[Test]
public void Constructor()
{
new AzureStorage(ConnectionString);
}
[Test]
public void IsIStorageAccount()
{
Assert.IsNotNull(new AzureStorage(ConnectionString) as IStorageAccount);
}
[Test]
public void ConstructorConnectionStringNull()
{
Assert.That(() => new AzureStorage((string)null), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void ConstructorAccountNull()
{
Assert.That(() => new AzureStorage((CloudStorageAccount)null), Throws.TypeOf<ArgumentNullException>());
}
}
}

Просмотреть файл

@ -0,0 +1,265 @@
namespace King.Azure.Unit.Test.Data
{
using King.Azure.Data;
using Microsoft.WindowsAzure.Storage;
using NUnit.Framework;
using System;
[TestFixture]
public class ContainerTests
{
private const string ConnectionString = "UseDevelopmentStorage=true;";
[Test]
public void Constructor()
{
new Container("test", ConnectionString);
}
[Test]
public void IsIContainer()
{
Assert.IsNotNull(new Container("test", ConnectionString) as IContainer);
}
[Test]
public void IsAzureStorage()
{
Assert.IsNotNull(new Container("test", ConnectionString) as AzureStorage);
}
[Test]
public void ConstructorNameNull()
{
Assert.That(() => new Container(null, ConnectionString), Throws.TypeOf<ArgumentException>());
}
[Test]
public void ConstructorAccountNameNull()
{
Assert.That(() => new Container(null, CloudStorageAccount.Parse(ConnectionString)), Throws.TypeOf<ArgumentException>());
}
[Test]
public void ConstructorKeyNull()
{
Assert.That(() => new Container("test", (string)null), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void DefaultCacheDuration()
{
Assert.AreEqual(31536000, Container.DefaultCacheDuration);
}
[Test]
public void Name()
{
var name = Guid.NewGuid().ToString();
var t = new Container(name, ConnectionString);
Assert.AreEqual(name, t.Name);
}
[Test]
public void IsPublic()
{
var name = Guid.NewGuid().ToString();
var t = new Container(name, ConnectionString, true);
Assert.IsTrue(t.IsPublic);
}
[Test]
public void Client()
{
var name = Guid.NewGuid().ToString();
var t = new Container(name, ConnectionString);
Assert.IsNotNull(t.Client);
}
[Test]
public void Reference()
{
var name = Guid.NewGuid().ToString();
var t = new Container(name, ConnectionString);
Assert.IsNotNull(t.Reference);
}
[Test]
public void DeleteBlobNameNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Delete(null), Throws.TypeOf<ArgumentException>());
}
[Test]
public void ExistsBlobNameNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Exists(null), Throws.TypeOf<ArgumentException>());
}
[Test]
public void GetBlobNameNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Get<object>(null), Throws.TypeOf<ArgumentException>());
}
[Test]
public void StreamBlobNameNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Stream(null), Throws.TypeOf<ArgumentException>());
}
[Test]
public void SaveBlobNameNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Save(null, new object()), Throws.TypeOf<ArgumentException>());
}
[Test]
public void SaveObjectNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Save(Guid.NewGuid().ToString(), (object)null), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void GetBytesBlobNameNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Get(null), Throws.TypeOf<ArgumentException>());
}
[Test]
public void GetTextBlobNameNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.GetText(null), Throws.TypeOf<ArgumentException>());
}
[Test]
public void SnapShotBlobNameNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Snapshot(null), Throws.TypeOf<ArgumentException>());
}
[Test]
public void SaveBytesBlobNameNull()
{
var random = new Random();
var bytes = new byte[1024];
random.NextBytes(bytes);
var c = new Container("test", ConnectionString);
Assert.That(() => c.Save(null, bytes), Throws.TypeOf<ArgumentException>());
}
[Test]
public void SaveTextBlobNameNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Save(null, Guid.NewGuid().ToString()), Throws.TypeOf<ArgumentException>());
}
[Test]
public void SaveBytesNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Save(Guid.NewGuid().ToString(), (byte[])null), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void SaveTextNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Save(Guid.NewGuid().ToString(), (string)null), Throws.TypeOf<ArgumentException>());
}
[Test]
public void GetBlockReferenceBlobNameNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.GetBlockReference(null), Throws.TypeOf<ArgumentException>());
}
[Test]
public void GetPageReferenceBlobNameNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.GetPageReference(null), Throws.TypeOf<ArgumentException>());
}
[Test]
public void PropertiesBlobNameNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Properties(null), Throws.TypeOf<ArgumentException>());
}
[Test]
public void SetCacheControlBlobNameNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.SetCacheControl(null), Throws.TypeOf<ArgumentException>());
}
[Test]
public void CopyFromToFromNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Copy(null, Guid.NewGuid().ToString()), Throws.TypeOf<ArgumentException>());
}
[Test]
public void CopyFromToToNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Copy(Guid.NewGuid().ToString(), null), Throws.TypeOf<ArgumentException>());
}
[Test]
public void CopyFromNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Copy(null, c, Guid.NewGuid().ToString()), Throws.TypeOf<ArgumentException>());
}
[Test]
public void CopyToNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Copy(Guid.NewGuid().ToString(), c, null), Throws.TypeOf<ArgumentException>());
}
[Test]
public void CopyTargetNull()
{
var c = new Container("test", ConnectionString);
Assert.That(() => c.Copy(Guid.NewGuid().ToString(), (IContainer)null, Guid.NewGuid().ToString()), Throws.TypeOf<ArgumentNullException>());
}
}
}

Просмотреть файл

@ -0,0 +1,73 @@
namespace King.Azure.Unit.Test.Data
{
using System;
using King.Azure.Data;
using Microsoft.WindowsAzure.Storage;
using NUnit.Framework;
[TestFixture]
public class FileShareTests
{
private const string ConnectionString = "DefaultEndpointsProtocol=https;AccountName=kingazure;AccountKey=LQFXI8kFSh0TR0dk2bvukQZRxymByGn1amCiR8chpIZ+NkLHqx6IFMcApHGWQutKpWfPloJfNv3ySM+uOJ3f9g==;";
[Test]
public void Constructor()
{
new FileShare("test", ConnectionString);
}
[Test]
public void ConstructorAccount()
{
new FileShare("test", CloudStorageAccount.Parse(ConnectionString));
}
[Test]
public void IsAzureStorage()
{
Assert.IsNotNull(new FileShare("test", ConnectionString) as AzureStorage);
}
[Test]
public void IsIFileShare()
{
Assert.IsNotNull(new FileShare("test", ConnectionString) as IFileShare);
}
[Test]
public void ConstructorNameNull()
{
Assert.That(() => new FileShare(null, ConnectionString), Throws.TypeOf<ArgumentException>());
}
[Test]
public void ConstructorAccountNameNull()
{
Assert.That(() => new FileShare(null, CloudStorageAccount.Parse(ConnectionString)), Throws.TypeOf<ArgumentException>());
}
[Test]
public void Client()
{
var name = Guid.NewGuid().ToString();
var t = new FileShare(name, ConnectionString);
Assert.IsNotNull(t.Client);
}
[Test]
public void Reference()
{
var name = Guid.NewGuid().ToString();
var t = new FileShare(name, ConnectionString);
Assert.IsNotNull(t.Reference);
}
[Test]
public void Name()
{
var name = Guid.NewGuid().ToString();
var t = new FileShare(name, ConnectionString);
Assert.AreEqual(name, t.Name);
}
}
}

Просмотреть файл

@ -0,0 +1,132 @@
namespace King.Azure.Unit.Test.Data
{
using King.Azure.Data;
using Microsoft.WindowsAzure.Storage.Queue;
using NSubstitute;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
[TestFixture]
public class StorageQueuePollerTests
{
const string ConnectionString = "UseDevelopmentStorage=true";
[Test]
public void Constructor()
{
new StorageQueuePoller<object>("queue", ConnectionString);
}
[Test]
public void ConstructorStorageQueueNull()
{
Assert.That(() => new StorageQueuePoller<object>(null), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void IsIStorageQueuePoller()
{
Assert.IsNotNull(new StorageQueuePoller<object>("queue", ConnectionString) as IStorageQueuePoller<object>);
}
[Test]
public void Queue()
{
var queue = Substitute.For<IStorageQueue>();
var poller = new StorageQueuePoller<object>(queue);
var returned = poller.Queue;
Assert.AreEqual(queue, returned);
}
[Test]
public async Task Poll()
{
var msg = new CloudQueueMessage("data");
var queue = Substitute.For<IStorageQueue>();
queue.Get().Returns(Task.FromResult(msg));
var poller = new StorageQueuePoller<object>(queue);
var returned = await poller.Poll();
Assert.IsNotNull(returned);
await queue.Received().Get();
}
[Test]
public async Task PollGetNull()
{
var queue = Substitute.For<IStorageQueue>();
queue.Get().Returns(Task.FromResult<CloudQueueMessage>(null));
var poller = new StorageQueuePoller<object>(queue);
var returned = await poller.Poll();
Assert.IsNull(returned);
await queue.Received().Get();
}
[Test]
public void PollGetThrows()
{
var msg = new CloudQueueMessage("data");
var queue = Substitute.For<IStorageQueue>();
queue.Get().ReturnsForAnyArgs<object>(x => { throw new ApplicationException(); });
var poller = new StorageQueuePoller<object>(queue);
Assert.That(() => poller.Poll(), Throws.TypeOf<ApplicationException>());
}
[Test]
public async Task PollMany()
{
var msg = new CloudQueueMessage("data");
var msgs = new List<CloudQueueMessage>(3);
msgs.Add(msg);
msgs.Add(msg);
msgs.Add(msg);
var queue = Substitute.For<IStorageQueue>();
queue.GetMany(3).Returns(Task.FromResult<IEnumerable<CloudQueueMessage>>(msgs));
var poller = new StorageQueuePoller<object>(queue);
var returned = await poller.PollMany(3);
Assert.IsNotNull(returned);
Assert.AreEqual(3, returned.Count());
await queue.Received().GetMany(3);
}
[Test]
public async Task PollGetManyNull()
{
var queue = Substitute.For<IStorageQueue>();
queue.GetMany(3).Returns(Task.FromResult<IEnumerable<CloudQueueMessage>>(null));
var poller = new StorageQueuePoller<object>(queue);
var returned = await poller.PollMany(3);
Assert.IsNull(returned);
await queue.Received().GetMany(3);
}
[Test]
public void PollGetManyThrows()
{
var msg = new CloudQueueMessage("data");
var queue = Substitute.For<IStorageQueue>();
queue.GetMany().ReturnsForAnyArgs<object>(x => { throw new ApplicationException(); });
var poller = new StorageQueuePoller<object>(queue);
Assert.That(() => poller.PollMany(), Throws.TypeOf<ApplicationException>());
}
}
}

Просмотреть файл

@ -0,0 +1,197 @@
namespace King.Azure.Unit.Test.Data
{
using King.Azure.Data;
using NSubstitute;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
[TestFixture]
public class StorageQueueShardsTests
{
private const string ConnectionString = "UseDevelopmentStorage=true;";
[Test]
public void Constructor()
{
var sqs = new StorageQueueShards("test", ConnectionString, 2);
Assert.AreEqual(2, sqs.Queues.Count());
}
[Test]
public void ConstructorConnectionNull()
{
Assert.That(() => new StorageQueueShards("test", null), Throws.TypeOf<ArgumentException>());
}
[Test]
public void ConstructorNameNull()
{
Assert.That(() => new StorageQueueShards(null, ConnectionString), Throws.TypeOf<ArgumentException>());
}
[Test]
public void ConstructorQueuesNull()
{
Assert.That(() => new StorageQueueShards(null), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void ConstructorQueuesEmpty()
{
Assert.That(() => new StorageQueueShards(new IStorageQueue[0]), Throws.TypeOf<ArgumentException>());
}
[Test]
public void ConstructorShardDefault()
{
var sqs = new StorageQueueShards("test", ConnectionString);
Assert.AreEqual(2, sqs.Queues.Count());
}
[Test]
public void IsIQueueShardSender()
{
Assert.IsNotNull(new StorageQueueShards("test", ConnectionString) as IQueueShardSender<IStorageQueue>);
}
[Test]
public void IsIAzureStorage()
{
Assert.IsNotNull(new StorageQueueShards("test", ConnectionString) as IAzureStorage);
}
[Test]
public void Name()
{
var name = Guid.NewGuid().ToString();
var sqs = new StorageQueueShards(name, ConnectionString, 2);
Assert.AreEqual(name, sqs.Name);
}
[Test]
public void Queues()
{
var random = new Random();
var i = (byte)random.Next(1, byte.MaxValue);
var sqs = new StorageQueueShards("test", ConnectionString, i);
Assert.IsNotNull(sqs.Queues);
Assert.AreEqual(i, sqs.Queues.Count());
}
[Test]
public async Task CreateIfNotExists()
{
var random = new Random();
var i = random.Next(1, byte.MaxValue);
var qs = new List<IStorageQueue>();
for (var j = 0; j < i; j++)
{
var q = Substitute.For<IStorageQueue>();
q.CreateIfNotExists().Returns(Task.FromResult(true));
qs.Add(q);
}
var sqs = new StorageQueueShards(qs.ToArray());
var success = await sqs.CreateIfNotExists();
Assert.IsTrue(success);
foreach (var q in qs)
{
await q.Received().CreateIfNotExists();
}
}
[Test]
public async Task Delete()
{
var random = new Random();
var i = random.Next(1, byte.MaxValue);
var qs = new List<IStorageQueue>();
for (var j = 0; j < i; j++)
{
var q = Substitute.For<IStorageQueue>();
q.Delete().Returns(Task.FromResult(true));
qs.Add(q);
}
var sqs = new StorageQueueShards(qs.ToArray());
await sqs.Delete();
foreach (var q in qs)
{
await q.Received().Delete();
}
}
[Test]
public async Task Save()
{
var random = new Random();
var i = (byte)random.Next(1, byte.MaxValue);
var index = random.Next(0, i);
var msg = new object();
var qs = new List<IStorageQueue>();
for (var j = 0; j < i; j++)
{
var q = Substitute.For<IStorageQueue>();
q.Send(msg).Returns(Task.CompletedTask);
qs.Add(q);
}
var sqs = new StorageQueueShards(qs);
await sqs.Save(msg, (byte)index);
for (var j = 0; j < i; j++)
{
if (j == index)
{
await qs[j].Received().Send(msg);
}
else
{
await qs[j].DidNotReceive().Send(msg);
}
}
}
[Test]
public void Index()
{
var msg = new object();
var q = Substitute.For<IStorageQueue>();
var qs = new List<IStorageQueue>();
qs.Add(q);
qs.Add(q);
qs.Add(q);
var sqs = new StorageQueueShards(qs);
var index = sqs.Index(0);
Assert.IsTrue(0 <= index && 3 > index);
}
[Test]
public void IndexBad([Values(0,255)] int val, [Values(0,0)] int expected)
{
var msg = new object();
var q = Substitute.For<IStorageQueue>();
var qs = new List<IStorageQueue>();
qs.Add(q);
var sqs = new StorageQueueShards(qs);
var index = sqs.Index((byte)val);
Assert.AreEqual(expected, index);
}
}
}

Просмотреть файл

@ -0,0 +1,95 @@
namespace King.Azure.Unit.Test.Data
{
using System;
using King.Azure.Data;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Queue;
using NUnit.Framework;
[TestFixture]
public class StorageQueueTests
{
private const string ConnectionString = "UseDevelopmentStorage=true;";
[Test]
public void Constructor()
{
new StorageQueue("test", ConnectionString, TimeSpan.FromSeconds(22));
}
[Test]
public void IQueue()
{
Assert.IsNotNull(new StorageQueue("test", ConnectionString) as IStorageQueue);
}
[Test]
public void ConstructorTableNull()
{
Assert.That(() => new StorageQueue(null, ConnectionString), Throws.TypeOf<ArgumentException>());
}
[Test]
public void ConstructorAccountTableNull()
{
Assert.That(() => new StorageQueue(null, CloudStorageAccount.Parse(ConnectionString)), Throws.TypeOf<ArgumentException>());
}
[Test]
public void ConstructorKeyNull()
{
Assert.That(() => new StorageQueue("test", (string)null), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void Name()
{
var name = Guid.NewGuid().ToString();
var t = new StorageQueue(name, ConnectionString);
Assert.AreEqual(name, t.Name);
}
[Test]
public void Client()
{
var name = Guid.NewGuid().ToString();
var t = new StorageQueue(name, ConnectionString);
Assert.IsNotNull(t.Client);
}
[Test]
public void Reference()
{
var name = Guid.NewGuid().ToString();
var t = new StorageQueue(name, ConnectionString);
Assert.IsNotNull(t.Reference);
}
[Test]
public void DeleteNull()
{
var name = Guid.NewGuid().ToString();
var t = new StorageQueue(name, ConnectionString);
Assert.That(() => t.Delete(null), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void SaveMessageNull()
{
var name = Guid.NewGuid().ToString();
var t = new StorageQueue(name, ConnectionString);
Assert.That(() => t.Send((CloudQueueMessage)null), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void SaveNull()
{
var name = Guid.NewGuid().ToString();
var t = new StorageQueue(name, ConnectionString);
Assert.That(() => t.Send((object)null), Throws.TypeOf<ArgumentNullException>());
}
}
}

Просмотреть файл

@ -0,0 +1,87 @@
namespace King.Azure.Unit.Test.Data
{
using System;
using System.Threading.Tasks;
using King.Azure.Data;
using Microsoft.WindowsAzure.Storage.Queue;
using Newtonsoft.Json;
using NSubstitute;
using NUnit.Framework;
[TestFixture]
public class StorageQueuedMessageTests
{
public class Helper
{
public Guid Test
{
get;
set;
}
}
[Test]
public void Constructor()
{
var queue = Substitute.For<IStorageQueue>();
new StorageQueuedMessage<object>(queue, new CloudQueueMessage("ship"));
}
[Test]
public void ConstructorQueueNull()
{
var message = new CloudQueueMessage("ship");
Assert.That(() => new StorageQueuedMessage<object>(null, message), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void ConstructorMessageNull()
{
var queue = Substitute.For<IStorageQueue>();
Assert.That(() => new StorageQueuedMessage<object>(queue, null), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public async Task Complete()
{
var queue = Substitute.For<IStorageQueue>();
var message = new CloudQueueMessage("ship");
await queue.Delete(message);
var sqm = new StorageQueuedMessage<object>(queue, message);
await sqm.Complete();
await queue.Received().Delete(message);
}
[Test]
public async Task Abandon()
{
var queue = Substitute.For<IStorageQueue>();
var message = new CloudQueueMessage("ship");
var sqm = new StorageQueuedMessage<object>(queue, message);
await sqm.Abandon();
}
[Test]
public async Task Data()
{
var expected = new Helper()
{
Test = Guid.NewGuid(),
};
var json = JsonConvert.SerializeObject(expected);
var queue = Substitute.For<IStorageQueue>();
var message = new CloudQueueMessage(json);
var sqm = new StorageQueuedMessage<Helper>(queue, message);
var data = await sqm.Data();
Assert.IsNotNull(data);
Assert.AreEqual(expected.Test, data.Test);
}
}
}

Просмотреть файл

@ -0,0 +1,358 @@
namespace King.Azure.Unit.Test.Data
{
using System;
using System.Collections.Generic;
using System.Linq;
using King.Azure.Data;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using NUnit.Framework;
[TestFixture]
public class TableStorageTests
{
private const string ConnectionString = "UseDevelopmentStorage=true;";
[Test]
public void Constructor()
{
new TableStorage("TestTable", ConnectionString);
}
[Test]
public void IsITableStorage()
{
Assert.IsNotNull(new TableStorage("TestTable", ConnectionString) as ITableStorage);
}
[Test]
public void PartitionKey()
{
Assert.AreEqual("PartitionKey", TableStorage.PartitionKey);
}
[Test]
public void RowKey()
{
Assert.AreEqual("RowKey", TableStorage.RowKey);
}
[Test]
public void Timestamp()
{
Assert.AreEqual("Timestamp", TableStorage.Timestamp);
}
[Test]
public void ETag()
{
Assert.AreEqual("ETag", TableStorage.ETag);
}
[Test]
public void ConstructorTableNull()
{
Assert.That(() => new TableStorage(null, ConnectionString), Throws.TypeOf<ArgumentException>());
}
[Test]
public void ConstructorAccountTableNull()
{
Assert.That(() => new TableStorage(null, CloudStorageAccount.Parse(ConnectionString)), Throws.TypeOf<ArgumentException>());
}
[Test]
public void ConstructorConnectionStringNull()
{
Assert.That(() => new TableStorage("TestTable", (string)null), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void Name()
{
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
Assert.AreEqual(name, t.Name);
}
[Test]
public void Client()
{
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
Assert.IsNotNull(t.Client);
}
[Test]
public void Reference()
{
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
Assert.IsNotNull(t.Reference);
}
[Test]
public void InsertDictionaryNull()
{
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
Assert.That(() => t.InsertOrReplace((IDictionary<string, object>)null), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void QueryFunctionNull()
{
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
Assert.That(() => t.Query<TableEntity>(null, 1000), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void QueryFunctionResultsNegative()
{
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
Assert.That(() => t.Query<TableEntity>(i => i.PartitionKey == "hi", -100), Throws.TypeOf<InvalidOperationException>());
}
[Test]
public void QueryTableQueryNull()
{
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
Assert.That(() => t.Query<TableEntity>(null), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void QueryDictionaryQueryNull()
{
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
Assert.That(() => t.Query((TableQuery)null), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void DeleteEntityNull()
{
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
Assert.That(() => t.Delete((ITableEntity)null), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void DeleteEntitiesNull()
{
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
Assert.That(() => t.Delete((IEnumerable<ITableEntity>)null), Throws.TypeOf<ArgumentNullException>());
}
[Test]
public void BatchOne()
{
var items = new List<ITableEntity>();
items.Add(new TableEntity());
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
var batches = t.Batch(items);
Assert.AreEqual(1, batches.Count());
Assert.AreEqual(1, batches.First().Count());
}
[Test]
public void BatchNone()
{
var items = new List<ITableEntity>();
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
var batches = t.Batch(items);
Assert.AreEqual(0, batches.Count());
}
[Test]
public void BatchThousandsDifferentPartitions()
{
var random = new Random();
var count = random.Next(2001, 10000);
var items = new List<ITableEntity>();
for (var i = 0; i < count; i++)
{
items.Add(new TableEntity() { PartitionKey = Guid.NewGuid().ToString() });
}
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
var batches = t.Batch(items);
Assert.AreEqual(count, batches.Count());
}
[Test]
public void BatchThousands()
{
var random = new Random();
var count = random.Next(2001, 10000);
var partition = Guid.NewGuid().ToString();
var items = new List<ITableEntity>();
for (var i = 0; i < count; i++)
{
items.Add(new TableEntity() { PartitionKey = partition });
}
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
var batches = t.Batch(items);
Assert.AreEqual(Math.Ceiling(((double)count / TableStorage.MaimumxInsertBatch)), batches.Count());
var resultCount = 0;
foreach (var b in batches)
{
resultCount += b.Count();
}
Assert.AreEqual(count, resultCount);
}
[Test]
public void ChunkThousands()
{
var random = new Random();
var count = random.Next(2001, 15000);
var partition = Guid.NewGuid().ToString();
var items = new List<ITableEntity>();
for (var i = 0; i < count; i++)
{
items.Add(new TableEntity() { PartitionKey = partition });
}
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
var batches = t.Chunk<ITableEntity>(items);
Assert.AreEqual(Math.Ceiling(((double)count / TableStorage.MaimumxInsertBatch)), batches.Count());
var resultCount = 0;
foreach (var b in batches)
{
resultCount += b.Count();
}
Assert.AreEqual(count, resultCount);
}
[Test]
public void ChunkOne()
{
var items = new List<ITableEntity>();
items.Add(new TableEntity());
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
var batches = t.Chunk<ITableEntity>(items);
Assert.AreEqual(1, batches.Count());
Assert.AreEqual(1, batches.First().Count());
}
[Test]
public void ChunkNone()
{
var items = new List<ITableEntity>();
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
var batches = t.Chunk<ITableEntity>(items);
Assert.AreEqual(0, batches.Count());
}
[Test]
public void BatchDictionaryOne()
{
var items = new List<IDictionary<string, object>>();
var dic = new Dictionary<string, object>();
dic.Add(TableStorage.PartitionKey, Guid.NewGuid().ToString());
items.Add(dic);
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
var batches = t.Batch(items);
Assert.AreEqual(1, batches.Count());
Assert.AreEqual(1, batches.First().Count());
}
[Test]
public void BatchDictionaryNone()
{
var items = new List<IDictionary<string, object>>();
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
var batches = t.Batch(items);
Assert.AreEqual(0, batches.Count());
}
[Test]
public void BatchDictionaryThousandsDifferentPartitions()
{
var random = new Random();
var count = random.Next(2001, 10000);
var items = new List<IDictionary<string, object>>();
for (var i = 0; i < count; i++)
{
var dic = new Dictionary<string, object>();
dic.Add(TableStorage.PartitionKey, Guid.NewGuid().ToString());
items.Add(dic);
}
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
var batches = t.Batch(items);
Assert.AreEqual(count, batches.Count());
}
[Test]
public void BatchDictionaryThousands()
{
var random = new Random();
var count = random.Next(2001, 10000);
var partition = Guid.NewGuid().ToString();
var items = new List<IDictionary<string, object>>();
for (var i = 0; i < count; i++)
{
var dic = new Dictionary<string, object>();
dic.Add(TableStorage.PartitionKey, partition);
items.Add(dic);
}
var name = Guid.NewGuid().ToString();
var t = new TableStorage(name, ConnectionString);
var batches = t.Batch(items);
Assert.AreEqual(Math.Ceiling(((double)count / TableStorage.MaimumxInsertBatch)), batches.Count());
var resultCount = 0;
foreach (var b in batches)
{
resultCount += b.Count();
}
Assert.AreEqual(count, resultCount);
}
}
}

Двоичные данные
King.Azure.Test/icon.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 5.3 KiB

43
King.Azure.sln Normal file
Просмотреть файл

@ -0,0 +1,43 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.4
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B65D0744-3BE9-4B13-A7D4-1D30E2587DD9}"
ProjectSection(SolutionItems) = preProject
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "King.Azure", "King.Azure\King.Azure.csproj", "{1DE3D5A9-273D-4758-813D-3CEA7DA096E2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "King.Azure.Test", "King.Azure.Test\King.Azure.Test.csproj", "{91EDFF1C-A9C5-4F92-B3E9-781651577D75}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1DE3D5A9-273D-4758-813D-3CEA7DA096E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1DE3D5A9-273D-4758-813D-3CEA7DA096E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1DE3D5A9-273D-4758-813D-3CEA7DA096E2}.Debug|x64.ActiveCfg = Debug|Any CPU
{1DE3D5A9-273D-4758-813D-3CEA7DA096E2}.Debug|x64.Build.0 = Debug|Any CPU
{1DE3D5A9-273D-4758-813D-3CEA7DA096E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1DE3D5A9-273D-4758-813D-3CEA7DA096E2}.Release|Any CPU.Build.0 = Release|Any CPU
{1DE3D5A9-273D-4758-813D-3CEA7DA096E2}.Release|x64.ActiveCfg = Release|Any CPU
{1DE3D5A9-273D-4758-813D-3CEA7DA096E2}.Release|x64.Build.0 = Release|Any CPU
{91EDFF1C-A9C5-4F92-B3E9-781651577D75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91EDFF1C-A9C5-4F92-B3E9-781651577D75}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91EDFF1C-A9C5-4F92-B3E9-781651577D75}.Debug|x64.ActiveCfg = Debug|Any CPU
{91EDFF1C-A9C5-4F92-B3E9-781651577D75}.Debug|x64.Build.0 = Debug|Any CPU
{91EDFF1C-A9C5-4F92-B3E9-781651577D75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91EDFF1C-A9C5-4F92-B3E9-781651577D75}.Release|Any CPU.Build.0 = Release|Any CPU
{91EDFF1C-A9C5-4F92-B3E9-781651577D75}.Release|x64.ActiveCfg = Release|Any CPU
{91EDFF1C-A9C5-4F92-B3E9-781651577D75}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Просмотреть файл

@ -0,0 +1,56 @@
namespace King.Azure.Data
{
using Microsoft.WindowsAzure.Storage;
using System;
/// <summary>
/// Azure Storage
/// </summary>
public class AzureStorage : IStorageAccount
{
#region Members
/// <summary>
/// Cloud Storage Account
/// </summary>
private readonly CloudStorageAccount account;
#endregion
#region Constructors
/// <summary>
/// Constructor
/// </summary>
/// <param name="connectionString">Connection String</param>
public AzureStorage(string connectionString)
: this(CloudStorageAccount.Parse(connectionString))
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="account">Storage Account</param>
public AzureStorage(CloudStorageAccount account)
{
if (null == account)
{
throw new ArgumentNullException("account");
}
this.account = account;
}
#endregion
#region Properties
/// <summary>
/// Cloud Storage Account
/// </summary>
public CloudStorageAccount Account
{
get
{
return this.account;
}
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,142 @@
namespace King.Azure.Data
{
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure.Storage.Queue;
using Microsoft.WindowsAzure.Storage.Table;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
/// <summary>
/// Azure Storage Resources
/// </summary>
public class AzureStorageResources : AzureStorage, IAzureStorageResources
{
#region Constructors
/// <summary>
/// Constructor
/// </summary>
/// <param name="connectionString">Storage Account</param>
public AzureStorageResources(string connectionString)
: base(connectionString)
{
}
#endregion
#region Methods
/// <summary>
/// List Table Names
/// </summary>
/// <returns>Table Names</returns>
public virtual async Task<IEnumerable<string>> TableNames()
{
TableContinuationToken token = null;
var names = new List<string>();
var client = base.Account.CreateCloudTableClient();
do
{
var segments = await client.ListTablesSegmentedAsync(token);
names.AddRange(segments.Results.Select(s => s.Name));
token = segments.ContinuationToken;
}
while (null != token);
return names;
}
/// <summary>
/// List Tables
/// </summary>
/// <returns>Tables</returns>
public virtual async Task<IEnumerable<ITableStorage>> Tables()
{
var tables = new List<ITableStorage>();
var names = await this.TableNames();
foreach (var name in names)
{
tables.Add(new TableStorage(name, base.Account));
}
return tables;
}
/// <summary>
/// List Container Names
/// </summary>
/// <returns>Container Names</returns>
public virtual async Task<IEnumerable<string>> ContainerNames()
{
BlobContinuationToken token = null;
var names = new List<string>();
var client = base.Account.CreateCloudBlobClient();
do
{
var segments = await client.ListContainersSegmentedAsync(token);
names.AddRange(segments.Results.Select(s => s.Name));
token = segments.ContinuationToken;
}
while (null != token);
return names;
}
/// <summary>
/// List Containers
/// </summary>
/// <returns>Containers</returns>
public virtual async Task<IEnumerable<IContainer>> Containers()
{
var containers = new List<IContainer>();
var names = await this.ContainerNames();
foreach (var name in names)
{
containers.Add(new Container(name, base.Account));
}
return containers;
}
/// <summary>
/// List Queue Names
/// </summary>
/// <returns>Queue Names</returns>
public virtual async Task<IEnumerable<string>> QueueNames()
{
QueueContinuationToken token = null;
var names = new List<string>();
var client = base.Account.CreateCloudQueueClient();
do
{
var segments = await client.ListQueuesSegmentedAsync(token);
names.AddRange(segments.Results.Select(s => s.Name));
token = segments.ContinuationToken;
}
while (null != token);
return names;
}
/// <summary>
/// List Queues
/// </summary>
/// <returns>Queues</returns>
public virtual async Task<IEnumerable<IStorageQueue>> Queues()
{
var queues = new List<IStorageQueue>();
var names = await this.QueueNames();
foreach (var name in names)
{
queues.Add(new StorageQueue(name, base.Account));
}
return queues;
}
#endregion
}
}

561
King.Azure/Container.cs Normal file
Просмотреть файл

@ -0,0 +1,561 @@
namespace King.Azure.Data
{
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure.Storage.RetryPolicies;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
/// <summary>
/// Blob Container
/// </summary>
public class Container : AzureStorage, IContainer
{
#region Members
/// <summary>
/// Default Cache Duration
/// </summary>
public const uint DefaultCacheDuration = 31536000;
/// <summary>
/// Client
/// </summary>
private readonly CloudBlobClient client;
/// <summary>
/// Reference
/// </summary>
private readonly CloudBlobContainer reference;
/// <summary>
/// Is Public
/// </summary>
private readonly bool isPublic = false;
#endregion
#region Constructors
/// <summary>
/// Container Constructor
/// </summary>
/// <param name="name">Name</param>
/// <param name="connectionString">Connection String</param>
/// <param name="isPublic">Is Public</param>
/// <param name="location">Location Mode</param>
public Container(string name, string connectionString, bool isPublic = false, LocationMode location = LocationMode.PrimaryThenSecondary)
: this(name, CloudStorageAccount.Parse(connectionString), isPublic, location)
{
}
/// <summary>
/// Container Constructor
/// </summary>
/// <param name="name">Name</param>
/// <param name="account">Storage Account</param>
/// <param name="isPublic">Is Public</param>
/// <param name="location">Location Mode</param>
public Container(string name, CloudStorageAccount account, bool isPublic = false, LocationMode location = LocationMode.PrimaryThenSecondary)
: base(account)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("name");
}
this.client = this.Account.CreateCloudBlobClient();
this.client.DefaultRequestOptions.LocationMode = location;
this.reference = this.client.GetContainerReference(name);
this.isPublic = isPublic;
}
#endregion
#region Properties
/// <summary>
/// Name
/// </summary>
public virtual string Name
{
get
{
return this.reference.Name;
}
}
/// <summary>
/// Is Public
/// </summary>
public virtual bool IsPublic
{
get
{
return this.isPublic;
}
}
/// <summary>
/// Client
/// </summary>
public virtual CloudBlobClient Client
{
get
{
return this.client;
}
}
/// <summary>
/// Reference
/// </summary>
public virtual CloudBlobContainer Reference
{
get
{
return this.reference;
}
}
#endregion
#region Methods
/// <summary>
/// Create If Not Exists
/// </summary>
/// <returns>Created</returns>
public virtual async Task<bool> CreateIfNotExists()
{
var result = await this.reference.CreateIfNotExistsAsync();
if (result)
{
var permissions = new BlobContainerPermissions()
{
PublicAccess = this.isPublic ? BlobContainerPublicAccessType.Blob : BlobContainerPublicAccessType.Off
};
await this.reference.SetPermissionsAsync(permissions);
}
return result;
}
/// <summary>
/// Delete Container
/// </summary>
/// <returns>Task</returns>
public virtual async Task Delete()
{
await this.reference.DeleteAsync();
}
/// <summary>
/// Delete from Blob Storage
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <param name="deleteHistory">Delete History (Snapshots)</param>
/// <returns>Object</returns>
public virtual async Task Delete(string blobName, bool deleteHistory = true)
{
if (string.IsNullOrWhiteSpace(blobName))
{
throw new ArgumentException("blobName");
}
var delSnapshots = deleteHistory ? DeleteSnapshotsOption.IncludeSnapshots : DeleteSnapshotsOption.None;
var blob = this.GetBlockReference(blobName);
await blob.DeleteAsync(delSnapshots, AccessCondition.GenerateEmptyCondition(), new BlobRequestOptions(), new OperationContext());
}
/// <summary>
/// Blob Exists
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <returns>bool</returns>
public virtual async Task<bool> Exists(string blobName)
{
if (string.IsNullOrWhiteSpace(blobName))
{
throw new ArgumentException("blobName");
}
var blob = this.GetBlockReference(blobName);
return await blob.ExistsAsync();
}
/// <summary>
/// Save Object as Json to Blob Storage
/// </summary>
/// <typeparam name="T">Type</typeparam>
/// <param name="blobName">Blob Name</param>
/// <param name="obj">Object</param>
/// <returns>Task</returns>
public virtual async Task Save(string blobName, object obj)
{
if (string.IsNullOrWhiteSpace(blobName))
{
throw new ArgumentException("blobName");
}
if (null == obj)
{
throw new ArgumentNullException("obj");
}
var json = JsonConvert.SerializeObject(obj);
await this.Save(blobName, json, "application/json");
}
/// <summary>
/// Save Text
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <param name="text">Text</param>
/// <param name="contentType">Content Type</param>
/// <returns>Task</returns>
public virtual async Task Save(string blobName, string text, string contentType = "text/plain")
{
if (string.IsNullOrWhiteSpace(blobName))
{
throw new ArgumentException("blobName");
}
if (string.IsNullOrWhiteSpace(text))
{
throw new ArgumentException("text");
}
var blob = this.GetBlockReference(blobName);
var cacheProperties = await this.Properties(blobName);
await blob.UploadTextAsync(text);
await this.Set(blob, cacheProperties, contentType);
}
/// <summary>
/// Set Properties on Blob
/// </summary>
/// <param name="blob">Blob</param>
/// <param name="cached">Cached Properties</param>
/// <param name="type">Content Type</param>
/// <param name="cacheControl">Cache Control</param>
/// <param name="disposition">Content Disposition</param>
/// <param name="encoding">Content Encoding</param>
/// <param name="language">Content Language</param>
/// <returns></returns>
public virtual async Task Set(CloudBlockBlob blob, BlobProperties cached, string type = null, string cacheControl = null, string disposition = null, string encoding = null, string language = null)
{
await blob.FetchAttributesAsync();
if (null != cached)
{
blob.Properties.CacheControl = cached.CacheControl;
blob.Properties.ContentDisposition = cached.ContentDisposition;
blob.Properties.ContentEncoding = cached.ContentEncoding;
blob.Properties.ContentLanguage = cached.ContentLanguage;
blob.Properties.ContentType = cached.ContentType;
}
blob.Properties.CacheControl = string.IsNullOrWhiteSpace(cacheControl) ? blob.Properties.CacheControl : cacheControl;
blob.Properties.ContentDisposition = string.IsNullOrWhiteSpace(disposition) ? blob.Properties.ContentDisposition : disposition;
blob.Properties.ContentEncoding = string.IsNullOrWhiteSpace(encoding) ? blob.Properties.ContentEncoding : encoding;
blob.Properties.ContentLanguage = string.IsNullOrWhiteSpace(language) ? blob.Properties.ContentLanguage : language;
blob.Properties.ContentType = string.IsNullOrWhiteSpace(type) ? blob.Properties.ContentType : type;
await blob.SetPropertiesAsync();
}
/// <summary>
/// Get Object from Blob Storage
/// </summary>
/// <typeparam name="T">Type</typeparam>
/// <param name="blobName">Blob Name</param>
/// <returns>Object</returns>
public virtual async Task<T> Get<T>(string blobName)
{
if (string.IsNullOrWhiteSpace(blobName))
{
throw new ArgumentException("blobName");
}
var json = await this.GetText(blobName);
return JsonConvert.DeserializeObject<T>(json);
}
/// <summary>
/// Get Bytes
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <returns>bytes</returns>
public virtual async Task<byte[]> Get(string blobName)
{
if (string.IsNullOrWhiteSpace(blobName))
{
throw new ArgumentException("blobName");
}
var blob = this.GetBlockReference(blobName);
await blob.FetchAttributesAsync();
var bytes = new byte[blob.Properties.Length];
await blob.DownloadToByteArrayAsync(bytes, 0);
return bytes;
}
/// <summary>
/// Get Bytes
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <returns>Text</returns>
public virtual async Task<string> GetText(string blobName)
{
if (string.IsNullOrWhiteSpace(blobName))
{
throw new ArgumentException("blobName");
}
var blob = this.GetBlockReference(blobName);
return await blob.DownloadTextAsync();
}
/// <summary>
/// Save Bytes
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <param name="bytes">bytes</param>
/// <returns>Task</returns>
public virtual async Task Save(string blobName, byte[] bytes, string contentType = "application/octet-stream")
{
if (string.IsNullOrWhiteSpace(blobName))
{
throw new ArgumentException("blobName");
}
if (null == bytes)
{
throw new ArgumentNullException("bytes");
}
var blob = this.GetBlockReference(blobName);
var cached = await this.Properties(blobName);
await blob.UploadFromByteArrayAsync(bytes, 0, bytes.Length);
await this.Set(blob, cached, contentType);
}
/// <summary>
/// Blob Properties
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <returns>Blob Container Properties</returns>
public virtual async Task<BlobProperties> Properties(string blobName)
{
if (string.IsNullOrWhiteSpace(blobName))
{
throw new ArgumentException("blobName");
}
var exists = await this.Exists(blobName);
if (exists)
{
var blob = this.GetBlockReference(blobName);
await blob.FetchAttributesAsync();
return blob.Properties;
}
else
{
return null;
}
}
/// <summary>
/// Set Cache Control
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <param name="cacheDuration">Cache Duration (Default 1 year)</param>
/// <returns>Task</returns>
public virtual async Task SetCacheControl(string blobName, uint cacheDuration = DefaultCacheDuration)
{
if (string.IsNullOrWhiteSpace(blobName))
{
throw new ArgumentException("blobName");
}
cacheDuration = cacheDuration < 1 ? DefaultCacheDuration : cacheDuration;
var blob = this.GetBlockReference(blobName);
await this.Set(blob, null, null, string.Format("public, max-age={0}", cacheDuration));
}
/// <summary>
/// Get Reference
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <param name="snapshot">Snapshot time</param>
/// <returns>Cloud Block Blob</returns>
public virtual CloudBlockBlob GetBlockReference(string blobName, DateTimeOffset? snapshot = null)
{
if (string.IsNullOrWhiteSpace(blobName))
{
throw new ArgumentException("blobName");
}
return this.reference.GetBlockBlobReference(blobName, snapshot);
}
/// <summary>
/// Get Reference
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <param name="snapshot">Snapshot time</param>
/// <returns>Cloud Block Blob</returns>
public virtual CloudPageBlob GetPageReference(string blobName, DateTimeOffset? snapshot = null)
{
if (string.IsNullOrWhiteSpace(blobName))
{
throw new ArgumentException("blobName");
}
return this.reference.GetPageBlobReference(blobName, snapshot);
}
/// <summary>
/// Get Stream
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <returns>Stream</returns>
public virtual async Task<Stream> Stream(string blobName)
{
if (string.IsNullOrWhiteSpace(blobName))
{
throw new ArgumentException("blobName");
}
var properties = await this.Properties(blobName);
var blob = this.GetBlockReference(blobName);
var stream = new MemoryStream();
await blob.DownloadRangeToStreamAsync(stream, 0, properties.Length);
stream.Position = 0;
return stream;
}
/// <summary>
/// List Blobs
/// </summary>
/// <param name="prefix">Prefix</param>
/// <param name="useFlatBlobListing">Use Flat Blob Listing</param>
/// <returns>Blobs</returns>
public async Task<IEnumerable<IListBlobItem>> List(string prefix = null, bool useFlatBlobListing = true, BlobListingDetails details = BlobListingDetails.All, int? maxResults = int.MaxValue)
{
BlobContinuationToken token = null;
var blobs = new List<IListBlobItem>();
var options = new BlobRequestOptions();
var operationContext = new OperationContext();
do
{
var segments = await this.reference.ListBlobsSegmentedAsync(prefix, useFlatBlobListing, details, maxResults, token, options, operationContext);
blobs.AddRange(segments.Results);
token = segments.ContinuationToken;
}
while (null != token);
return blobs;
}
/// <summary>
/// Create Snapshot
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <returns>Task</returns>
public virtual async Task<ICloudBlob> Snapshot(string blobName)
{
if (string.IsNullOrWhiteSpace(blobName))
{
throw new ArgumentException("blobName");
}
var options = new BlobRequestOptions
{
LocationMode = LocationMode.PrimaryOnly,
};
var blobs = await this.List(blobName);
var blob = blobs.FirstOrDefault();
var block = blob as CloudBlockBlob;
if (null != block)
{
return await block.CreateSnapshotAsync(null, null, options, null);
}
var page = blob as CloudPageBlob;
if (null != page)
{
return await page.CreateSnapshotAsync(null, null, options, null);
}
return null;
}
/// <summary>
/// Copy From Blob to Blob
/// </summary>
/// <param name="from">From</param>
/// <param name="to">To</param>
/// <returns>Blob Uri</returns>
public virtual async Task<string> Copy(string from, string to)
{
if (string.IsNullOrWhiteSpace(from))
{
throw new ArgumentException("Source blob address");
}
if (string.IsNullOrWhiteSpace(to))
{
throw new ArgumentException("Target blob address");
}
var source = this.GetBlockReference(from);
var target = this.GetBlockReference(to);
return await target.StartCopyAsync(source);
}
/// <summary>
/// Copy from, to seperate container/blob
/// </summary>
/// <param name="from">From</param>
/// <param name="target">Target</param>
/// <param name="to">To</param>
/// <returns>Blob Uri</returns>
public virtual async Task<string> Copy(string from, string target, string to)
{
return await this.Copy(from, new Container(target, this.Account), to);
}
/// <summary>
/// Copy from, to seperate container/blob
/// </summary>
/// <param name="from">From</param>
/// <param name="target">Target</param>
/// <param name="to">To</param>
/// <returns>Blob Uri</returns>
public virtual async Task<string> Copy(string from, IContainer target, string to)
{
if (string.IsNullOrWhiteSpace(from))
{
throw new ArgumentException("from");
}
if (null == target)
{
throw new ArgumentNullException("target");
}
if (string.IsNullOrWhiteSpace(to))
{
throw new ArgumentException("to");
}
var source = this.GetBlockReference(from);
var targetBlockBlob = target.GetBlockReference(to);
return await targetBlockBlob.StartCopyAsync(source);
}
#endregion
}
}

107
King.Azure/FileShare.cs Normal file
Просмотреть файл

@ -0,0 +1,107 @@
namespace King.Azure.Data
{
using System;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.File;
/// <summary>
/// File Share
/// </summary>
public class FileShare : AzureStorage, IFileShare
{
#region Members
/// <summary>
/// Client
/// </summary>
private readonly CloudFileClient client;
/// <summary>
/// Reference
/// </summary>
private readonly CloudFileShare reference;
#endregion
#region Constructors
/// <summary>
/// File Share Constructor
/// </summary>
/// <param name="name">Name</param>
/// <param name="connectionString">Connection String</param>
public FileShare(string name, string connectionString)
: base(connectionString)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("name");
}
this.client = this.Account.CreateCloudFileClient();
this.reference = this.client.GetShareReference(name);
}
/// <summary>
/// File Share Constructor
/// </summary>
/// <param name="name">Name</param>
/// <param name="account">Storage Account</param>
public FileShare(string name, CloudStorageAccount account)
: base(account)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("name");
}
this.client = this.Account.CreateCloudFileClient();
this.reference = this.client.GetShareReference(name);
}
#endregion
#region Properties
/// <summary>
/// Name
/// </summary>
public virtual string Name
{
get
{
return this.reference.Name;
}
}
/// <summary>
/// Client
/// </summary>
public virtual CloudFileClient Client
{
get
{
return this.client;
}
}
/// <summary>
/// Reference
/// </summary>
public virtual CloudFileShare Reference
{
get
{
return this.reference;
}
}
#endregion
#region Methods
/// <summary>
/// Create If Not Exists
/// </summary>
/// <returns>Created</returns>
public virtual async Task<bool> CreateIfNotExists()
{
return await this.reference.CreateIfNotExistsAsync();
}
#endregion
}
}

688
King.Azure/Interfaces.cs Normal file
Просмотреть файл

@ -0,0 +1,688 @@
namespace King.Azure.Data
{
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure.Storage.File;
using Microsoft.WindowsAzure.Storage.Queue;
using Microsoft.WindowsAzure.Storage.Table;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
#region IAccount
/// <summary>
/// Azure Storage Account
/// </summary>
public interface IStorageAccount
{
#region Properties
/// <summary>
/// Cloud Storage Account
/// </summary>
CloudStorageAccount Account
{
get;
}
#endregion
}
#endregion
#region IStorageClient
/// <summary>
/// Storage Client Interface
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IStorageClient<T>
{
#region Properties
/// <summary>
/// Storage Client
/// </summary>
T Client
{
get;
}
#endregion
}
#endregion
#region IStorageReference
/// <summary>
/// Storage Reference Interface
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IStorageReference<T>
{
#region Properties
/// <summary>
/// Storage Reference
/// </summary>
T Reference
{
get;
}
#endregion
}
#endregion
#region ITableStorage
/// <summary>
/// Table Storage Interface
/// </summary>
public interface ITableStorage : IAzureStorage, IStorageReference<CloudTable>, IStorageClient<CloudTableClient>
{
#region Methods
/// <summary>
/// Create Table
/// </summary>
/// <param name="tableName">Table Name</param>
Task<bool> Create();
/// <summary>
/// Insert or update the record in table
/// </summary>
/// <param name="entity">Entity</param>
Task<TableResult> InsertOrReplace(ITableEntity entity);
/// <summary>
/// Insert Batch
/// </summary>
/// <param name="entities"></param>
Task<IEnumerable<TableResult>> Insert(IEnumerable<ITableEntity> entities);
/// <summary>
/// Insert Or Replace Entity (Dictionary)
/// </summary>
/// <remarks>
/// Specify: PartitionKey, RowKey and ETag
/// </remarks>
/// <param name="entity">Entity</param>
/// <returns>Result</returns>
Task<TableResult> InsertOrReplace(IDictionary<string, object> entity);
/// <summary>
/// Insert Batch
/// </summary>
/// <param name="entities">Entities</param>
Task<IEnumerable<TableResult>> Insert(IEnumerable<IDictionary<string, object>> entities);
/// <summary>
/// Query By Partition
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="partition"></param>
/// <returns></returns>
Task<IEnumerable<T>> QueryByPartition<T>(string partition)
where T : ITableEntity, new();
/// <summary>
/// Query By Partition
/// </summary>
/// <remarks>
/// Without providing the partion this query may not perform well.
/// </remarks>
/// <typeparam name="T"></typeparam>
/// <param name="rowKey"></param>
/// <returns></returns>
Task<IEnumerable<T>> QueryByRow<T>(string rowKey)
where T : ITableEntity, new();
/// <summary>
/// Query By Partition
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="rowKey"></param>
/// <returns></returns>
Task<T> QueryByPartitionAndRow<T>(string partitionKey, string rowKey)
where T : ITableEntity, new();
/// <summary>
/// Query
/// </summary>
/// <typeparam name="T">Type</typeparam>
/// <param name="query">Table Query</param>
/// <returns>Results</returns>
Task<IEnumerable<T>> Query<T>(TableQuery<T> query)
where T : ITableEntity, new();
/// <summary>
/// Query by Expression
/// </summary>
/// <typeparam name="T">Table Entity</typeparam>
/// <param name="predicate">Predicate</param>
/// <param name="maxResults">Max Result</param>
/// <returns></returns>
Task<IEnumerable<T>> Query<T>(Func<T, bool> predicate, int maxResults = int.MaxValue)
where T : ITableEntity, new();
/// <summary>
/// Query By Partition
/// </summary>
/// <param name="partitionKey"></param>
/// <returns>Entities</returns>
Task<IEnumerable<IDictionary<string, object>>> QueryByPartition(string partitionKey);
/// <summary>
/// Query By Partition
/// </summary>
/// <remarks>
/// Without providing the partion this query may not perform well.
/// </remarks>
/// <param name="rowKey">Row Key</param>
/// <returns>Entities</returns>
Task<IEnumerable<IDictionary<string, object>>> QueryByRow(string rowKey);
/// <summary>
/// Query By Partition and Row
/// </summary>
/// <param name="partitionKey">Partition Key</param>
/// <param name="rowKey">Row</param>
/// <returns></returns>
Task<IDictionary<string, object>> QueryByPartitionAndRow(string partitionKey, string rowKey);
/// <summary>
/// Generic Query
/// </summary>
/// <param name="query">Query</param>
/// <returns>Entities</returns>
Task<IEnumerable<IDictionary<string, object>>> Query(TableQuery query);
/// <summary>
/// Delete By Partition
/// </summary>
/// <param name="partitionKey">Partition Key</param>
/// <returns>Task</returns>
Task DeleteByPartition(string partitionKey);
/// <summary>
/// Delete By Row
/// </summary>
/// <param name="rowKey">Row Key</param>
/// <returns>Task</returns>
Task DeleteByRow(string rowKey);
/// <summary>
/// Delete By Partition and Row
/// </summary>
/// <param name="partitionKey">Partition Key</param>
/// <param name="rowKey"></param>
/// <returns>Task</returns>
Task DeleteByPartitionAndRow(string partitionKey, string row);
/// <summary>
/// Delete Entity
/// </summary>
/// <param name="entity">Entity</param>
/// <returns>Task</returns>
Task<TableResult> Delete(ITableEntity entity);
/// <summary>
/// Delete Entities
/// </summary>
/// <param name="entities">Entities</param>
/// <returns>Table Results</returns>
Task<IEnumerable<TableResult>> Delete(IEnumerable<ITableEntity> entities);
#endregion
}
#endregion
#region IContainer
/// <summary>
/// Blob Container
/// </summary>
public interface IContainer : IAzureStorage, IStorageReference<CloudBlobContainer>, IStorageClient<CloudBlobClient>
{
#region Properties
/// <summary>
/// Is Public
/// </summary>
bool IsPublic
{
get;
}
#endregion
#region Methods
/// <summary>
/// Blob Exists
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <returns>bool</returns>
Task<bool> Exists(string blobName);
/// <summary>
/// Delete from Blob Storage
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <param name="deleteHistory">Delete History (Snapshots)</param>
/// <returns>Object</returns>
Task Delete(string blobName, bool deleteHistory = true);
/// <summary>
/// Save Object as Json to Blob Storage
/// </summary>
/// <typeparam name="T">Type</typeparam>
/// <param name="blobName">Blob Name</param>
/// <param name="obj">Object</param>
/// <returns>Task</returns>
Task Save(string blobName, object obj);
/// <summary>
/// Get Object from Blob Storage
/// </summary>
/// <typeparam name="T">Type</typeparam>
/// <param name="blobName">Blob Name</param>
/// <returns>Object</returns>
Task<T> Get<T>(string blobName);
/// <summary>
/// Stream Blob
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <returns>Stream</returns>
Task<Stream> Stream(string blobName);
/// <summary>
/// Get Reference
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <param name="snapshot">Snapshot time</param>
/// <returns>Cloud Blob</returns>
CloudBlockBlob GetBlockReference(string blobName, DateTimeOffset? snapshot = null);
/// <summary>
/// Get Reference
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <param name="snapshot">Snapshot time</param>
/// <returns>Cloud Blob</returns>
CloudPageBlob GetPageReference(string blobName, DateTimeOffset? snapshot = null);
/// <summary>
/// Save Binary Data
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <param name="bytes">Bytes</param>
/// <param name="contentType">Content Type</param>
/// <returns>Task</returns>
Task Save(string blobName, byte[] bytes, string contentType = "application/octet-stream");
/// <summary>
/// Save Text
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <param name="text">Text</param>
/// <param name="contentType">Content Type</param>
/// <returns>Task</returns>
Task Save(string blobName, string text, string contentType = "text/plain");
/// <summary>
/// Get Binary Data
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <returns>Bytes</returns>
Task<byte[]> Get(string blobName);
/// <summary>
/// Get Bytes
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <returns>Text</returns>
Task<string> GetText(string blobName);
/// <summary>
/// Blob Properties
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <returns>Blob Container Properties</returns>
Task<BlobProperties> Properties(string blobName);
/// <summary>
/// Set Cache Control
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <param name="cacheDuration">Cache Duration (Default 1 year)</param>
/// <returns>Task</returns>
Task SetCacheControl(string blobName, uint cacheDuration = Container.DefaultCacheDuration);
/// <summary>
/// List Blobs
/// </summary>
/// <param name="prefix">Prefix</param>
/// <param name="useFlatBlobListing">Use Flat Blob Listing</param>
/// <returns>Blobs</returns>
Task<IEnumerable<IListBlobItem>> List(string prefix = null, bool useFlatBlobListing = true, BlobListingDetails details = BlobListingDetails.All, int? maxResults = int.MaxValue);
/// <summary>
/// Create Snapshot
/// </summary>
/// <param name="blobName">Blob Name</param>
/// <returns>Task</returns>
Task<ICloudBlob> Snapshot(string blobName);
/// <summary>
/// Copy from, to seperate container/blob
/// </summary>
/// <param name="from">From</param>
/// <param name="target">Target</param>
/// <param name="to">To</param>
/// <returns>Blob Uri</returns>
Task<string> Copy(string from, IContainer target, string to);
/// <summary>
/// Copy from, to seperate container/blob
/// </summary>
/// <param name="from">From</param>
/// <param name="target">Target</param>
/// <param name="to">To</param>
/// <returns>Blob Uri</returns>
Task<string> Copy(string from, string target, string to);
/// <summary>
/// Copy From Blob to Blob
/// </summary>
/// <param name="from">From</param>
/// <param name="to">To</param>
/// <returns>Blob Uri</returns>
Task<string> Copy(string from, string to);
#endregion
}
#endregion
#region IQueueObject
/// <summary>
/// Queue Object Interface
/// </summary>
public interface IQueueObject
{
#region Methods
/// <summary>
/// Save Specific Message to Queue
/// </summary>
/// <param name="obj">Object</param>
/// <returns>Task</returns>
Task Send(object obj);
#endregion
}
#endregion
#region IQueue<T>
/// <summary>
/// IQueue
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IQueue<T>
{
#region Methods
/// <summary>
/// Get Cloud Queue Message
/// </summary>
/// <returns>Message</returns>
Task<T> Get();
/// <summary>
/// Delete Message from Queue
/// </summary>
/// <param name="message">Message</param>
/// <returns>Task</returns>
Task Delete(T message);
/// <summary>
/// Save Message to Queue
/// </summary>
/// <param name="message">Message</param>
/// <returns>Task</returns>
Task Send(T message);
#endregion
}
#endregion
#region IStorageQueue
/// <summary>
/// Storage Queue Interface
/// </summary>
public interface IStorageQueue : IQueue<CloudQueueMessage>, IQueueObject, IAzureStorage, IStorageReference<CloudQueue>, IStorageClient<CloudQueueClient>, IQueueCount
{
#region Methods
/// <summary>
/// Get Many Cloud Queue Message
/// </summary>
/// <returns>Messages</returns>
Task<IEnumerable<CloudQueueMessage>> GetMany(int messageCount = 5);
#endregion
}
#endregion
#region IQueueCount
/// <summary>
/// Queue Count
/// </summary>
public interface IQueueCount
{
#region Methods
/// <summary>
/// Approixmate Message Count
/// </summary>
/// <returns>Message Count</returns>
Task<long?> ApproixmateMessageCount();
#endregion
}
#endregion
#region IAzureStorage
/// <summary>
/// Azure Storage
/// </summary>
public interface IAzureStorage
{
#region Properties
/// <summary>
/// Name
/// </summary>
string Name
{
get;
}
#endregion
#region Methods
/// <summary>
/// Create If Not Exists
/// </summary>
/// <returns></returns>
Task<bool> CreateIfNotExists();
/// <summary>
/// Delete Item
/// </summary>
/// <returns>Task</returns>
Task Delete();
#endregion
}
#endregion
#region IProcessor
/// <summary>
/// IProcessor
/// </summary>
public interface IProcessor<T>
{
#region Methods
/// <summary>
/// Process Data
/// </summary>
/// <param name="data">Data to Process</param>
/// <returns>Successful</returns>
Task<bool> Process(T data);
#endregion
}
#endregion
#region IPoller
/// <summary>
/// Store Poller Interface
/// </summary>
/// <typeparam name="T">Dequeue Type</typeparam>
public interface IPoller<T>
{
#region Methods
/// <summary>
/// Poll for Queued Message
/// </summary>
/// <returns>Queued Item</returns>
Task<IQueued<T>> Poll();
/// <summary>
/// Poll for Queued Message
/// </summary>
/// <returns>Queued Item</returns>
Task<IEnumerable<IQueued<T>>> PollMany(int messageCount = 5);
#endregion
}
#endregion
#region IStorageQueuePoller
/// <summary>
/// Storage Queue Poller Interface
/// </summary>
/// <typeparam name="T">Dequeue Type</typeparam>
public interface IStorageQueuePoller<T> : IPoller<T>
{
#region Properties
/// <summary>
/// Storage Queue
/// </summary>
IStorageQueue Queue
{
get;
}
#endregion
}
#endregion
#region IQueued
/// <summary>
/// IQueued
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IQueued<T>
{
#region Methods
/// <summary>
/// Delete Message
/// </summary>
/// <returns>Task</returns>
Task Complete();
/// <summary>
/// Abandon Message
/// </summary>
/// <returns>Task</returns>
Task Abandon();
/// <summary>
/// Data
/// </summary>
/// <returns>Data</returns>
Task<T> Data();
#endregion
}
#endregion
#region IAzureStorageResources
/// <summary>
/// Azure Storage Resources Interface
/// </summary>
public interface IAzureStorageResources
{
#region Methods
/// <summary>
/// List Table Names
/// </summary>
/// <returns>Table Names</returns>
Task<IEnumerable<string>> TableNames();
/// <summary>
/// List Tables
/// </summary>
/// <returns>Tables</returns>
Task<IEnumerable<ITableStorage>> Tables();
/// <summary>
/// List Container Names
/// </summary>
/// <returns>Container Names</returns>
Task<IEnumerable<string>> ContainerNames();
/// <summary>
/// List Containers
/// </summary>
/// <returns>Containers</returns>
Task<IEnumerable<IContainer>> Containers();
/// <summary>
/// List Queue Names
/// </summary>
/// <returns>Queue Names</returns>
Task<IEnumerable<string>> QueueNames();
/// <summary>
/// List Queues
/// </summary>
/// <returns>Queues</returns>
Task<IEnumerable<IStorageQueue>> Queues();
#endregion
}
#endregion
#region IFileShare
/// <summary>
/// File Share Interface
/// </summary>
public interface IFileShare : IStorageReference<CloudFileShare>, IStorageClient<CloudFileClient>
{
}
#endregion
#region QueueShardSender
/// <summary>
/// Queue Shard Sender
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IQueueShardSender<T>
{
#region Properties
/// <summary>
/// Queues
/// </summary>
IReadOnlyCollection<T> Queues
{
get;
}
#endregion
#region Methods
/// <summary>
/// Queue Message to shard, 0 means at random
/// </summary>
/// <param name="obj">message</param>
/// <param name="shardTarget">Shard Target</param>
/// <returns>Task</returns>
Task Save(object obj, byte shardTarget = 0);
/// <summary>
/// Create all queues
/// </summary>
/// <returns></returns>
Task<bool> CreateIfNotExists();
/// <summary>
/// Delete all queues
/// </summary>
/// <returns>Task</returns>
Task Delete();
#endregion
}
#endregion
}

Просмотреть файл

@ -0,0 +1,72 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>King.Azure.Data Class Library</Description>
<AssemblyTitle>King.Azure</AssemblyTitle>
<VersionPrefix>2.0.19</VersionPrefix>
<Authors>Jef King</Authors>
<TargetFrameworks>netcoreapp1.0;netstandard1.3;net45;net451;net452;net46;net461;net462</TargetFrameworks>
<AssemblyName>King.Azure</AssemblyName>
<PackageId>King.Azure</PackageId>
<PackageTags>King.Azure;Azure;Storage;Mock;Mockable;Simple;Data;Table;Storage;File;Share;File-Share;Queue;Queuing;Blob;Query;dependency;injection;dependency-injection;Cloud;Table-Storage;Windows-Azure;Windows;dotNet;CSharp;Mocking;Data-Table;Blob;Json;WindowsAzure.Storage;.NetCore;DNX</PackageTags>
<PackageReleaseNotes>Updated Dependancies.</PackageReleaseNotes>
<PackageIconUrl>https://raw.githubusercontent.com/jefking/King.Azure/master/icon.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/jefking/King.Azure</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/jefking/King.Azure/blob/master/LICENSE</PackageLicenseUrl>
<PackageTargetFallback Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">$(PackageTargetFallback);portable-net451+win8</PackageTargetFallback>
<PackageTargetFallback Condition=" '$(TargetFramework)' == 'netstandard1.3' ">$(PackageTargetFallback);portable-net451+win8</PackageTargetFallback>
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<ApplicationIcon>icon.ico</ApplicationIcon>
<RepositoryUrl>https://github.com/jefking/King.Azure</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netcoreapp1.0|AnyCPU'">
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
<TreatSpecificWarningsAsErrors />
<DefineConstants>TRACE;RELEASE;NETCOREAPP1_0</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="WindowsAzure.Storage" Version="8.1.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net46' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net462' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,15 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("King.Azure")]
[assembly: AssemblyDescription("Azure Storage Simplified")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("King.Azure")]
[assembly: AssemblyCopyright("Copyright © Jef King 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("4e7ae8fe-0ee3-44a4-bae7-2ea46062c10e")]
[assembly: AssemblyVersion("2.0.0.11")]
[assembly: AssemblyFileVersion("2.0.0.11")]

211
King.Azure/StorageQueue.cs Normal file
Просмотреть файл

@ -0,0 +1,211 @@
namespace King.Azure.Data
{
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Queue;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
/// <summary>
/// Storage Queue
/// </summary>
public class StorageQueue : AzureStorage, IStorageQueue
{
#region Members
/// <summary>
/// Cloud Queue Client
/// </summary>
private readonly CloudQueueClient client;
/// <summary>
/// Cloud Reference
/// </summary>
private readonly CloudQueue reference;
/// <summary>
/// Visibility Timeout
/// </summary>
protected readonly TimeSpan? visibilityTimeout = null;
#endregion
#region Constructors
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Name</param>
/// <param name="connectionStringKey">Connection String</param>
public StorageQueue(string name, string connectionString, TimeSpan? visibilityTimeout = null)
: base(connectionString)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("name");
}
this.client = base.Account.CreateCloudQueueClient();
this.reference = client.GetQueueReference(name);
this.visibilityTimeout = visibilityTimeout;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Name</param>
/// <param name="account">Storage Account</param>
public StorageQueue(string name, CloudStorageAccount account, TimeSpan? visibilityTimeout = null)
: base(account)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("name");
}
this.client = base.Account.CreateCloudQueueClient();
this.reference = client.GetQueueReference(name);
this.visibilityTimeout = visibilityTimeout;
}
#endregion
#region Properties
/// <summary>
/// Table Name
/// </summary>
public virtual string Name
{
get
{
return this.reference.Name;
}
}
/// <summary>
/// Cloud Queue Client
/// </summary>
public virtual CloudQueueClient Client
{
get
{
return this.client;
}
}
/// <summary>
/// Cloud Reference
/// </summary>
public virtual CloudQueue Reference
{
get
{
return this.reference;
}
}
#endregion
#region Methods
/// <summary>
/// Create If Not Exists
/// </summary>
/// <returns>Created</returns>
public virtual async Task<bool> CreateIfNotExists()
{
return await this.reference.CreateIfNotExistsAsync();
}
/// <summary>
/// Delete Queue
/// </summary>
/// <returns>Task</returns>
public virtual async Task Delete()
{
await this.reference.DeleteAsync();
}
/// <summary>
/// Get Cloud Queue Message
/// </summary>
/// <returns>Message</returns>
public virtual async Task<CloudQueueMessage> Get()
{
return await this.reference.GetMessageAsync(this.visibilityTimeout, null, null);
}
/// <summary>
/// Approixmate Message Count
/// </summary>
/// <returns>Message Count</returns>
public virtual async Task<long?> ApproixmateMessageCount()
{
await this.reference.FetchAttributesAsync();
return this.reference.ApproximateMessageCount;
}
/// <summary>
/// Get Many Cloud Queue Message
/// </summary>
/// <param name="messageCount">Message Count</param>
/// <returns>Messages</returns>
public virtual async Task<IEnumerable<CloudQueueMessage>> GetMany(int messageCount = 5)
{
if (0 >= messageCount)
{
messageCount = 1;
}
return await this.reference.GetMessagesAsync(messageCount, this.visibilityTimeout, null, null);
}
/// <summary>
/// Save Message to Queue
/// </summary>
/// <param name="message">Message</param>
/// <returns>Task</returns>
public virtual async Task Send(CloudQueueMessage message)
{
if (null == message)
{
throw new ArgumentNullException("message");
}
await this.reference.AddMessageAsync(message);
}
/// <summary>
/// Save Model to queue, as json
/// </summary>
/// <param name="obj">object</param>
/// <returns>Task</returns>
public virtual async Task Send(object obj)
{
if (null == obj)
{
throw new ArgumentNullException("obj");
}
if (obj is CloudQueueMessage)
{
await this.Send(obj as CloudQueueMessage);
}
else
{
await this.Send(new CloudQueueMessage(JsonConvert.SerializeObject(obj)));
}
}
/// <summary>
/// Delete Message from Queue
/// </summary>
/// <param name="message">Message</param>
/// <returns>Task</returns>
public virtual async Task Delete(CloudQueueMessage message)
{
if (null == message)
{
throw new ArgumentNullException("message");
}
await this.reference.DeleteMessageAsync(message);
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,89 @@
namespace King.Azure.Data
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
/// <summary>
/// Queue Poller
/// </summary>
/// <typeparam name="T">Type</typeparam>
public class StorageQueuePoller<T> : IStorageQueuePoller<T>
{
#region Members
/// <summary>
/// Queue
/// </summary>
protected readonly IStorageQueue queue = null;
#endregion
#region Constructors
/// <summary>
/// Default Constructor
/// </summary>
/// <param name="queueName">Queue Name</param>
/// <param name="connectionString">Connection String</param>
public StorageQueuePoller(string queueName, string connectionString)
: this(new StorageQueue(queueName, connectionString))
{
}
/// <summary>
/// Constructor for Mocking
/// </summary>
/// <param name="queue">Queue</param>
public StorageQueuePoller(IStorageQueue queue)
{
if (null == queue)
{
throw new ArgumentNullException("queue");
}
this.queue = queue;
}
#endregion
#region Properties
/// <summary>
/// Storage Queue
/// </summary>
public virtual IStorageQueue Queue
{
get
{
return this.queue;
}
}
#endregion
#region Methods
/// <summary>
/// Poll for Queued Message
/// </summary>
/// <returns>Queued Item</returns>
public virtual async Task<IQueued<T>> Poll()
{
var msg = await this.queue.Get();
return null == msg ? null : new StorageQueuedMessage<T>(this.queue, msg);
}
/// <summary>
/// Poll for Queued Message
/// </summary>
/// <returns>Queued Item</returns>
public virtual async Task<IEnumerable<IQueued<T>>> PollMany(int messageCount = 5)
{
messageCount = 0 >= messageCount ? 5 : messageCount;
var msgs = await this.queue.GetMany(messageCount);
if (null == msgs || !msgs.Any())
{
return null;
}
return msgs.Where(m => m != null).Select(m => new StorageQueuedMessage<T>(this.queue, m));
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,159 @@
namespace King.Azure.Data
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
/// <summary>
/// Queue Shard Sender
/// </summary>
public class StorageQueueShards : IQueueShardSender<IStorageQueue>, IAzureStorage
{
#region Members
/// <summary>
/// Queues
/// </summary>
protected readonly IEnumerable<IStorageQueue> queues;
/// <summary>
/// Base of the Name
/// </summary>
protected readonly string baseName;
#endregion
#region Constructors
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Name</param>
/// <param name="connection">Connection</param>
/// <param name="shardCount">Shard Count</param>
public StorageQueueShards(string name, string connection, byte shardCount = 2)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("name");
}
if (string.IsNullOrWhiteSpace(connection))
{
throw new ArgumentException("connection");
}
this.baseName = name;
shardCount = shardCount > 0 ? shardCount : (byte)2;
var qs = new IStorageQueue[shardCount];
for (var i = 0; i < shardCount; i++)
{
var n = string.Format("{0}{1}", this.baseName, i);
qs[i] = new StorageQueue(n, connection);
}
this.queues = new ReadOnlyCollection<IStorageQueue>(qs);
}
/// <summary>
/// Constructor for mocking
/// </summary>
/// <param name="queues">Queues</param>
public StorageQueueShards(IEnumerable<IStorageQueue> queues)
{
if (null == queues)
{
throw new ArgumentNullException("queue");
}
if (0 == queues.Count())
{
throw new ArgumentException("Queues length is 0.");
}
this.queues = queues;
}
#endregion
#region Properties
/// <summary>
/// Queues
/// </summary>
public virtual IReadOnlyCollection<IStorageQueue> Queues
{
get
{
return new ReadOnlyCollection<IStorageQueue>(this.queues.ToList());
}
}
/// <summary>
/// Name
/// </summary>
public string Name
{
get
{
return this.baseName;
}
}
#endregion
#region Methods
/// <summary>
/// Queue Message
/// </summary>
/// <param name="obj">Message</param>
/// <param name="shardTarget">Shard Target</param>
/// <returns>Created</returns>
public virtual async Task<bool> CreateIfNotExists()
{
var success = true;
foreach (var q in this.queues)
{
success &= await q.CreateIfNotExists();
}
return success;
}
/// <summary>
/// Delete all queues
/// </summary>
/// <returns>Task</returns>
public virtual async Task Delete()
{
foreach (var q in this.queues)
{
await q.Delete();
}
}
/// <summary>
/// Queue Message to shard, 0 means at random
/// </summary>
/// <param name="obj">Message</param>
/// <param name="shardTarget">Shard Target</param>
/// <returns>Task</returns>
public virtual async Task Save(object obj, byte shardTarget = 0)
{
var index = this.Index(shardTarget);
var q = this.queues.ElementAt(index);
await q.Send(obj);
}
/// <summary>
/// Determine index of queues to interact with
/// </summary>
/// <remarks>
/// Specifically broken out for testing safety
/// </remarks>
/// <param name="shardTarget">Shard Target</param>
/// <returns>Index</returns>
public virtual byte Index(byte shardTarget)
{
var random = new Random();
var count = this.queues.Count();
return shardTarget == 0 || shardTarget > count ? (byte)random.Next(0, count) : shardTarget;
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,78 @@
namespace King.Azure.Data
{
using Microsoft.WindowsAzure.Storage.Queue;
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
/// <summary>
/// Queued Message
/// </summary>
/// <typeparam name="T">Type</typeparam>
public class StorageQueuedMessage<T> : IQueued<T>
{
#region Members
/// <summary>
/// Storage Queue
/// </summary>
protected readonly IStorageQueue queue = null;
/// <summary>
/// Cloud Queue Message
/// </summary>
protected readonly CloudQueueMessage message = null;
#endregion
#region Constructors
/// <summary>
/// Default Constructor
/// </summary>
/// <param name="queue">Queue</param>
/// <param name="message">Cloud Queue Message</param>
public StorageQueuedMessage(IStorageQueue queue, CloudQueueMessage message)
{
if (null == queue)
{
throw new ArgumentNullException("queue");
}
if (null == message)
{
throw new ArgumentNullException("message");
}
this.queue = queue;
this.message = message;
}
#endregion
#region Methods
/// <summary>
/// Delete Message
/// </summary>
/// <returns>Task</returns>
public virtual async Task Complete()
{
await this.queue.Delete(this.message);
}
/// <summary>
/// Abandon Message
/// </summary>
/// <returns>Task</returns>
public virtual async Task Abandon()
{
await Task.Factory.StartNew(() => { }); //No Abandon?
}
/// <summary>
/// Data
/// </summary>
/// <returns>Data</returns>
public virtual async Task<T> Data()
{
return await Task.Factory.StartNew(() => JsonConvert.DeserializeObject<T>(this.message.AsString));
}
#endregion
}
}

556
King.Azure/TableStorage.cs Normal file
Просмотреть файл

@ -0,0 +1,556 @@
namespace King.Azure.Data
{
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.RetryPolicies;
using Microsoft.WindowsAzure.Storage.Table;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
/// <summary>
/// Table Storage
/// </summary>
public class TableStorage : AzureStorage, ITableStorage
{
#region Members
/// <summary>
/// Partition Key
/// </summary>
public const string PartitionKey = "PartitionKey";
/// <summary>
/// Row Key
/// </summary>
public const string RowKey = "RowKey";
/// <summary>
/// Timestamp
/// </summary>
public const string Timestamp = "Timestamp";
/// <summary>
/// ETag
/// </summary>
public const string ETag = "ETag";
/// <summary>
/// Maximum Insert Batch
/// </summary>
public const int MaimumxInsertBatch = 100;
/// <summary>
/// Table Client
/// </summary>
private readonly CloudTableClient client;
/// <summary>
/// Table
/// </summary>
private readonly CloudTable reference;
#endregion
#region Constructors
/// <summary>
/// Table Storage
/// </summary>
/// <param name="tableName">Table Name</param>
/// <param name="connectionString">Connection String</param>
/// <param name="location">Location Mode</param>
public TableStorage(string tableName, string connectionString, LocationMode location = LocationMode.PrimaryThenSecondary)
: this(tableName, CloudStorageAccount.Parse(connectionString), location)
{
}
/// <summary>
/// Table Storage
/// </summary>
/// <param name="tableName">Table Name</param>
/// <param name="account">Storage Account</param>
/// <param name="location">Location Mode</param>
public TableStorage(string tableName, CloudStorageAccount account, LocationMode location = LocationMode.PrimaryThenSecondary)
: base(account)
{
if (string.IsNullOrWhiteSpace(tableName))
{
throw new ArgumentException("tableName");
}
this.client = base.Account.CreateCloudTableClient();
this.client.DefaultRequestOptions.LocationMode = location;
this.reference = client.GetTableReference(tableName);
}
#endregion
#region Properties
/// <summary>
/// Table Name
/// </summary>
public virtual string Name
{
get
{
return this.reference.Name;
}
}
/// <summary>
/// Table Client
/// </summary>
public virtual CloudTableClient Client
{
get
{
return this.client;
}
}
/// <summary>
/// Table
/// </summary>
public virtual CloudTable Reference
{
get
{
return this.reference;
}
}
#endregion
#region Create Table
/// <summary>
/// Create If Not Exists
/// </summary>
/// <returns></returns>
public virtual async Task<bool> CreateIfNotExists()
{
return await this.reference.CreateIfNotExistsAsync();
}
/// <summary>
/// Create Table
/// </summary>
/// <param name="tableName">Table Name</param>
public virtual async Task<bool> Create()
{
return await this.reference.CreateIfNotExistsAsync();
}
#endregion
#region Delete
/// <summary>
/// Delete Table
/// </summary>
/// <param name="tableName"></param>
public virtual async Task Delete()
{
await this.reference.DeleteAsync();
}
/// <summary>
/// Delete By Partition
/// </summary>
/// <param name="partitionKey">Partition Key</param>
/// <returns>Task</returns>
public virtual async Task DeleteByPartition(string partitionKey)
{
var entities = await this.QueryByPartition<TableEntity>(partitionKey);
if (null != entities && entities.Any())
{
await this.Delete(entities);
}
}
/// <summary>
/// Delete By Row
/// </summary>
/// <param name="rowKey">Row Key</param>
/// <returns>Task</returns>
public virtual async Task DeleteByRow(string rowKey)
{
var entities = await this.QueryByRow<TableEntity>(rowKey);
if (null != entities && entities.Any())
{
foreach (var entity in entities)
{
await this.Delete(entity);
}
}
}
/// <summary>
/// Delete By Partition and Row
/// </summary>
/// <param name="partitionKey">Partition Key</param>
/// <param name="rowKey">Row Key</param>
/// <returns>Task</returns>
public virtual async Task DeleteByPartitionAndRow(string partitionKey, string rowKey)
{
var entity = await this.QueryByPartitionAndRow<TableEntity>(partitionKey, rowKey);
if (null != entity)
{
await this.Delete(entity);
}
}
/// <summary>
/// Delete Entity
/// </summary>
/// <param name="entity">Entity</param>
/// <returns>Task</returns>
public virtual async Task<TableResult> Delete(ITableEntity entity)
{
if (null == entity)
{
throw new ArgumentNullException("entity");
}
return await this.reference.ExecuteAsync(TableOperation.Delete(entity));
}
/// <summary>
/// Delete Entities
/// </summary>
/// <param name="entities">Entities</param>
/// <returns>Table Results</returns>
public virtual async Task<IEnumerable<TableResult>> Delete(IEnumerable<ITableEntity> entities)
{
if (null == entities)
{
throw new ArgumentNullException("entities");
}
if (!entities.Any())
{
return null;
}
var result = new List<TableResult>();
foreach (var batch in this.Batch(entities))
{
var batchOperation = new TableBatchOperation();
batch.ToList().ForEach(e => batchOperation.Delete(e));
var r = await this.reference.ExecuteBatchAsync(batchOperation);
result.AddRange(r);
}
return result;
}
#endregion
#region Save Data
/// <summary>
/// Insert or update the record in table
/// </summary>
/// <param name="entity">Entity</param>
public virtual async Task<TableResult> InsertOrReplace(ITableEntity entity)
{
return await this.reference.ExecuteAsync(TableOperation.InsertOrReplace(entity));
}
/// <summary>
/// Insert Batch
/// </summary>
/// <param name="entities">Entities</param>
public virtual async Task<IEnumerable<TableResult>> Insert(IEnumerable<ITableEntity> entities)
{
var result = new List<TableResult>();
foreach (var batch in this.Batch(entities))
{
var batchOperation = new TableBatchOperation();
batch.ToList().ForEach(e => batchOperation.InsertOrReplace(e));
var r = await this.reference.ExecuteBatchAsync(batchOperation);
result.AddRange(r);
}
return result;
}
/// <summary>
/// Insert Or Replace Entity (Dictionary)
/// </summary>
/// <remarks>
/// Specify: PartitionKey, RowKey and ETag
/// </remarks>
/// <param name="entity">Entity</param>
/// <returns>Result</returns>
public virtual async Task<TableResult> InsertOrReplace(IDictionary<string, object> entity)
{
if (null == entity)
{
throw new ArgumentNullException("data");
}
var properties = new Dictionary<string, EntityProperty>();
entity.Keys.Where(k => k != PartitionKey && k != RowKey && k != ETag).ToList().ForEach(key => properties.Add(key, EntityProperty.CreateEntityPropertyFromObject(entity[key])));
var partitionKey = entity.Keys.Contains(PartitionKey) ? entity[PartitionKey].ToString() : string.Empty;
var rowKey = entity.Keys.Contains(RowKey) ? entity[RowKey].ToString() : string.Empty;
var etag = entity.Keys.Contains(ETag) ? entity[ETag].ToString() : null;
var dynamicEntity = new DynamicTableEntity(partitionKey, rowKey, etag, properties);
return await this.InsertOrReplace(dynamicEntity);
}
/// <summary>
/// Insert Batch
/// </summary>
/// <param name="entities">Entities</param>
public virtual async Task<IEnumerable<TableResult>> Insert(IEnumerable<IDictionary<string, object>> entities)
{
var result = new List<TableResult>();
foreach (var batch in this.Batch(entities))
{
var batchOperation = new TableBatchOperation();
foreach (var entity in batch)
{
var properties = new Dictionary<string, EntityProperty>();
entity.Keys.Where(k => k != PartitionKey && k != RowKey && k != ETag).ToList().ForEach(key => properties.Add(key, EntityProperty.CreateEntityPropertyFromObject(entity[key])));
var partitionKey = entity.Keys.Contains(PartitionKey) ? entity[PartitionKey].ToString() : string.Empty;
var rowKey = entity.Keys.Contains(RowKey) ? entity[RowKey].ToString() : string.Empty;
var etag = entity.Keys.Contains(ETag) ? entity[ETag].ToString() : null;
batchOperation.InsertOrMerge(new DynamicTableEntity(partitionKey, rowKey, etag, properties));
}
var r = await this.reference.ExecuteBatchAsync(batchOperation);
result.AddRange(r);
}
return result;
}
#endregion
#region Query Object
/// <summary>
/// Query By Partition
/// </summary>
/// <typeparam name="T">Return Type</typeparam>
/// <param name="partitionKey"></param>
/// <returns>Entities</returns>
public virtual async Task<IEnumerable<T>> QueryByPartition<T>(string partitionKey)
where T : ITableEntity, new()
{
var query = new TableQuery<T>().Where(TableQuery.GenerateFilterCondition(PartitionKey, QueryComparisons.Equal, partitionKey));
return await this.Query<T>(query);
}
/// <summary>
/// Query By Partition
/// </summary>
/// <remarks>
/// Without providing the partion this query may not perform well.
/// </remarks>
/// <typeparam name="T">Return Type</typeparam>
/// <param name="rowKey">Row Key</param>
/// <returns>Entities</returns>
public virtual async Task<IEnumerable<T>> QueryByRow<T>(string rowKey)
where T : ITableEntity, new()
{
var query = new TableQuery<T>().Where(TableQuery.GenerateFilterCondition(RowKey, QueryComparisons.Equal, rowKey));
return await this.Query<T>(query);
}
/// <summary>
/// Query By Partition and Row
/// </summary>
/// <typeparam name="T">Return Type</typeparam>
/// <param name="partitionKey">Partition Key</param>
/// <param name="rowKey">Row</param>
/// <returns></returns>
public virtual async Task<T> QueryByPartitionAndRow<T>(string partitionKey, string rowKey)
where T : ITableEntity, new()
{
var partitionFilter = TableQuery.GenerateFilterCondition(PartitionKey, QueryComparisons.Equal, partitionKey);
var rowFilter = TableQuery.GenerateFilterCondition(RowKey, QueryComparisons.Equal, rowKey);
var filter = TableQuery.CombineFilters(partitionFilter, TableOperators.And, rowFilter);
var query = new TableQuery<T>().Where(filter);
var result = await this.Query<T>(query);
return result.FirstOrDefault();
}
/// <summary>
/// Query by Expression
/// </summary>
/// <remarks>Filtering is done on client; can be expensive</remarks>
/// <typeparam name="T">Return Type</typeparam>
/// <param name="predicate">Predicate</param>
/// <param name="maxResults">Max Result</param>
/// <returns></returns>
public virtual async Task<IEnumerable<T>> Query<T>(Func<T, bool> predicate, int maxResults = int.MaxValue)
where T : ITableEntity, new()
{
if (null == predicate)
{
throw new ArgumentNullException("predicate");
}
if (0 >= maxResults)
{
throw new InvalidOperationException("maxResults: must be above 0.");
}
var items = await this.Query<T>(new TableQuery<T>());
return items.Where(predicate).Take(maxResults);
}
/// <summary>
/// Query
/// </summary>
/// <typeparam name="T">Return Type</typeparam>
/// <param name="query">Table Query</param>
/// <returns>Results</returns>
public virtual async Task<IEnumerable<T>> Query<T>(TableQuery<T> query)
where T : ITableEntity, new()
{
if (null == query)
{
throw new ArgumentNullException("query");
}
var entities = new List<T>();
TableContinuationToken token = null;
do
{
var queryResult = await this.reference.ExecuteQuerySegmentedAsync<T>(query, token);
entities.AddRange(queryResult.Results);
token = queryResult.ContinuationToken;
}
while (null != token);
return entities;
}
#endregion
#region Query Dictionary
/// <summary>
/// Query By Partition
/// </summary>
/// <param name="partitionKey"></param>
/// <returns>Entities</returns>
public virtual async Task<IEnumerable<IDictionary<string, object>>> QueryByPartition(string partitionKey)
{
return await this.Query(new TableQuery().Where(TableQuery.GenerateFilterCondition(TableStorage.PartitionKey, QueryComparisons.Equal, partitionKey)));
}
/// <summary>
/// Query By Partition
/// </summary>
/// <remarks>
/// Without providing the partion this query may not perform well.
/// </remarks>
/// <param name="rowKey">Row Key</param>
/// <returns>Entities</returns>
public virtual async Task<IEnumerable<IDictionary<string, object>>> QueryByRow(string rowKey)
{
return await this.Query(new TableQuery().Where(TableQuery.GenerateFilterCondition(TableStorage.RowKey, QueryComparisons.Equal, rowKey)));
}
/// <summary>
/// Query By Partition and Row
/// </summary>
/// <param name="partitionKey">Partition Key</param>
/// <param name="rowKey">Row</param>
/// <returns></returns>
public virtual async Task<IDictionary<string, object>> QueryByPartitionAndRow(string partitionKey, string rowKey)
{
var partitionFilter = TableQuery.GenerateFilterCondition(TableStorage.PartitionKey, QueryComparisons.Equal, partitionKey);
var rowFilter = TableQuery.GenerateFilterCondition(TableStorage.RowKey, QueryComparisons.Equal, rowKey);
var filter = TableQuery.CombineFilters(partitionFilter, TableOperators.And, rowFilter);
var query = new TableQuery().Where(filter);
var result = await this.Query(query);
return result.FirstOrDefault();
}
/// <summary>
/// Generic Query
/// </summary>
/// <param name="query">Query</param>
/// <returns>Entities</returns>
public virtual async Task<IEnumerable<IDictionary<string, object>>> Query(TableQuery query)
{
if (null == query)
{
throw new ArgumentNullException("query");
}
var q = new TableQuery<DynamicTableEntity>()
{
FilterString = query.FilterString,
SelectColumns = query.SelectColumns,
TakeCount = query.TakeCount
};
var entities = new List<DynamicTableEntity>();
TableContinuationToken token = null;
do
{
var queryResult = await this.reference.ExecuteQuerySegmentedAsync<DynamicTableEntity>(q, token);
entities.AddRange(queryResult.Results);
token = queryResult.ContinuationToken;
}
while (null != token);
var results = new List<IDictionary<string, object>>();
foreach (var e in entities)
{
var dic = new Dictionary<string, object>();
foreach (var p in e.Properties)
{
dic.Add(p.Key, p.Value.PropertyAsObject);
}
dic.Add(TableStorage.PartitionKey, e.PartitionKey);
dic.Add(TableStorage.RowKey, e.RowKey);
dic.Add(TableStorage.ETag, e.ETag);
dic.Add(TableStorage.Timestamp, e.Timestamp.DateTime);
results.Add(dic);
}
return results;
}
#endregion
#region Additional Methods
/// <summary>
/// Break Entities into batches
/// </summary>
/// <param name="entities">Entities</param>
/// <returns>Batches</returns>
public virtual IEnumerable<IEnumerable<ITableEntity>> Batch(IEnumerable<ITableEntity> entities)
{
return entities.GroupBy(en => en.PartitionKey).SelectMany(e => this.Chunk<ITableEntity>(e));
}
/// <summary>
/// Break Entities into batches
/// </summary>
/// <param name="entities">Entities</param>
/// <returns>Batches</returns>
public virtual IEnumerable<IEnumerable<IDictionary<string, object>>> Batch(IEnumerable<IDictionary<string, object>> entities)
{
return entities.GroupBy(en => en[PartitionKey]).SelectMany(e => this.Chunk<IDictionary<string, object>>(e));
}
/// <summary>
/// Chunk data into smaller blocks
/// </summary>
/// <typeparam name="T">Type</typeparam>
/// <param name="entities">Entities</param>
/// <returns>Chunks</returns>
public virtual IEnumerable<IEnumerable<T>> Chunk<T>(IEnumerable<T> entities)
{
return entities.Select((x, i) => new { Index = i, Value = x }).GroupBy(x => x.Index / TableStorage.MaimumxInsertBatch).Select(x => x.Select(v => v.Value));
}
#endregion
}
}

Двоичные данные
King.Azure/icon.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 5.3 KiB

42
LICENSE
Просмотреть файл

@ -1,21 +1,21 @@
MIT License
Copyright (c) Microsoft Corporation. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
MIT License
Copyright (c) Microsoft Corporation. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE

Просмотреть файл

@ -1,3 +1,19 @@
# Contributing
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
# Contributing
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
## Azure Storage Simplified
- Queues/Blobs/Tables/File Shares
- Azure Storage Resources
- Dependancy Injection
- Mockable for testing
- Prefer async calls
- Plugs into the [King.Service](https://github.com/jefking/King.Service) task framework
## [NuGet](https://www.nuget.org/packages/King.Azure)
```
PM> Install-Package King.Azure
```
### [Wiki](https://github.com/jefking/King.Azure/wiki)
View the wiki to learn how to use this.

Двоичные данные
icon.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 5.3 KiB

Двоичные данные
icon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.3 KiB