Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion GeekLearning.Storage.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25123.0
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "GeekLearning.Storage", "src\GeekLearning.Storage\GeekLearning.Storage.xproj", "{1F419C53-73C6-4460-B284-6A49AE41C596}"
EndProject
Expand All @@ -25,6 +25,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
EndProjectSection
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "GeekLearning.Storage.FileSystem.Server", "src\GeekLearning.Storage.FileSystem.Server\GeekLearning.Storage.FileSystem.Server.xproj", "{9D94CD6C-9451-449A-BED2-1C07D624A8E0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -51,6 +53,10 @@ Global
{590B21B0-2AFA-4329-82AD-EF180C50EB5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{590B21B0-2AFA-4329-82AD-EF180C50EB5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{590B21B0-2AFA-4329-82AD-EF180C50EB5C}.Release|Any CPU.Build.0 = Release|Any CPU
{9D94CD6C-9451-449A-BED2-1C07D624A8E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9D94CD6C-9451-449A-BED2-1C07D624A8E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D94CD6C-9451-449A-BED2-1C07D624A8E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D94CD6C-9451-449A-BED2-1C07D624A8E0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public ValuesController(TemplatesStore templates)
public async Task<IEnumerable<string>> Get()
{

return new string[] { await templates.Store.ReadAllText("json.json"), "value2" };
return new string[] { await templates.Store.ReadAllTextAsync("json.json"), "value2" };
}

// GET api/values/5
Expand Down
9 changes: 8 additions & 1 deletion samples/GeekLearning.Storage.BasicSample/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,25 @@ public Startup(IHostingEnvironment env)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
HostingEnvironement = env;
}

public IConfigurationRoot Configuration { get; }
public IHostingEnvironment HostingEnvironement { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();

services.AddStorage()
.AddAzureStorage()
.AddFileSystemStorage(HostingEnvironement.ContentRootPath);

services.AddStorage().AddAzureStorage().AddFileSystemStorage();
services.Configure<StorageOptions>(Configuration.GetSection("Storage"));

services.AddScoped<TemplatesStore>();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
Expand Down
10 changes: 10 additions & 0 deletions samples/GeekLearning.Storage.BasicSample/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,15 @@
"System": "Information",
"Microsoft": "Information"
}
},
"Storage": {
"Stores": {
"Templates": {
"Provider": "FileSystem",
"Parameters": {
"Path" : "Templates"
}
}
}
}
}
123 changes: 90 additions & 33 deletions src/GeekLearning.Storage.Azure/AzureStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,96 +34,153 @@ public AzureStore(string connectionString, string containerName)
container = new Lazy<CloudBlobContainer>(() => this.client.Value.GetContainerReference(this.containerName));
}

public Task<string> GetExpirableUri(string uri)
private async Task<Internal.AzureFileReference> InternalGetAsync(IPrivateFileReference file)
{
throw new NotImplementedException();
return new Internal.AzureFileReference(file.Path, await this.container.Value.GetBlobReferenceFromServerAsync(file.Path));
}

public async Task<MemoryStream> ReadInMemory(string path)
public async Task<IFileReference> GetAsync(IPrivateFileReference file)
{
var memoryStream = new MemoryStream();
var blockBlob = await GetBlobReference(path);
await blockBlob.DownloadRangeToStreamAsync(memoryStream, null, null);
return memoryStream;
return await InternalGetAsync(file);
}

private Task<ICloudBlob> GetBlobReference(string path)
public async Task<IFileReference> GetAsync(Uri uri)
{
var uri = new Uri(path, UriKind.RelativeOrAbsolute);
if (uri.IsAbsoluteUri)
{
return this.client.Value.GetBlobReferenceFromServerAsync(uri);
return new Internal.AzureFileReference(await this.client.Value.GetBlobReferenceFromServerAsync(uri));
}
else
{
return this.container.Value.GetBlobReferenceFromServerAsync(path);
return new Internal.AzureFileReference(await this.container.Value.GetBlobReferenceFromServerAsync(uri.ToString()));
}
}

public async Task<Stream> Read(string path)

public async Task<Stream> ReadAsync(IPrivateFileReference file)
{
return await this.ReadInMemory(path);
var fileReference = await InternalGetAsync(file);
return await fileReference.ReadInMemoryAsync();
}

public async Task<byte[]> ReadAllBytes(string path)
public async Task<byte[]> ReadAllBytesAsync(IPrivateFileReference file)
{
var stream = await this.ReadInMemory(path);
return stream.ToArray();
var fileReference = await InternalGetAsync(file);
return (await fileReference.ReadInMemoryAsync()).ToArray();
}

public async Task<string> ReadAllText(string path)
public async Task<string> ReadAllTextAsync(IPrivateFileReference file)
{
var blockBlob = await GetBlobReference(path);
using (var reader = new StreamReader(await blockBlob.OpenReadAsync(AccessCondition.GenerateEmptyCondition(), new BlobRequestOptions(), new OperationContext())))
var fileReference = await InternalGetAsync(file);
using (var reader = new StreamReader(await fileReference.CloudBlob.OpenReadAsync(AccessCondition.GenerateEmptyCondition(), new BlobRequestOptions(), new OperationContext())))
{
return await reader.ReadToEndAsync();
}
}

public async Task<string> Save(Stream data, string path, string mimeType)
public async Task<IFileReference> SaveAsync(Stream data, IPrivateFileReference file, string mimeType)
{
var blockBlob = this.container.Value.GetBlockBlobReference(path);
var blockBlob = this.container.Value.GetBlockBlobReference(file.Path);
await blockBlob.UploadFromStreamAsync(data);
blockBlob.Properties.ContentType = mimeType;
blockBlob.Properties.CacheControl = "max-age=300, must-revalidate";
await blockBlob.SetPropertiesAsync();
return blockBlob.Uri.ToString();
return new Internal.AzureFileReference(blockBlob);
}

public async Task<string> Save(byte[] data, string path, string mimeType)
public async Task<IFileReference> SaveAsync(byte[] data, IPrivateFileReference file, string mimeType)
{
var blockBlob = this.container.Value.GetBlockBlobReference(path);
var blockBlob = this.container.Value.GetBlockBlobReference(file.Path);
await blockBlob.UploadFromByteArrayAsync(data, 0, data.Length);
blockBlob.Properties.ContentType = mimeType;
blockBlob.Properties.CacheControl = "max-age=300, must-revalidate";
await blockBlob.SetPropertiesAsync();
return blockBlob.Uri.ToString();
return new Internal.AzureFileReference(blockBlob);
}

public async Task<string[]> List(string path)
//public async Task<IFileReference[]> ListAsync(string path)
//{
// if (string.IsNullOrEmpty(path) || path == "/" || path == "\\")
// {
// path = "";
// }

// BlobContinuationToken continuationToken = null;
// List<IListBlobItem> results = new List<IListBlobItem>();
// do
// {
// var response = await this.container.Value.ListBlobsSegmentedAsync(path, true, BlobListingDetails.None, null, continuationToken, new BlobRequestOptions(), new OperationContext());
// continuationToken = response.ContinuationToken;
// results.AddRange(response.Results);
// }
// while (continuationToken != null);

// return results.Select(blob => new Internal.AzureFileReference(blob)).ToArray();
//}

public async Task<IFileReference[]> ListAsync(string path, bool recursive)
{
if (path.EndsWith("*"))
if (string.IsNullOrWhiteSpace(path))
{
path = null;
}
else
{
path = path.TrimEnd('*');
if (!path.EndsWith("/"))
{
path = path + "/";
}
}

BlobContinuationToken continuationToken = null;
List<IListBlobItem> results = new List<IListBlobItem>();
do
{
var response = await this.container.Value.ListBlobsSegmentedAsync(path, continuationToken);
var response = await this.container.Value.ListBlobsSegmentedAsync(path, recursive, BlobListingDetails.None, null, continuationToken, new BlobRequestOptions(), new OperationContext());
continuationToken = response.ContinuationToken;
results.AddRange(response.Results);
}
while (continuationToken != null);

return results.Select(blob => blob.Uri.ToString()).ToArray();
return results.OfType<ICloudBlob>().Select(blob => new Internal.AzureFileReference(blob)).ToArray();
}

public async Task<IFileReference[]> ListAsync(string path, string searchPattern, bool recursive)
{
var firstWildCard = searchPattern.IndexOf('*');
if (firstWildCard >= 0)
{
path += searchPattern.Substring(0, firstWildCard);
searchPattern = searchPattern.Substring(firstWildCard);
}

Microsoft.Extensions.FileSystemGlobbing.Matcher matcher = new Microsoft.Extensions.FileSystemGlobbing.Matcher(StringComparison.Ordinal);
matcher.AddInclude(searchPattern);

var operationContext = new OperationContext();
BlobContinuationToken continuationToken = null;
List<IListBlobItem> results = new List<IListBlobItem>();
do
{
var response = await this.container.Value.ListBlobsSegmentedAsync(path, recursive, BlobListingDetails.None, null, continuationToken, new BlobRequestOptions(), new OperationContext());
continuationToken = response.ContinuationToken;
results.AddRange(response.Results);
}
while (continuationToken != null);

var pathMap = results.Select(blob => new Internal.AzureFileReference(blob)).ToDictionary(x => x.Path);
throw new NotSupportedException();
//var filteredResults = matcher.Execute(
// new Internal.AzureListDirectoryWrapper(path,
// pathMap.Values));

//return filteredResults.Files.Select(x => pathMap[x.Path]).ToArray();
}

public async Task Delete(string path)
public async Task DeleteAsync(IPrivateFileReference file)
{
var blockBlob = await GetBlobReference(path);
await blockBlob.DeleteAsync();
var fileReference = await InternalGetAsync(file);
await fileReference.DeleteAsync();
}
}
}
70 changes: 70 additions & 0 deletions src/GeekLearning.Storage.Azure/Internal/AzureFileReference.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using Microsoft.WindowsAzure.Storage.Blob;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace GeekLearning.Storage.Azure.Internal
{
public class AzureFileReference : IFileReference
{
private ICloudBlob cloudBlob;

public AzureFileReference(IListBlobItem blobItem)
: this(blobItem as ICloudBlob)
{
}

public AzureFileReference(string path, IListBlobItem blobItem)
: this(path, blobItem as ICloudBlob)
{
}

public AzureFileReference(string path, ICloudBlob cloudBlob)
{
this.Path = path;
this.cloudBlob = cloudBlob;
}

public AzureFileReference(ICloudBlob cloudBlob) :
this(cloudBlob.Name, cloudBlob)
{

}

public string Path { get; }

public string PublicUrl => cloudBlob.Uri.ToString();

public ICloudBlob CloudBlob => this.cloudBlob;

public Task DeleteAsync()
{
return this.cloudBlob.DeleteAsync();
}

public async Task<Stream> ReadAsync()
{
return await this.ReadInMemoryAsync();
}

public async Task<MemoryStream> ReadInMemoryAsync()
{
var memoryStream = new MemoryStream();
await this.CloudBlob.DownloadRangeToStreamAsync(memoryStream, null, null);
memoryStream.Seek(0, SeekOrigin.Begin);
return memoryStream;
}

public Task UpdateAsync(Stream stream)
{
return this.cloudBlob.UploadFromStreamAsync(stream);
}

public Task<string> GetExpirableUriAsync()
{
throw new NotImplementedException();
}
}
}
Loading