From f3901d772c590cb36720c37a183df0a2ec052fe4 Mon Sep 17 00:00:00 2001 From: Galo Date: Thu, 5 Jan 2017 18:27:42 +0100 Subject: [PATCH 01/12] Migration .NET Core 1.1 (#24) * Migration .NET Core 1.1 * Bump --- GeekLearning.Storage.sln | 14 +++---- global.json | 2 +- .../Controllers/SampleController.cs | 21 ++++------- .../Controllers/ValuesController.cs | 20 +++------- .../Program.cs | 14 +++---- .../Startup.cs | 25 +++++-------- .../TemplatesStore.cs | 7 +--- .../project.json | 28 +++++++------- .../web.config | 5 --- .../AzureStorageExtensions.cs | 1 - .../AzureStorageManagerOptions.cs | 2 +- .../AzureStorageProvider.cs | 8 +--- src/GeekLearning.Storage.Azure/AzureStore.cs | 5 ++- .../Internal/AzureFileReference.cs | 17 ++++----- .../Internal/AzureListDirectoryWrapper.cs | 36 +++++------------- .../Internal/AzureListFileWrapper.cs | 37 ++++--------------- .../Properties/AssemblyInfo.cs | 11 ++---- src/GeekLearning.Storage.Azure/project.json | 24 ++++++------ .../FileSystemStorageServerExtensions.cs | 6 +-- .../FileSystemStorageServerMiddleware.cs | 16 +++----- .../FileSystemStorageServerOptions.cs | 7 +--- .../Internal/PublicUrlProvider.cs | 7 +--- .../Properties/AssemblyInfo.cs | 9 +++-- .../project.json | 25 ++++++++----- .../FileSystemOptions.cs | 7 +--- .../FileSystemStorageProvider.cs | 13 ++----- .../FileSystemStore.cs | 9 +++-- .../IPublicUrlProvider.cs | 7 +--- .../Internal/FileSystemFileReference.cs | 20 +++++----- .../Properties/AssemblyInfo.cs | 9 +---- .../project.json | 26 ++++++------- src/GeekLearning.Storage/IFileReference.cs | 2 - src/GeekLearning.Storage/IStorageFactory.cs | 3 ++ .../IStorageStoreOptions.cs | 10 ++--- src/GeekLearning.Storage/IStoreExtensions.cs | 5 --- .../Internal/PrivateFileReference.cs | 1 + .../Internal/StorageFactory.cs | 5 ++- .../Properties/AssemblyInfo.cs | 9 +---- src/GeekLearning.Storage/StorageOptions.cs | 4 -- src/GeekLearning.Storage/project.json | 21 ++++------- .../IntegrationCollection.cs | 14 ------- .../DeleteTests.cs | 12 ++---- ...ekLearning.Storage.Integration.Test.xproj} | 2 +- .../IntegrationCollection.cs | 9 +++++ .../ListTests.cs | 10 ++--- .../Properties/AssemblyInfo.cs | 2 +- .../ReadTests.cs | 14 +++---- .../SampleDirectory/Delete/ToDelete.txt | 0 .../SampleDirectory/Delete/ToSurvive.txt | 0 .../Globbing/template-header.hbs | 0 .../Globbing/template-header.mustache | 0 .../SampleDirectory/Globbing/template.hbs | 0 .../Globbing/template.mustache | 0 .../SampleDirectory/Metadata/TextFile.txt | 0 .../SubDirectory/TextFile2.txt | 0 .../SampleDirectory/TextFile.txt | 0 .../SampleDirectory/template.hbs | 0 .../StoresFixture.cs | 35 ++++++------------ .../UpdateTests.cs | 13 +++---- .../appsettings.development.json | 19 ++++++++++ .../appsettings.json | 0 .../project.json | 32 ++++++++-------- 62 files changed, 260 insertions(+), 400 deletions(-) delete mode 100644 tests/GeekLearning.Integration.Test/IntegrationCollection.cs rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/DeleteTests.cs (81%) rename tests/{GeekLearning.Integration.Test/GeekLearning.Integration.Test.xproj => GeekLearning.Storage.Integration.Test/GeekLearning.Storage.Integration.Test.xproj} (94%) create mode 100644 tests/GeekLearning.Storage.Integration.Test/IntegrationCollection.cs rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/ListTests.cs (97%) rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/Properties/AssemblyInfo.cs (91%) rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/ReadTests.cs (96%) rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/SampleDirectory/Delete/ToDelete.txt (100%) rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/SampleDirectory/Delete/ToSurvive.txt (100%) rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/SampleDirectory/Globbing/template-header.hbs (100%) rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/SampleDirectory/Globbing/template-header.mustache (100%) rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/SampleDirectory/Globbing/template.hbs (100%) rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/SampleDirectory/Globbing/template.mustache (100%) rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/SampleDirectory/Metadata/TextFile.txt (100%) rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/SampleDirectory/SubDirectory/TextFile2.txt (100%) rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/SampleDirectory/TextFile.txt (100%) rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/SampleDirectory/template.hbs (100%) rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/StoresFixture.cs (86%) rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/UpdateTests.cs (96%) create mode 100644 tests/GeekLearning.Storage.Integration.Test/appsettings.development.json rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/appsettings.json (100%) rename tests/{GeekLearning.Integration.Test => GeekLearning.Storage.Integration.Test}/project.json (57%) diff --git a/GeekLearning.Storage.sln b/GeekLearning.Storage.sln index 90d4920..bc2f558 100644 --- a/GeekLearning.Storage.sln +++ b/GeekLearning.Storage.sln @@ -15,8 +15,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "GeekLearning.Storage.BasicS EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{2DAF5EF9-8F8E-4C51-BE2D-8D63CA143360}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "GeekLearning.Integration.Test", "tests\GeekLearning.Integration.Test\GeekLearning.Integration.Test.xproj", "{590B21B0-2AFA-4329-82AD-EF180C50EB5C}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "items", "items", "{6BEB33C6-FA17-4F58-ACC3-83C1EB28B604}" ProjectSection(SolutionItems) = preProject .gitattributes = .gitattributes @@ -31,6 +29,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "GeekLearning.Storage.FileSy EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{520AB1D3-C501-40FD-ACEB-7CC0D1F00B90}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "GeekLearning.Storage.Integration.Test", "tests\GeekLearning.Storage.Integration.Test\GeekLearning.Storage.Integration.Test.xproj", "{590B21B0-2AFA-4329-82AD-EF180C50EB5C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -53,14 +53,14 @@ Global {63416AEA-DA51-4D62-B566-DB7D9BC800DC}.Debug|Any CPU.Build.0 = Debug|Any CPU {63416AEA-DA51-4D62-B566-DB7D9BC800DC}.Release|Any CPU.ActiveCfg = Release|Any CPU {63416AEA-DA51-4D62-B566-DB7D9BC800DC}.Release|Any CPU.Build.0 = Release|Any CPU - {590B21B0-2AFA-4329-82AD-EF180C50EB5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {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 + {590B21B0-2AFA-4329-82AD-EF180C50EB5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -70,7 +70,7 @@ Global {FD8BB8F9-9AF5-4C12-B962-9E08C30B01E2} = {520AB1D3-C501-40FD-ACEB-7CC0D1F00B90} {4A12B042-76B3-471B-9235-F653E1ABE3C0} = {520AB1D3-C501-40FD-ACEB-7CC0D1F00B90} {63416AEA-DA51-4D62-B566-DB7D9BC800DC} = {FBAC4C17-D755-49A9-959D-18FD6B95B543} - {590B21B0-2AFA-4329-82AD-EF180C50EB5C} = {2DAF5EF9-8F8E-4C51-BE2D-8D63CA143360} {9D94CD6C-9451-449A-BED2-1C07D624A8E0} = {520AB1D3-C501-40FD-ACEB-7CC0D1F00B90} + {590B21B0-2AFA-4329-82AD-EF180C50EB5C} = {2DAF5EF9-8F8E-4C51-BE2D-8D63CA143360} EndGlobalSection EndGlobal diff --git a/global.json b/global.json index 53c35ad..65e97c5 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "projects": [ "src", "tests", "samples" ], "sdk": { - "version": "1.0.0-preview2-003133" + "version": "1.0.0-preview2-1-003177" } } \ No newline at end of file diff --git a/samples/GeekLearning.Storage.BasicSample/Controllers/SampleController.cs b/samples/GeekLearning.Storage.BasicSample/Controllers/SampleController.cs index 7606c62..433bb5a 100644 --- a/samples/GeekLearning.Storage.BasicSample/Controllers/SampleController.cs +++ b/samples/GeekLearning.Storage.BasicSample/Controllers/SampleController.cs @@ -1,14 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using System.Text; - -// For more information on enabling Web API for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860 - -namespace GeekLearning.Storage.BasicSample.Controllers +namespace GeekLearning.Storage.BasicSample.Controllers { + using Microsoft.AspNetCore.Mvc; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + [Route("api/[controller]")] public class SampleController : Controller { @@ -19,7 +16,6 @@ public SampleController(IStorageFactory storageFactory) this.sharedAssets = storageFactory.GetStore("SharedAssets"); } - // GET: api/values [HttpGet] public async Task> Get() { @@ -27,7 +23,6 @@ public async Task> Get() return summaries.Select(x => x.Path); } - // GET api/values/5 [HttpGet] public async Task Get(string path) { @@ -35,14 +30,12 @@ public async Task Get(string path) return await summary.ReadAllTextAsync(); } - // PUT api/values/5 [HttpPut()] public async Task Put(string path, [FromBody]string value) { await sharedAssets.SaveAsync(Encoding.UTF8.GetBytes(value), path, "text/plain"); } - // DELETE api/values/5 [HttpDelete()] public async Task Delete(string path) { diff --git a/samples/GeekLearning.Storage.BasicSample/Controllers/ValuesController.cs b/samples/GeekLearning.Storage.BasicSample/Controllers/ValuesController.cs index 8fcd503..affe249 100644 --- a/samples/GeekLearning.Storage.BasicSample/Controllers/ValuesController.cs +++ b/samples/GeekLearning.Storage.BasicSample/Controllers/ValuesController.cs @@ -1,15 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; - -namespace GeekLearning.Storage.BasicSample.Controllers +namespace GeekLearning.Storage.BasicSample.Controllers { + using Microsoft.AspNetCore.Mvc; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + [Route("api/[controller]")] public class ValuesController : Controller { - // GET api/values private TemplatesStore templates; public ValuesController(TemplatesStore templates) @@ -17,15 +15,12 @@ public ValuesController(TemplatesStore templates) this.templates = templates; } - // GET: api/values [HttpGet] public async Task> Get() { - return new string[] { await templates.Store.ReadAllTextAsync("json.json"), "value2" }; } - // GET api/values/5 [HttpGet("files")] public async Task> Get(int id) { @@ -33,19 +28,16 @@ public async Task> Get(int id) return files.Select(x => x.PublicUrl); } - // POST api/values [HttpPost] public void Post([FromBody]string value) { } - // PUT api/values/5 [HttpPut("{id}")] public void Put(int id, [FromBody]string value) { } - // DELETE api/values/5 [HttpDelete("{id}")] public void Delete(int id) { diff --git a/samples/GeekLearning.Storage.BasicSample/Program.cs b/samples/GeekLearning.Storage.BasicSample/Program.cs index 0efd76e..2610fdf 100644 --- a/samples/GeekLearning.Storage.BasicSample/Program.cs +++ b/samples/GeekLearning.Storage.BasicSample/Program.cs @@ -1,13 +1,9 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Builder; - -namespace GeekLearning.Storage.BasicSample +namespace GeekLearning.Storage.BasicSample { + using Microsoft.AspNetCore.Builder; + using Microsoft.AspNetCore.Hosting; + using System.IO; + public class Program { public static void Main(string[] args) diff --git a/samples/GeekLearning.Storage.BasicSample/Startup.cs b/samples/GeekLearning.Storage.BasicSample/Startup.cs index 6744d89..e9fb65d 100644 --- a/samples/GeekLearning.Storage.BasicSample/Startup.cs +++ b/samples/GeekLearning.Storage.BasicSample/Startup.cs @@ -1,16 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using System.Security.Cryptography; - -namespace GeekLearning.Storage.BasicSample +namespace GeekLearning.Storage.BasicSample { + using Microsoft.AspNetCore.Builder; + using Microsoft.AspNetCore.Hosting; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging; + using System; + using System.Security.Cryptography; + public class Startup { public Startup(IHostingEnvironment env) @@ -25,12 +22,11 @@ public Startup(IHostingEnvironment 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(); var rng = RandomNumberGenerator.Create(); @@ -50,7 +46,6 @@ public void ConfigureServices(IServiceCollection services) services.AddScoped(); } - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); diff --git a/samples/GeekLearning.Storage.BasicSample/TemplatesStore.cs b/samples/GeekLearning.Storage.BasicSample/TemplatesStore.cs index 13fd8d5..ee5765f 100644 --- a/samples/GeekLearning.Storage.BasicSample/TemplatesStore.cs +++ b/samples/GeekLearning.Storage.BasicSample/TemplatesStore.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace GeekLearning.Storage.BasicSample +namespace GeekLearning.Storage.BasicSample { public class TemplatesStore : StoreBase { diff --git a/samples/GeekLearning.Storage.BasicSample/project.json b/samples/GeekLearning.Storage.BasicSample/project.json index 8abd787..cb6d25b 100644 --- a/samples/GeekLearning.Storage.BasicSample/project.json +++ b/samples/GeekLearning.Storage.BasicSample/project.json @@ -1,20 +1,21 @@ { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.1", + "version": "1.1.0", "type": "platform" }, - "Microsoft.AspNetCore.Mvc": "1.0.1", - "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.1", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", - "Microsoft.Extensions.Configuration.Json": "1.0.0", - "Microsoft.Extensions.Logging": "1.0.0", - "Microsoft.Extensions.Logging.Console": "1.0.0", - "Microsoft.Extensions.Logging.Debug": "1.0.0", - "Microsoft.Extensions.Options": "1.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Microsoft.AspNetCore.Mvc": "1.1.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.1.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.1.0", + "Microsoft.Extensions.Configuration.Json": "1.1.0", + "Microsoft.Extensions.Logging": "1.1.0", + "Microsoft.Extensions.Logging.Console": "1.1.0", + "Microsoft.Extensions.Logging.Debug": "1.1.0", + "Microsoft.Extensions.Options": "1.1.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0", + "GeekLearning.Storage": "*", "GeekLearning.Storage.Azure": "*", "GeekLearning.Storage.FileSystem": "*", @@ -26,9 +27,8 @@ }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "imports": [ - "dotnet5.6", "portable-net45+win8" ] } diff --git a/samples/GeekLearning.Storage.BasicSample/web.config b/samples/GeekLearning.Storage.BasicSample/web.config index dc0514f..05ac0e3 100644 --- a/samples/GeekLearning.Storage.BasicSample/web.config +++ b/samples/GeekLearning.Storage.BasicSample/web.config @@ -1,10 +1,5 @@  - - - diff --git a/src/GeekLearning.Storage.Azure/AzureStorageExtensions.cs b/src/GeekLearning.Storage.Azure/AzureStorageExtensions.cs index 98ab8c9..45cae55 100644 --- a/src/GeekLearning.Storage.Azure/AzureStorageExtensions.cs +++ b/src/GeekLearning.Storage.Azure/AzureStorageExtensions.cs @@ -6,7 +6,6 @@ public static class AzureStorageExtensions { - public static IServiceCollection AddAzureStorage(this IServiceCollection services) { services.TryAddEnumerable(ServiceDescriptor.Transient()); diff --git a/src/GeekLearning.Storage.Azure/AzureStorageManagerOptions.cs b/src/GeekLearning.Storage.Azure/AzureStorageManagerOptions.cs index b79dae4..917a72d 100644 --- a/src/GeekLearning.Storage.Azure/AzureStorageManagerOptions.cs +++ b/src/GeekLearning.Storage.Azure/AzureStorageManagerOptions.cs @@ -4,7 +4,7 @@ public class AzureStorageManagerOptions { - public Dictionary SubStores { get; set; } + public Dictionary SubStores { get; set; } public class SubStore { diff --git a/src/GeekLearning.Storage.Azure/AzureStorageProvider.cs b/src/GeekLearning.Storage.Azure/AzureStorageProvider.cs index 93dfad5..b0086bc 100644 --- a/src/GeekLearning.Storage.Azure/AzureStorageProvider.cs +++ b/src/GeekLearning.Storage.Azure/AzureStorageProvider.cs @@ -4,13 +4,7 @@ public class AzureStorageProvider : IStorageProvider { - public string Name - { - get - { - return "Azure"; - } - } + public string Name => "Azure"; public IStore BuildStore(string storeName, IStorageStoreOptions storeOptions) { diff --git a/src/GeekLearning.Storage.Azure/AzureStore.cs b/src/GeekLearning.Storage.Azure/AzureStore.cs index e671587..f6f67a6 100644 --- a/src/GeekLearning.Storage.Azure/AzureStore.cs +++ b/src/GeekLearning.Storage.Azure/AzureStore.cs @@ -78,7 +78,6 @@ public async Task GetAsync(Uri uri, bool withMetadata) } } - public async Task ReadAsync(IPrivateFileReference file) { var fileReference = await InternalGetAsync(file, false); @@ -133,6 +132,7 @@ public async Task ListAsync(string path, bool recursive, bool BlobContinuationToken continuationToken = null; List results = new List(); + do { var response = await this.container.Value.ListBlobsSegmentedAsync(path, recursive, withMetadata ? BlobListingDetails.Metadata : BlobListingDetails.None, null, continuationToken, new BlobRequestOptions(), new OperationContext()); @@ -172,6 +172,7 @@ public async Task ListAsync(string path, string searchPattern, var operationContext = new OperationContext(); BlobContinuationToken continuationToken = null; List results = new List(); + do { var response = await this.container.Value.ListBlobsSegmentedAsync(prefix, recursive, withMetadata ? BlobListingDetails.Metadata : BlobListingDetails.None, null, continuationToken, new BlobRequestOptions(), new OperationContext()); @@ -199,7 +200,7 @@ public async Task AddMetadataAsync(IPrivateFileReference file, I { var fileReference = await InternalGetAsync(file, false); - fileReference.AddMetadataAsync(metadata); + await fileReference.AddMetadataAsync(metadata); return fileReference; } diff --git a/src/GeekLearning.Storage.Azure/Internal/AzureFileReference.cs b/src/GeekLearning.Storage.Azure/Internal/AzureFileReference.cs index 392ed3a..032e1b0 100644 --- a/src/GeekLearning.Storage.Azure/Internal/AzureFileReference.cs +++ b/src/GeekLearning.Storage.Azure/Internal/AzureFileReference.cs @@ -1,13 +1,12 @@ -using Microsoft.WindowsAzure.Storage; -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 +namespace GeekLearning.Storage.Azure.Internal { + using Microsoft.WindowsAzure.Storage; + using Microsoft.WindowsAzure.Storage.Blob; + using System; + using System.Collections.Generic; + using System.IO; + using System.Threading.Tasks; + public class AzureFileReference : IFileReference { private ICloudBlob cloudBlob; diff --git a/src/GeekLearning.Storage.Azure/Internal/AzureListDirectoryWrapper.cs b/src/GeekLearning.Storage.Azure/Internal/AzureListDirectoryWrapper.cs index 78da914..f33bf10 100644 --- a/src/GeekLearning.Storage.Azure/Internal/AzureListDirectoryWrapper.cs +++ b/src/GeekLearning.Storage.Azure/Internal/AzureListDirectoryWrapper.cs @@ -1,12 +1,11 @@ -using Microsoft.Extensions.FileSystemGlobbing.Abstractions; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.WindowsAzure.Storage.Blob; - -namespace GeekLearning.Storage.Azure.Internal +namespace GeekLearning.Storage.Azure.Internal { + using Microsoft.Extensions.FileSystemGlobbing.Abstractions; + using Microsoft.WindowsAzure.Storage.Blob; + using System; + using System.Collections.Generic; + using System.Linq; + public class AzureListDirectoryWrapper : DirectoryInfoBase { private string name; @@ -42,26 +41,11 @@ public AzureListDirectoryWrapper(CloudBlobDirectory blobDirectory, AzureListDire this.fullName = blobDirectory.Prefix; } - public override string FullName - { - get - { - return fullName; - } - } + public override string FullName => this.fullName; - public override string Name - { - get - { - return name; - } - } + public override string Name => this.name; - public override DirectoryInfoBase ParentDirectory - { - get; - } + public override DirectoryInfoBase ParentDirectory { get; } public override IEnumerable EnumerateFileSystemInfos() { diff --git a/src/GeekLearning.Storage.Azure/Internal/AzureListFileWrapper.cs b/src/GeekLearning.Storage.Azure/Internal/AzureListFileWrapper.cs index 8d459d0..c44c05f 100644 --- a/src/GeekLearning.Storage.Azure/Internal/AzureListFileWrapper.cs +++ b/src/GeekLearning.Storage.Azure/Internal/AzureListFileWrapper.cs @@ -1,12 +1,8 @@ -using Microsoft.Extensions.FileSystemGlobbing.Abstractions; -using Microsoft.WindowsAzure.Storage.Blob; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace GeekLearning.Storage.Azure.Internal +namespace GeekLearning.Storage.Azure.Internal { + using Microsoft.Extensions.FileSystemGlobbing.Abstractions; + using Microsoft.WindowsAzure.Storage.Blob; + public class AzureListFileWrapper : FileInfoBase { private ICloudBlob blob; @@ -25,31 +21,14 @@ public AzureListFileWrapper(ICloudBlob blob, AzureListDirectoryWrapper parent) { this.name = blob.Name; } + this.parent = parent; } - public override string FullName - { - get - { - return this.blob.Name; - } - } + public override string FullName => this.blob.Name; - public override string Name - { - get - { - return name; - } - } + public override string Name => this.name; - public override DirectoryInfoBase ParentDirectory - { - get - { - return this.parent; - } - } + public override DirectoryInfoBase ParentDirectory => this.parent; } } diff --git a/src/GeekLearning.Storage.Azure/Properties/AssemblyInfo.cs b/src/GeekLearning.Storage.Azure/Properties/AssemblyInfo.cs index 463d146..0b37cfb 100644 --- a/src/GeekLearning.Storage.Azure/Properties/AssemblyInfo.cs +++ b/src/GeekLearning.Storage.Azure/Properties/AssemblyInfo.cs @@ -1,16 +1,15 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("GeekLearning.Storage.Azure")] -[assembly: AssemblyDescription("Geek Learning Azure Storage Provider")] +[assembly: AssemblyDescription("Azure Storage Provider for Geek Learning Storage Abstractions.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Geek Learning")] -[assembly: AssemblyProduct("GeekLearning.Storage.Azure")] -[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyProduct("GeekLearning.Storage")] +[assembly: AssemblyCopyright("Copyright © Geek Learning 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -21,7 +20,3 @@ // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("fd8bb8f9-9af5-4c12-b962-9e08c30b01e2")] - -[assembly: AssemblyVersion("0.1.0.0")] -[assembly: AssemblyInformationalVersion("0.1.0+3.Branch.master.Sha.c1972a5901589d4f8d5670ad90b383609ee69408")] -[assembly: AssemblyFileVersion("0.1.0.0")] \ No newline at end of file diff --git a/src/GeekLearning.Storage.Azure/project.json b/src/GeekLearning.Storage.Azure/project.json index 5cf632c..9fc3c0a 100644 --- a/src/GeekLearning.Storage.Azure/project.json +++ b/src/GeekLearning.Storage.Azure/project.json @@ -1,25 +1,27 @@ { - "version": "1.0.0-*", - "description": "GeekLearning.Storage.Azure Class Library", + "version": "0.0.1-*", + "description": "Azure Storage Provider for Geek Learning Storage Abstractions.", "authors": [ "Geek Learning", "Cyprien Autexier", "Adrien Siffermann" ], "packOptions": { - "tags": [ ], + "tags": [], "projectUrl": "", "licenseUrl": "" }, "dependencies": { - "NETStandard.Library": "1.6.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "1.0.0", - "Microsoft.Extensions.Options": "1.0.0", - "WindowsAzure.Storage": "7.2.1", - "GeekLearning.Storage": "*", - "Microsoft.Extensions.FileSystemGlobbing": "1.0.0" + "NETStandard.Library": "1.6.1", + "Microsoft.Extensions.DependencyInjection.Abstractions": "1.1.0", + "Microsoft.Extensions.Options": "1.1.0", + "Microsoft.Extensions.FileSystemGlobbing": "1.1.0", + + "WindowsAzure.Storage": "8.0.0", + + "GeekLearning.Storage": "*" }, "frameworks": { - "net451": { }, - "netstandard1.5": { + "net45": {}, + "netstandard1.3": { "imports": [ "portable-net45+win8" ] diff --git a/src/GeekLearning.Storage.FileSystem.Server/FileSystemStorageServerExtensions.cs b/src/GeekLearning.Storage.FileSystem.Server/FileSystemStorageServerExtensions.cs index 8448176..338ef9f 100644 --- a/src/GeekLearning.Storage.FileSystem.Server/FileSystemStorageServerExtensions.cs +++ b/src/GeekLearning.Storage.FileSystem.Server/FileSystemStorageServerExtensions.cs @@ -1,15 +1,11 @@ namespace GeekLearning.Storage { using FileSystem; - using GeekLearning.Storage.FileSystem.Server; + using FileSystem.Server; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - public static class FileSystemStorageServerExtensions { diff --git a/src/GeekLearning.Storage.FileSystem.Server/FileSystemStorageServerMiddleware.cs b/src/GeekLearning.Storage.FileSystem.Server/FileSystemStorageServerMiddleware.cs index 089a7f5..862611f 100644 --- a/src/GeekLearning.Storage.FileSystem.Server/FileSystemStorageServerMiddleware.cs +++ b/src/GeekLearning.Storage.FileSystem.Server/FileSystemStorageServerMiddleware.cs @@ -1,14 +1,10 @@ - -namespace GeekLearning.Storage.FileSystem.Server +namespace GeekLearning.Storage.FileSystem.Server { - using Microsoft.Extensions.Options; - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; using Microsoft.AspNetCore.Http; - using Microsoft.Extensions.Logging; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging; + using Microsoft.Extensions.Options; + using System.Threading.Tasks; public class FileSystemStorageServerMiddleware { @@ -49,8 +45,7 @@ public async Task Invoke(HttpContext context) } IStore store = storageFactory.GetStore(storeName, storeOptions); - //if (storageFactory.TryGetStore(storeName, out store, "FileSystem")) - //{ + var file = await store.GetAsync(context.Request.Path.Value.Substring(subPathStart + 1)); if (file != null) { @@ -59,7 +54,6 @@ public async Task Invoke(HttpContext context) await file.ReadToStreamAsync(context.Response.Body); return; } - //} } } diff --git a/src/GeekLearning.Storage.FileSystem.Server/FileSystemStorageServerOptions.cs b/src/GeekLearning.Storage.FileSystem.Server/FileSystemStorageServerOptions.cs index a8fd629..9004d3d 100644 --- a/src/GeekLearning.Storage.FileSystem.Server/FileSystemStorageServerOptions.cs +++ b/src/GeekLearning.Storage.FileSystem.Server/FileSystemStorageServerOptions.cs @@ -1,12 +1,7 @@ - -namespace GeekLearning.Storage.FileSystem.Server +namespace GeekLearning.Storage.FileSystem.Server { using Microsoft.AspNetCore.Http; using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using Microsoft.IdentityModel.Tokens; public class FileSystemStorageServerOptions { diff --git a/src/GeekLearning.Storage.FileSystem.Server/Internal/PublicUrlProvider.cs b/src/GeekLearning.Storage.FileSystem.Server/Internal/PublicUrlProvider.cs index 5c87987..98ed307 100644 --- a/src/GeekLearning.Storage.FileSystem.Server/Internal/PublicUrlProvider.cs +++ b/src/GeekLearning.Storage.FileSystem.Server/Internal/PublicUrlProvider.cs @@ -1,11 +1,8 @@ namespace GeekLearning.Storage.FileSystem.Server.Internal { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using GeekLearning.Storage.FileSystem.Internal; + using FileSystem.Internal; using Microsoft.Extensions.Options; + using System; public class PublicUrlProvider : IPublicUrlProvider { diff --git a/src/GeekLearning.Storage.FileSystem.Server/Properties/AssemblyInfo.cs b/src/GeekLearning.Storage.FileSystem.Server/Properties/AssemblyInfo.cs index 7395edb..f86cb40 100644 --- a/src/GeekLearning.Storage.FileSystem.Server/Properties/AssemblyInfo.cs +++ b/src/GeekLearning.Storage.FileSystem.Server/Properties/AssemblyInfo.cs @@ -1,14 +1,17 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. +[assembly: AssemblyTitle("GeekLearning.Storage.FileSystem.Server")] +[assembly: AssemblyDescription("Geek Learning File Server based on FileSystem Storage Provider.")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("GeekLearning.Storage.FileSystem.Server")] +[assembly: AssemblyCompany("Geek Learning")] +[assembly: AssemblyProduct("GeekLearning.Storage")] +[assembly: AssemblyCopyright("Copyright © Geek Learning 2016")] [assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from diff --git a/src/GeekLearning.Storage.FileSystem.Server/project.json b/src/GeekLearning.Storage.FileSystem.Server/project.json index b036eee..a809676 100644 --- a/src/GeekLearning.Storage.FileSystem.Server/project.json +++ b/src/GeekLearning.Storage.FileSystem.Server/project.json @@ -1,17 +1,24 @@ { - "version": "1.0.0-*", + "version": "0.0.1-*", + "description": "Geek Learning File Server based on FileSystem Storage Provider.", + "authors": [ "Geek Learning", "Cyprien Autexier", "Adrien Siffermann" ], + "packOptions": { + "tags": [], + "projectUrl": "", + "licenseUrl": "" + }, "dependencies": { - "GeekLearning.Storage.FileSystem": "*", - "Microsoft.AspNetCore.Http.Abstractions": "1.0.0", - "Microsoft.Extensions.Logging.Abstractions": "1.0.0", - "Microsoft.IdentityModel.Tokens": "5.0.0", - "NETStandard.Library": "1.6.0" + "NETStandard.Library": "1.6.1", + "Microsoft.AspNetCore.Http.Abstractions": "1.1.0", + "Microsoft.Extensions.Logging.Abstractions": "1.1.0", + "Microsoft.IdentityModel.Tokens": "5.1.0", + + "GeekLearning.Storage.FileSystem": "*" }, "frameworks": { - "netstandard1.6": { - "imports": "dnxcore50" - } + "net451": {}, + "netstandard1.4": {} } } diff --git a/src/GeekLearning.Storage.FileSystem/FileSystemOptions.cs b/src/GeekLearning.Storage.FileSystem/FileSystemOptions.cs index e9d35bb..5476e6a 100644 --- a/src/GeekLearning.Storage.FileSystem/FileSystemOptions.cs +++ b/src/GeekLearning.Storage.FileSystem/FileSystemOptions.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace GeekLearning.Storage.FileSystem +namespace GeekLearning.Storage.FileSystem { public class FileSystemOptions { diff --git a/src/GeekLearning.Storage.FileSystem/FileSystemStorageProvider.cs b/src/GeekLearning.Storage.FileSystem/FileSystemStorageProvider.cs index f5370c6..f729d18 100644 --- a/src/GeekLearning.Storage.FileSystem/FileSystemStorageProvider.cs +++ b/src/GeekLearning.Storage.FileSystem/FileSystemStorageProvider.cs @@ -1,10 +1,9 @@ namespace GeekLearning.Storage.FileSystem { - using Storage; + using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; + using Storage; using System; - using Microsoft.Extensions.DependencyInjection.Extensions; - using Microsoft.Extensions.DependencyInjection; public class FileSystemStorageProvider : IStorageProvider { @@ -17,13 +16,7 @@ public FileSystemStorageProvider(IOptions options, IServicePr this.serviceProvider = serviceProvider; } - public string Name - { - get - { - return "FileSystem"; - } - } + public string Name => "FileSystem"; public IStore BuildStore(string storeName, IStorageStoreOptions storeOptions) { diff --git a/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs b/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs index b6c3397..d9d5047 100644 --- a/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs +++ b/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs @@ -30,6 +30,7 @@ public FileSystemStore(string storeName, string path, string rootPath, IPublicUr this.absolutePath = Path.Combine(rootPath, path); } } + public string Name { get; } private Internal.FileSystemFileReference InternalGetAsync(IPrivateFileReference file) @@ -39,6 +40,7 @@ private Internal.FileSystemFileReference InternalGetAsync(IPrivateFileReference { return reference; } + return null; } @@ -48,12 +50,13 @@ private Internal.FileSystemFileReference InternalGetOrCreateAsync(IPrivateFileRe return new Internal.FileSystemFileReference(fullPath, file.Path, this.Name, this.publicUrlProvider); } - public async Task GetAsync(IPrivateFileReference file, bool withMetadata) + public Task GetAsync(IPrivateFileReference file, bool withMetadata) { - return InternalGetAsync(file); + IFileReference fileReference = this.InternalGetAsync(file); + return Task.FromResult(fileReference); } - public async Task GetAsync(Uri uri, bool withMetadata) + public Task GetAsync(Uri uri, bool withMetadata) { throw new NotImplementedException(); } diff --git a/src/GeekLearning.Storage.FileSystem/IPublicUrlProvider.cs b/src/GeekLearning.Storage.FileSystem/IPublicUrlProvider.cs index 6b8f06b..7fb6e79 100644 --- a/src/GeekLearning.Storage.FileSystem/IPublicUrlProvider.cs +++ b/src/GeekLearning.Storage.FileSystem/IPublicUrlProvider.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace GeekLearning.Storage.FileSystem +namespace GeekLearning.Storage.FileSystem { public interface IPublicUrlProvider { diff --git a/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs b/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs index 2d917a0..a85a29a 100644 --- a/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs +++ b/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs @@ -1,11 +1,10 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; - -namespace GeekLearning.Storage.FileSystem.Internal +namespace GeekLearning.Storage.FileSystem.Internal { + using System; + using System.Collections.Generic; + using System.IO; + using System.Threading.Tasks; + public class FileSystemFileReference : IFileReference { private string filePath; @@ -60,7 +59,7 @@ public string ContentType } public long? Length => this.fileInfo.Length; - + public Task DeleteAsync() { File.Delete(this.filePath); @@ -82,9 +81,10 @@ public Task ReadAllTextAsync() return Task.FromResult(File.ReadAllText(this.FileSystemPath)); } - public async Task ReadAsync() + public Task ReadAsync() { - return File.OpenRead(this.filePath); + Stream stream = File.OpenRead(this.filePath); + return Task.FromResult(stream); } public async Task ReadToStreamAsync(Stream targetStream) diff --git a/src/GeekLearning.Storage.FileSystem/Properties/AssemblyInfo.cs b/src/GeekLearning.Storage.FileSystem/Properties/AssemblyInfo.cs index 2617307..4d9786a 100644 --- a/src/GeekLearning.Storage.FileSystem/Properties/AssemblyInfo.cs +++ b/src/GeekLearning.Storage.FileSystem/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following @@ -9,8 +8,8 @@ [assembly: AssemblyDescription("Geek Learning FileSystem Storage Provider")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Geek Learning")] -[assembly: AssemblyProduct("GeekLearning.Storage.FileSystem")] -[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyProduct("GeekLearning.Storage")] +[assembly: AssemblyCopyright("Copyright © Geek Learning 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -21,7 +20,3 @@ // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("4a12b042-76b3-471b-9235-f653e1abe3c0")] - -[assembly: AssemblyVersion("0.1.0.0")] -[assembly: AssemblyInformationalVersion("0.1.0+3.Branch.master.Sha.c1972a5901589d4f8d5670ad90b383609ee69408")] -[assembly: AssemblyFileVersion("0.1.0.0")] \ No newline at end of file diff --git a/src/GeekLearning.Storage.FileSystem/project.json b/src/GeekLearning.Storage.FileSystem/project.json index 502b82f..e708da4 100644 --- a/src/GeekLearning.Storage.FileSystem/project.json +++ b/src/GeekLearning.Storage.FileSystem/project.json @@ -1,28 +1,24 @@ { - "version": "1.0.0-*", - "description": "GeekLearning.Storage.FileSystem Class Library", + "version": "0.0.1-*", + "description": "FileSystem Provider for Geek Learning Storage Abstractions.", "authors": [ "Geek Learning", "Cyprien Autexier", "Adrien Siffermann" ], "packOptions": { - "tags": [ ], + "tags": [], "projectUrl": "", "licenseUrl": "" }, "dependencies": { - "NETStandard.Library": "1.6.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "1.0.0", - "Microsoft.Extensions.Options": "1.0.0", - "GeekLearning.Storage": "*", - "Microsoft.Extensions.FileSystemGlobbing": "1.0.0" + "NETStandard.Library": "1.6.1", + "Microsoft.Extensions.DependencyInjection.Abstractions": "1.1.0", + "Microsoft.Extensions.Options": "1.1.0", + "Microsoft.Extensions.FileSystemGlobbing": "1.1.0", + + "GeekLearning.Storage": "*" }, "frameworks": { - "net451": { }, - "netstandard1.5": { - "imports": [ - "dotnet5.6", - "portable-net45+win8" - ] - } + "net45": {}, + "netstandard1.3": {} } } diff --git a/src/GeekLearning.Storage/IFileReference.cs b/src/GeekLearning.Storage/IFileReference.cs index d6717f7..171899c 100644 --- a/src/GeekLearning.Storage/IFileReference.cs +++ b/src/GeekLearning.Storage/IFileReference.cs @@ -7,8 +7,6 @@ public interface IFileReference : IPrivateFileReference { - string Path { get; } - string PublicUrl { get; } DateTimeOffset? LastModified { get; } diff --git a/src/GeekLearning.Storage/IStorageFactory.cs b/src/GeekLearning.Storage/IStorageFactory.cs index 567a09c..4bf8398 100644 --- a/src/GeekLearning.Storage/IStorageFactory.cs +++ b/src/GeekLearning.Storage/IStorageFactory.cs @@ -3,8 +3,11 @@ public interface IStorageFactory { IStore GetStore(string storeName, IStorageStoreOptions configuration); + IStore GetStore(string storeName); + bool TryGetStore(string storeName, out IStore store); + bool TryGetStore(string storeName, out IStore store, string provider); } } diff --git a/src/GeekLearning.Storage/IStorageStoreOptions.cs b/src/GeekLearning.Storage/IStorageStoreOptions.cs index 369d275..4807f7b 100644 --- a/src/GeekLearning.Storage/IStorageStoreOptions.cs +++ b/src/GeekLearning.Storage/IStorageStoreOptions.cs @@ -1,13 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace GeekLearning.Storage +namespace GeekLearning.Storage { + using System.Collections.Generic; + public interface IStorageStoreOptions { string Provider { get; } + Dictionary Parameters { get; } } } diff --git a/src/GeekLearning.Storage/IStoreExtensions.cs b/src/GeekLearning.Storage/IStoreExtensions.cs index c30013c..36fa987 100644 --- a/src/GeekLearning.Storage/IStoreExtensions.cs +++ b/src/GeekLearning.Storage/IStoreExtensions.cs @@ -1,13 +1,8 @@ namespace GeekLearning.Storage { - using GeekLearning.Storage; - using System; - using System.Collections.Generic; using System.IO; - using System.Linq; using System.Threading.Tasks; - public static class IStoreExtensions { public static Task ListAsync(this IStore store, string path, bool recursive = false, bool withMetadata = false) diff --git a/src/GeekLearning.Storage/Internal/PrivateFileReference.cs b/src/GeekLearning.Storage/Internal/PrivateFileReference.cs index 7f8fd81..13b4579 100644 --- a/src/GeekLearning.Storage/Internal/PrivateFileReference.cs +++ b/src/GeekLearning.Storage/Internal/PrivateFileReference.cs @@ -6,6 +6,7 @@ public PrivateFileReference(string path) { this.Path = path.Replace("\\", "/").TrimStart('/'); } + public string Path { get; } } } diff --git a/src/GeekLearning.Storage/Internal/StorageFactory.cs b/src/GeekLearning.Storage/Internal/StorageFactory.cs index 7f1ceaa..609e566 100644 --- a/src/GeekLearning.Storage/Internal/StorageFactory.cs +++ b/src/GeekLearning.Storage/Internal/StorageFactory.cs @@ -3,7 +3,6 @@ using Microsoft.Extensions.Options; using System.Collections.Generic; using System.Linq; - using System; public class StorageFactory : IStorageFactory { @@ -32,9 +31,10 @@ public bool TryGetStore(string storeName, out IStore store) StorageOptions.StorageStoreOptions conf; if (this.options.Value.Stores.TryGetValue(storeName, out conf)) { - store= this.storageProviders.FirstOrDefault(x => x.Name == conf.Provider).BuildStore(storeName, conf); + store = this.storageProviders.FirstOrDefault(x => x.Name == conf.Provider).BuildStore(storeName, conf); return true; } + store = null; return false; } @@ -50,6 +50,7 @@ public bool TryGetStore(string storeName, out IStore store, string provider) return true; } } + store = null; return false; } diff --git a/src/GeekLearning.Storage/Properties/AssemblyInfo.cs b/src/GeekLearning.Storage/Properties/AssemblyInfo.cs index 119ff8b..82a6b4c 100644 --- a/src/GeekLearning.Storage/Properties/AssemblyInfo.cs +++ b/src/GeekLearning.Storage/Properties/AssemblyInfo.cs @@ -1,16 +1,15 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("GeekLearning.Storage")] -[assembly: AssemblyDescription("Geek Learning Storage abstraction")] +[assembly: AssemblyDescription("File Storage abstractions with providers.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Geek Learning")] [assembly: AssemblyProduct("GeekLearning.Storage")] -[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyCopyright("Copyright © Geek Learning 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -21,7 +20,3 @@ // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("1f419c53-73c6-4460-b284-6a49ae41c596")] - -[assembly: AssemblyVersion("0.1.0.0")] -[assembly: AssemblyInformationalVersion("0.1.0+3.Branch.master.Sha.c1972a5901589d4f8d5670ad90b383609ee69408")] -[assembly: AssemblyFileVersion("0.1.0.0")] \ No newline at end of file diff --git a/src/GeekLearning.Storage/StorageOptions.cs b/src/GeekLearning.Storage/StorageOptions.cs index 6902fec..f26e4cf 100644 --- a/src/GeekLearning.Storage/StorageOptions.cs +++ b/src/GeekLearning.Storage/StorageOptions.cs @@ -4,10 +4,6 @@ public class StorageOptions { - public StorageOptions() - { - } - public Dictionary Stores { get; set; } public class StorageStoreOptions : IStorageStoreOptions diff --git a/src/GeekLearning.Storage/project.json b/src/GeekLearning.Storage/project.json index 18e05d6..e8a24b8 100644 --- a/src/GeekLearning.Storage/project.json +++ b/src/GeekLearning.Storage/project.json @@ -1,27 +1,20 @@ { - "version": "1.0.0-*", - "description": "GeekLearning.Storage Class Library", + "version": "0.0.1-*", + "description": "File Storage abstractions with providers.", "authors": [ "Geek Learning", "Cyprien Autexier", "Adrien Siffermann" ], "packOptions": { - "tags": [ ], + "tags": [], "projectUrl": "", "licenseUrl": "" }, "dependencies": { - "NETStandard.Library": "1.6.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "1.0.0", - "Microsoft.Extensions.Options": "1.0.0" + "NETStandard.Library": "1.6.1", + "Microsoft.Extensions.DependencyInjection.Abstractions": "1.1.0", + "Microsoft.Extensions.Options": "1.1.0" }, "frameworks": { - "net451": { }, - "netstandard1.5": { - "imports": [ - "dotnet5.6", - "dnxcore50", - "portable-net45+win8" - ] - } + "netstandard1.1": {} } } diff --git a/tests/GeekLearning.Integration.Test/IntegrationCollection.cs b/tests/GeekLearning.Integration.Test/IntegrationCollection.cs deleted file mode 100644 index 010fea9..0000000 --- a/tests/GeekLearning.Integration.Test/IntegrationCollection.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Xunit; - -namespace GeekLearning.Integration.Test -{ - [CollectionDefinition(nameof(IntegrationCollection))] - public class IntegrationCollection: ICollectionFixture - { - - } -} diff --git a/tests/GeekLearning.Integration.Test/DeleteTests.cs b/tests/GeekLearning.Storage.Integration.Test/DeleteTests.cs similarity index 81% rename from tests/GeekLearning.Integration.Test/DeleteTests.cs rename to tests/GeekLearning.Storage.Integration.Test/DeleteTests.cs index 019f433..2ddf857 100644 --- a/tests/GeekLearning.Integration.Test/DeleteTests.cs +++ b/tests/GeekLearning.Storage.Integration.Test/DeleteTests.cs @@ -1,19 +1,15 @@ -namespace GeekLearning.Integration.Test +namespace GeekLearning.Storage.Integration.Test { - using System; - using System.Collections.Generic; - using System.Linq; + using Microsoft.Extensions.DependencyInjection; + using Storage; using System.Threading.Tasks; using Xunit; - using GeekLearning.Storage; - using Microsoft.Extensions.DependencyInjection; - using System.IO; [Collection(nameof(IntegrationCollection))] [Trait("Operation", "Delete"), Trait("Kind", "Integration")] public class DeleteTests { - StoresFixture storeFixture; + private StoresFixture storeFixture; public DeleteTests(StoresFixture fixture) { diff --git a/tests/GeekLearning.Integration.Test/GeekLearning.Integration.Test.xproj b/tests/GeekLearning.Storage.Integration.Test/GeekLearning.Storage.Integration.Test.xproj similarity index 94% rename from tests/GeekLearning.Integration.Test/GeekLearning.Integration.Test.xproj rename to tests/GeekLearning.Storage.Integration.Test/GeekLearning.Storage.Integration.Test.xproj index f22f170..bb63879 100644 --- a/tests/GeekLearning.Integration.Test/GeekLearning.Integration.Test.xproj +++ b/tests/GeekLearning.Storage.Integration.Test/GeekLearning.Storage.Integration.Test.xproj @@ -7,7 +7,7 @@ 590b21b0-2afa-4329-82ad-ef180c50eb5c - GeekLearning.Integration.Test + GeekLearning.Storage.Integration.Test .\obj .\bin\ v4.5.2 diff --git a/tests/GeekLearning.Storage.Integration.Test/IntegrationCollection.cs b/tests/GeekLearning.Storage.Integration.Test/IntegrationCollection.cs new file mode 100644 index 0000000..9f9ab8e --- /dev/null +++ b/tests/GeekLearning.Storage.Integration.Test/IntegrationCollection.cs @@ -0,0 +1,9 @@ +namespace GeekLearning.Storage.Integration.Test +{ + using Xunit; + + [CollectionDefinition(nameof(IntegrationCollection))] + public class IntegrationCollection: ICollectionFixture + { + } +} diff --git a/tests/GeekLearning.Integration.Test/ListTests.cs b/tests/GeekLearning.Storage.Integration.Test/ListTests.cs similarity index 97% rename from tests/GeekLearning.Integration.Test/ListTests.cs rename to tests/GeekLearning.Storage.Integration.Test/ListTests.cs index 3180432..1c1c0d1 100644 --- a/tests/GeekLearning.Integration.Test/ListTests.cs +++ b/tests/GeekLearning.Storage.Integration.Test/ListTests.cs @@ -1,18 +1,16 @@ -namespace GeekLearning.Integration.Test +namespace GeekLearning.Storage.Integration.Test { - using System; - using System.Collections.Generic; + using Microsoft.Extensions.DependencyInjection; + using Storage; using System.Linq; using System.Threading.Tasks; using Xunit; - using GeekLearning.Storage; - using Microsoft.Extensions.DependencyInjection; [Collection(nameof(IntegrationCollection))] [Trait("Operation", "List"), Trait("Kind", "Integration")] public class ListTests { - StoresFixture storeFixture; + private StoresFixture storeFixture; public ListTests(StoresFixture fixture) { diff --git a/tests/GeekLearning.Integration.Test/Properties/AssemblyInfo.cs b/tests/GeekLearning.Storage.Integration.Test/Properties/AssemblyInfo.cs similarity index 91% rename from tests/GeekLearning.Integration.Test/Properties/AssemblyInfo.cs rename to tests/GeekLearning.Storage.Integration.Test/Properties/AssemblyInfo.cs index 6b0e4f0..07776c7 100644 --- a/tests/GeekLearning.Integration.Test/Properties/AssemblyInfo.cs +++ b/tests/GeekLearning.Storage.Integration.Test/Properties/AssemblyInfo.cs @@ -7,7 +7,7 @@ // associated with an assembly. [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("GeekLearning.Integration.Test")] +[assembly: AssemblyProduct("GeekLearning.Storage.Integration.Test")] [assembly: AssemblyTrademark("")] // Setting ComVisible to false makes the types in this assembly not visible diff --git a/tests/GeekLearning.Integration.Test/ReadTests.cs b/tests/GeekLearning.Storage.Integration.Test/ReadTests.cs similarity index 96% rename from tests/GeekLearning.Integration.Test/ReadTests.cs rename to tests/GeekLearning.Storage.Integration.Test/ReadTests.cs index 5f8df1f..9b45aa0 100644 --- a/tests/GeekLearning.Integration.Test/ReadTests.cs +++ b/tests/GeekLearning.Storage.Integration.Test/ReadTests.cs @@ -1,19 +1,16 @@ -namespace GeekLearning.Integration.Test +namespace GeekLearning.Storage.Integration.Test { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using Xunit; - using GeekLearning.Storage; using Microsoft.Extensions.DependencyInjection; + using Storage; using System.IO; + using System.Threading.Tasks; + using Xunit; [Collection(nameof(IntegrationCollection))] [Trait("Operation", "Read"), Trait("Kind", "Integration")] public class ReadTests { - StoresFixture storeFixture; + private StoresFixture storeFixture; public ReadTests(StoresFixture fixture) { @@ -64,7 +61,6 @@ public async Task ReadAllBytesFromSubdirectoryFile(string storeName) } } - [Theory(DisplayName = nameof(ReadAllBytesFromSubdirectoryFileUsingFileReference)), InlineData("azure"), InlineData("filesystem")] public async Task ReadAllBytesFromSubdirectoryFileUsingFileReference(string storeName) { diff --git a/tests/GeekLearning.Integration.Test/SampleDirectory/Delete/ToDelete.txt b/tests/GeekLearning.Storage.Integration.Test/SampleDirectory/Delete/ToDelete.txt similarity index 100% rename from tests/GeekLearning.Integration.Test/SampleDirectory/Delete/ToDelete.txt rename to tests/GeekLearning.Storage.Integration.Test/SampleDirectory/Delete/ToDelete.txt diff --git a/tests/GeekLearning.Integration.Test/SampleDirectory/Delete/ToSurvive.txt b/tests/GeekLearning.Storage.Integration.Test/SampleDirectory/Delete/ToSurvive.txt similarity index 100% rename from tests/GeekLearning.Integration.Test/SampleDirectory/Delete/ToSurvive.txt rename to tests/GeekLearning.Storage.Integration.Test/SampleDirectory/Delete/ToSurvive.txt diff --git a/tests/GeekLearning.Integration.Test/SampleDirectory/Globbing/template-header.hbs b/tests/GeekLearning.Storage.Integration.Test/SampleDirectory/Globbing/template-header.hbs similarity index 100% rename from tests/GeekLearning.Integration.Test/SampleDirectory/Globbing/template-header.hbs rename to tests/GeekLearning.Storage.Integration.Test/SampleDirectory/Globbing/template-header.hbs diff --git a/tests/GeekLearning.Integration.Test/SampleDirectory/Globbing/template-header.mustache b/tests/GeekLearning.Storage.Integration.Test/SampleDirectory/Globbing/template-header.mustache similarity index 100% rename from tests/GeekLearning.Integration.Test/SampleDirectory/Globbing/template-header.mustache rename to tests/GeekLearning.Storage.Integration.Test/SampleDirectory/Globbing/template-header.mustache diff --git a/tests/GeekLearning.Integration.Test/SampleDirectory/Globbing/template.hbs b/tests/GeekLearning.Storage.Integration.Test/SampleDirectory/Globbing/template.hbs similarity index 100% rename from tests/GeekLearning.Integration.Test/SampleDirectory/Globbing/template.hbs rename to tests/GeekLearning.Storage.Integration.Test/SampleDirectory/Globbing/template.hbs diff --git a/tests/GeekLearning.Integration.Test/SampleDirectory/Globbing/template.mustache b/tests/GeekLearning.Storage.Integration.Test/SampleDirectory/Globbing/template.mustache similarity index 100% rename from tests/GeekLearning.Integration.Test/SampleDirectory/Globbing/template.mustache rename to tests/GeekLearning.Storage.Integration.Test/SampleDirectory/Globbing/template.mustache diff --git a/tests/GeekLearning.Integration.Test/SampleDirectory/Metadata/TextFile.txt b/tests/GeekLearning.Storage.Integration.Test/SampleDirectory/Metadata/TextFile.txt similarity index 100% rename from tests/GeekLearning.Integration.Test/SampleDirectory/Metadata/TextFile.txt rename to tests/GeekLearning.Storage.Integration.Test/SampleDirectory/Metadata/TextFile.txt diff --git a/tests/GeekLearning.Integration.Test/SampleDirectory/SubDirectory/TextFile2.txt b/tests/GeekLearning.Storage.Integration.Test/SampleDirectory/SubDirectory/TextFile2.txt similarity index 100% rename from tests/GeekLearning.Integration.Test/SampleDirectory/SubDirectory/TextFile2.txt rename to tests/GeekLearning.Storage.Integration.Test/SampleDirectory/SubDirectory/TextFile2.txt diff --git a/tests/GeekLearning.Integration.Test/SampleDirectory/TextFile.txt b/tests/GeekLearning.Storage.Integration.Test/SampleDirectory/TextFile.txt similarity index 100% rename from tests/GeekLearning.Integration.Test/SampleDirectory/TextFile.txt rename to tests/GeekLearning.Storage.Integration.Test/SampleDirectory/TextFile.txt diff --git a/tests/GeekLearning.Integration.Test/SampleDirectory/template.hbs b/tests/GeekLearning.Storage.Integration.Test/SampleDirectory/template.hbs similarity index 100% rename from tests/GeekLearning.Integration.Test/SampleDirectory/template.hbs rename to tests/GeekLearning.Storage.Integration.Test/SampleDirectory/template.hbs diff --git a/tests/GeekLearning.Integration.Test/StoresFixture.cs b/tests/GeekLearning.Storage.Integration.Test/StoresFixture.cs similarity index 86% rename from tests/GeekLearning.Integration.Test/StoresFixture.cs rename to tests/GeekLearning.Storage.Integration.Test/StoresFixture.cs index 1f21a5e..d89422f 100644 --- a/tests/GeekLearning.Integration.Test/StoresFixture.cs +++ b/tests/GeekLearning.Storage.Integration.Test/StoresFixture.cs @@ -1,17 +1,14 @@ -namespace GeekLearning.Integration.Test +namespace GeekLearning.Storage.Integration.Test { + using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.PlatformAbstractions; + using Microsoft.WindowsAzure.Storage; + using Microsoft.WindowsAzure.Storage.Blob; using Storage; using System; using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using Xunit; - using Microsoft.Extensions.PlatformAbstractions; - using Microsoft.Extensions.Configuration; using System.Diagnostics; - using Microsoft.WindowsAzure.Storage; - using Microsoft.WindowsAzure.Storage.Blob; public class StoresFixture : IDisposable { @@ -25,8 +22,8 @@ public StoresFixture() var builder = new ConfigurationBuilder() .SetBasePath(BasePath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) - .AddJsonFile($"appsettings.development.json", optional: true). - AddInMemoryCollection(new KeyValuePair[] { + .AddJsonFile($"appsettings.development.json", optional: true) + .AddInMemoryCollection(new KeyValuePair[] { new KeyValuePair("Storage:Stores:azure:Parameters:Container", Guid.NewGuid().ToString("N").ToLower()) }); @@ -45,7 +42,6 @@ public StoresFixture() this.Services = services.BuildServiceProvider(); ResetStores(); - } private void ResetStores() @@ -62,11 +58,7 @@ private void ResetFileSystemStore() Arguments = $"\"{System.IO.Path.Combine(BasePath, "SampleDirectory")}\" \"{System.IO.Path.Combine(BasePath, directoryName)}\" /MIR" }); - if (process.WaitForExit(30000)) - { - - } - else + if (!process.WaitForExit(30000)) { throw new TimeoutException("File system store was not reset properly"); } @@ -78,8 +70,7 @@ private void ResetAzureStore() Environment.ExpandEnvironmentVariables(Configuration["AzCopyPath"]), "AzCopy.exe"); - - cloudStorageAccount = Microsoft.WindowsAzure.Storage.CloudStorageAccount.Parse(Configuration["Storage:Stores:azure:Parameters:ConnectionString"]); + cloudStorageAccount = CloudStorageAccount.Parse(Configuration["Storage:Stores:azure:Parameters:ConnectionString"]); var key = cloudStorageAccount.Credentials.ExportBase64EncodedKey(); var containerName = Configuration["Storage:Stores:azure:Parameters:Container"]; var dest = cloudStorageAccount.BlobStorageUri.PrimaryUri.ToString() + containerName; @@ -94,18 +85,16 @@ private void ResetAzureStore() Arguments = $"/Source:\"{System.IO.Path.Combine(BasePath, "SampleDirectory")}\" /Dest:\"{dest}\" /DestKey:{key} /S" }); - if (process.WaitForExit(30000)) - { - - } - else + if (!process.WaitForExit(30000)) { throw new TimeoutException("Azure store was not reset properly"); } } public IConfigurationRoot Configuration { get; } + public IServiceProvider Services { get; } + public string BasePath { get; } public void Dispose() diff --git a/tests/GeekLearning.Integration.Test/UpdateTests.cs b/tests/GeekLearning.Storage.Integration.Test/UpdateTests.cs similarity index 96% rename from tests/GeekLearning.Integration.Test/UpdateTests.cs rename to tests/GeekLearning.Storage.Integration.Test/UpdateTests.cs index ac341d7..31176df 100644 --- a/tests/GeekLearning.Integration.Test/UpdateTests.cs +++ b/tests/GeekLearning.Storage.Integration.Test/UpdateTests.cs @@ -1,20 +1,19 @@ -namespace GeekLearning.Integration.Test +namespace GeekLearning.Storage.Integration.Test { + using Storage; + using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using Xunit; - using GeekLearning.Storage; - using Microsoft.Extensions.DependencyInjection; using System.IO; using System.Text; + using System.Threading.Tasks; + using Xunit; [Collection(nameof(IntegrationCollection))] [Trait("Operation", "Update"), Trait("Kind", "Integration")] public class UpdateTests { - StoresFixture storeFixture; + private StoresFixture storeFixture; public UpdateTests(StoresFixture fixture) { diff --git a/tests/GeekLearning.Storage.Integration.Test/appsettings.development.json b/tests/GeekLearning.Storage.Integration.Test/appsettings.development.json new file mode 100644 index 0000000..739585f --- /dev/null +++ b/tests/GeekLearning.Storage.Integration.Test/appsettings.development.json @@ -0,0 +1,19 @@ +{ + "Storage": { + "Stores": { + "filesystem": { + "Provider": "FileSystem", + "Parameters": { + "Path": "Templates" + } + }, + "azure": { + "Provider": "Azure", + "Parameters": { + "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=glstoragetests;AccountKey=91+UllcfvxK/ghaN3tFUD6/QJZ7t/A4hL0vN9ha587syUxcD3SzCmYuAybBcwbwx77NjV+4/1WXqFTlwwxdA5Q==;", + "Container": "templates" + } + } + } + } +} \ No newline at end of file diff --git a/tests/GeekLearning.Integration.Test/appsettings.json b/tests/GeekLearning.Storage.Integration.Test/appsettings.json similarity index 100% rename from tests/GeekLearning.Integration.Test/appsettings.json rename to tests/GeekLearning.Storage.Integration.Test/appsettings.json diff --git a/tests/GeekLearning.Integration.Test/project.json b/tests/GeekLearning.Storage.Integration.Test/project.json similarity index 57% rename from tests/GeekLearning.Integration.Test/project.json rename to tests/GeekLearning.Storage.Integration.Test/project.json index 7f1f9dc..5f6f1f5 100644 --- a/tests/GeekLearning.Integration.Test/project.json +++ b/tests/GeekLearning.Storage.Integration.Test/project.json @@ -1,5 +1,6 @@ { "version": "1.0.0-*", + "buildOptions": { "copyToOutput": [ "SampleDirectory/**/*.*", @@ -11,21 +12,22 @@ "testRunner": "xunit", "dependencies": { - "GeekLearning.Storage": "*", - "GeekLearning.Storage.Azure": "*", - "GeekLearning.Storage.FileSystem": "*", - "Microsoft.NETCore.Platforms": "1.0.1", + "Microsoft.NETCore.Platforms": "1.1.0", "dotnet-test-xunit": "2.2.0-preview2-build1029", "xunit": "2.2.0-beta2-build3300", "xunit.runner.visualstudio": "2.2.0-beta2-build1149", - "Microsoft.Extensions.DependencyInjection": "1.0.0", - "Microsoft.Extensions.PlatformAbstractions": "1.0.0", - "Microsoft.Extensions.Configuration": "1.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", - "Microsoft.Extensions.Configuration.Json": "1.0.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", - "Microsoft.Extensions.Options": "1.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0" + "Microsoft.Extensions.DependencyInjection": "1.1.0", + "Microsoft.Extensions.PlatformAbstractions": "1.1.0", + "Microsoft.Extensions.Configuration": "1.1.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.1.0", + "Microsoft.Extensions.Configuration.Json": "1.1.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0", + "Microsoft.Extensions.Options": "1.1.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0", + + "GeekLearning.Storage": "*", + "GeekLearning.Storage.Azure": "*", + "GeekLearning.Storage.FileSystem": "*" }, "frameworks": { @@ -39,10 +41,8 @@ } }, "net451": { - "frameworkAssemblies": { - }, - "dependencies": { - } + "frameworkAssemblies": {}, + "dependencies": {} } } } From da17fce8d7a47a0c5acccdb611955705d6b8d27a Mon Sep 17 00:00:00 2001 From: Adrien Siffermann Date: Fri, 6 Jan 2017 16:14:25 +0100 Subject: [PATCH 02/12] Fix #19 --- .../Internal/AzureFileReference.cs | 17 +++++---- .../FileSystemStore.cs | 38 +++++++++---------- .../Internal/FileSystemFileReference.cs | 27 +++++++------ src/GeekLearning.Storage/IFileReference.cs | 2 + 4 files changed, 46 insertions(+), 38 deletions(-) diff --git a/src/GeekLearning.Storage.Azure/Internal/AzureFileReference.cs b/src/GeekLearning.Storage.Azure/Internal/AzureFileReference.cs index 032e1b0..92e7a5d 100644 --- a/src/GeekLearning.Storage.Azure/Internal/AzureFileReference.cs +++ b/src/GeekLearning.Storage.Azure/Internal/AzureFileReference.cs @@ -11,6 +11,12 @@ public class AzureFileReference : IFileReference { private ICloudBlob cloudBlob; + public AzureFileReference(string path, ICloudBlob cloudBlob) + { + this.Path = path; + this.cloudBlob = cloudBlob; + } + public AzureFileReference(IListBlobItem blobItem) : this(blobItem as ICloudBlob) { @@ -21,25 +27,20 @@ public AzureFileReference(string path, IListBlobItem blobItem) { } - 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 DateTimeOffset? LastModified => this.cloudBlob.Properties?.LastModified; public string ContentType => this.cloudBlob.Properties?.ContentType; public long? Length => this.cloudBlob.Properties?.Length; - public string Path { get; } + public string ETag => this.cloudBlob.Properties?.ETag; public string PublicUrl => cloudBlob.Uri.ToString(); diff --git a/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs b/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs index d9d5047..b67f0dd 100644 --- a/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs +++ b/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs @@ -33,23 +33,6 @@ public FileSystemStore(string storeName, string path, string rootPath, IPublicUr public string Name { get; } - private Internal.FileSystemFileReference InternalGetAsync(IPrivateFileReference file) - { - var reference = InternalGetOrCreateAsync(file); - if (File.Exists(reference.FileSystemPath)) - { - return reference; - } - - return null; - } - - private Internal.FileSystemFileReference InternalGetOrCreateAsync(IPrivateFileReference file) - { - var fullPath = Path.Combine(this.absolutePath, file.Path); - return new Internal.FileSystemFileReference(fullPath, file.Path, this.Name, this.publicUrlProvider); - } - public Task GetAsync(IPrivateFileReference file, bool withMetadata) { IFileReference fileReference = this.InternalGetAsync(file); @@ -138,6 +121,11 @@ public Task SaveAsync(byte[] data, IPrivateFileReference file, s return Task.FromResult((IFileReference)fileReference); } + public Task AddMetadataAsync(IPrivateFileReference file, IDictionary metadata) + { + throw new NotImplementedException(); + } + private void EnsurePathExists(string path) { var directoryPath = Path.GetDirectoryName(path); @@ -147,9 +135,21 @@ private void EnsurePathExists(string path) } } - public Task AddMetadataAsync(IPrivateFileReference file, IDictionary metadata) + private Internal.FileSystemFileReference InternalGetAsync(IPrivateFileReference file) { - throw new NotImplementedException(); + var reference = InternalGetOrCreateAsync(file); + if (File.Exists(reference.FileSystemPath)) + { + return reference; + } + + return null; + } + + private Internal.FileSystemFileReference InternalGetOrCreateAsync(IPrivateFileReference file) + { + var fullPath = Path.Combine(this.absolutePath, file.Path); + return new Internal.FileSystemFileReference(fullPath, file.Path, this.Name, this.publicUrlProvider); } } } diff --git a/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs b/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs index a85a29a..5712330 100644 --- a/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs +++ b/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs @@ -7,8 +7,6 @@ public class FileSystemFileReference : IFileReference { - private string filePath; - private string path; private IPublicUrlProvider publicUrlProvider; private string storeName; private FileInfo fileInfo; @@ -17,12 +15,14 @@ public FileSystemFileReference(string filePath, string path, string storeName, I { this.storeName = storeName; this.publicUrlProvider = publicUrlProvider; - this.filePath = filePath; - this.path = path.Replace('\\', '/'); + this.FileSystemPath = filePath; + this.Path = path.Replace('\\', '/'); this.fileInfo = new FileInfo(this.FileSystemPath); } - public string FileSystemPath => this.filePath; + public string FileSystemPath { get; } + + public string Path { get; } public IDictionary Metadata { @@ -32,8 +32,13 @@ public IDictionary Metadata } } - public string Path => this.path; - + public string ETag + { + get + { + throw new NotImplementedException(); + } + } public string PublicUrl { @@ -62,7 +67,7 @@ public string ContentType public Task DeleteAsync() { - File.Delete(this.filePath); + File.Delete(this.FileSystemPath); return Task.FromResult(true); } @@ -83,13 +88,13 @@ public Task ReadAllTextAsync() public Task ReadAsync() { - Stream stream = File.OpenRead(this.filePath); + Stream stream = File.OpenRead(this.FileSystemPath); return Task.FromResult(stream); } public async Task ReadToStreamAsync(Stream targetStream) { - using (var file = File.Open(this.filePath, FileMode.Open, FileAccess.Read)) + using (var file = File.Open(this.FileSystemPath, FileMode.Open, FileAccess.Read)) { await file.CopyToAsync(targetStream); } @@ -97,7 +102,7 @@ public async Task ReadToStreamAsync(Stream targetStream) public async Task UpdateAsync(Stream stream) { - using (var file = File.Open(this.filePath, FileMode.Truncate, FileAccess.Write)) + using (var file = File.Open(this.FileSystemPath, FileMode.Truncate, FileAccess.Write)) { await stream.CopyToAsync(file); } diff --git a/src/GeekLearning.Storage/IFileReference.cs b/src/GeekLearning.Storage/IFileReference.cs index 171899c..2448f8a 100644 --- a/src/GeekLearning.Storage/IFileReference.cs +++ b/src/GeekLearning.Storage/IFileReference.cs @@ -15,6 +15,8 @@ public interface IFileReference : IPrivateFileReference long? Length { get; } + string ETag { get; } + IDictionary Metadata { get; } Task ReadToStreamAsync(Stream targetStream); From 47f7aab50e423dd972f0f796649af711e8aaa117 Mon Sep 17 00:00:00 2001 From: Adrien Siffermann Date: Mon, 9 Jan 2017 15:29:14 +0100 Subject: [PATCH 03/12] Create IFileProperties and real optionnal load of properties and metadata --- src/GeekLearning.Storage.Azure/AzureStore.cs | 114 ++++++++++-------- .../Internal/AzureFileProperties.cs | 26 ++++ .../Internal/AzureFileReference.cs | 74 ++++-------- .../FileSystemStore.cs | 5 - .../Internal/FileSystemFileProperties.cs | 49 ++++++++ .../Internal/FileSystemFileReference.cs | 55 +++------ src/GeekLearning.Storage/IFileProperties.cs | 18 +++ src/GeekLearning.Storage/IFileReference.cs | 16 +-- src/GeekLearning.Storage/IStore.cs | 3 - .../UpdateTests.cs | 31 +++-- 10 files changed, 214 insertions(+), 177 deletions(-) create mode 100644 src/GeekLearning.Storage.Azure/Internal/AzureFileProperties.cs create mode 100644 src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileProperties.cs create mode 100644 src/GeekLearning.Storage/IFileProperties.cs diff --git a/src/GeekLearning.Storage.Azure/AzureStore.cs b/src/GeekLearning.Storage.Azure/AzureStore.cs index f6f67a6..c3529e8 100644 --- a/src/GeekLearning.Storage.Azure/AzureStore.cs +++ b/src/GeekLearning.Storage.Azure/AzureStore.cs @@ -10,10 +10,8 @@ public class AzureStore : IStore { - private string connectionString; - private Lazy container; private Lazy client; - private string containerName; + private Lazy container; public AzureStore(string storeName, string connectionString, string containerName) { @@ -29,70 +27,37 @@ public AzureStore(string storeName, string connectionString, string containerNam throw new ArgumentNullException("containerName"); } - this.connectionString = connectionString; - this.containerName = containerName; - - client = new Lazy(() => CloudStorageAccount.Parse(this.connectionString).CreateCloudBlobClient()); - container = new Lazy(() => this.client.Value.GetContainerReference(this.containerName)); + this.client = new Lazy(() => CloudStorageAccount.Parse(connectionString).CreateCloudBlobClient()); + this.container = new Lazy(() => this.client.Value.GetContainerReference(containerName)); } public string Name { get; } - private async Task InternalGetAsync(IPrivateFileReference file, bool withMetadata) - { - var azureFile = file as Internal.AzureFileReference; - if (azureFile != null) - { - return azureFile; - } - - try - { - var blob = await this.container.Value.GetBlobReferenceFromServerAsync(file.Path); - return new Internal.AzureFileReference(file.Path, blob); - } - catch (StorageException storageException) - { - if (storageException.RequestInformation.HttpStatusCode == 404) - { - return null; - } - throw; - } - } - public async Task GetAsync(IPrivateFileReference file, bool withMetadata) { - return await InternalGetAsync(file, withMetadata); + return await this.InternalGetAsync(file, withMetadata); } public async Task GetAsync(Uri uri, bool withMetadata) { - if (uri.IsAbsoluteUri) - { - return new Internal.AzureFileReference(await this.client.Value.GetBlobReferenceFromServerAsync(uri)); - } - else - { - return new Internal.AzureFileReference(await this.container.Value.GetBlobReferenceFromServerAsync(uri.ToString())); - } + return await this.InternalGetAsync(uri, withMetadata); } public async Task ReadAsync(IPrivateFileReference file) { - var fileReference = await InternalGetAsync(file, false); + var fileReference = await this.InternalGetAsync(file); return await fileReference.ReadInMemoryAsync(); } public async Task ReadAllBytesAsync(IPrivateFileReference file) { - var fileReference = await InternalGetAsync(file, false); + var fileReference = await this.InternalGetAsync(file); return await fileReference.ReadAllBytesAsync(); } public async Task ReadAllTextAsync(IPrivateFileReference file) { - var fileReference = await InternalGetAsync(file, false); + var fileReference = await this.InternalGetAsync(file); return await fileReference.ReadAllTextAsync(); } @@ -103,7 +68,7 @@ public async Task SaveAsync(Stream data, IPrivateFileReference f blockBlob.Properties.ContentType = contentType; blockBlob.Properties.CacheControl = "max-age=300, must-revalidate"; await blockBlob.SetPropertiesAsync(); - return new Internal.AzureFileReference(blockBlob); + return new Internal.AzureFileReference(blockBlob, withMetadata: true); } public async Task SaveAsync(byte[] data, IPrivateFileReference file, string contentType) @@ -113,7 +78,7 @@ public async Task SaveAsync(byte[] data, IPrivateFileReference f blockBlob.Properties.ContentType = contentType; blockBlob.Properties.CacheControl = "max-age=300, must-revalidate"; await blockBlob.SetPropertiesAsync(); - return new Internal.AzureFileReference(blockBlob); + return new Internal.AzureFileReference(blockBlob, withMetadata: true); } public async Task ListAsync(string path, bool recursive, bool withMetadata) @@ -141,7 +106,7 @@ public async Task ListAsync(string path, bool recursive, bool } while (continuationToken != null); - return results.OfType().Select(blob => new Internal.AzureFileReference(blob)).ToArray(); + return results.OfType().Select(blob => new Internal.AzureFileReference(blob, withMetadata: withMetadata)).ToArray(); } public async Task ListAsync(string path, string searchPattern, bool recursive, bool withMetadata) @@ -181,7 +146,7 @@ public async Task ListAsync(string path, string searchPattern, } while (continuationToken != null); - var pathMap = results.OfType().Select(blob => new Internal.AzureFileReference(blob)).ToDictionary(x => x.Path); + var pathMap = results.OfType().Select(blob => new Internal.AzureFileReference(blob, withMetadata: withMetadata)).ToDictionary(x => x.Path); var filteredResults = matcher.Execute( new Internal.AzureListDirectoryWrapper(path, @@ -192,17 +157,62 @@ public async Task ListAsync(string path, string searchPattern, public async Task DeleteAsync(IPrivateFileReference file) { - var fileReference = await InternalGetAsync(file, false); + var fileReference = await this.InternalGetAsync(file); await fileReference.DeleteAsync(); } - public async Task AddMetadataAsync(IPrivateFileReference file, IDictionary metadata) + private async Task InternalGetAsync(IPrivateFileReference file, bool withMetadata = false) + { + var azureFile = file as Internal.AzureFileReference; + if (azureFile != null) + { + return azureFile; + } + + return await this.InternalGetAsync(new Uri(file.Path, UriKind.Relative), withMetadata); + } + + private async Task InternalGetAsync(Uri uri, bool withMetadata) { - var fileReference = await InternalGetAsync(file, false); + try + { + ICloudBlob blob; - await fileReference.AddMetadataAsync(metadata); + if (uri.IsAbsoluteUri) + { + // When the URI is absolute, we cannot get a simple reference to the blob, so the + // properties and metadata are fetched, even if it was not asked. - return fileReference; + blob = await this.client.Value.GetBlobReferenceFromServerAsync(uri); + withMetadata = true; + } + else + { + if (withMetadata) + { + blob = await this.container.Value.GetBlobReferenceFromServerAsync(uri.ToString()); + } + else + { + blob = this.container.Value.GetBlockBlobReference(uri.ToString()); + if (!(await blob.ExistsAsync())) + { + return null; + } + } + } + + return new Internal.AzureFileReference(blob, withMetadata); + } + catch (StorageException storageException) + { + if (storageException.RequestInformation.HttpStatusCode == 404) + { + return null; + } + + throw; + } } } } diff --git a/src/GeekLearning.Storage.Azure/Internal/AzureFileProperties.cs b/src/GeekLearning.Storage.Azure/Internal/AzureFileProperties.cs new file mode 100644 index 0000000..8cf609a --- /dev/null +++ b/src/GeekLearning.Storage.Azure/Internal/AzureFileProperties.cs @@ -0,0 +1,26 @@ +namespace GeekLearning.Storage.Azure.Internal +{ + using Microsoft.WindowsAzure.Storage.Blob; + using System; + using System.Collections.Generic; + + public class AzureFileProperties : IFileProperties + { + private ICloudBlob cloudBlob; + + public AzureFileProperties(ICloudBlob cloudBlob) + { + this.cloudBlob = cloudBlob; + } + + public DateTimeOffset? LastModified => this.cloudBlob.Properties.LastModified; + + public string ContentType => this.cloudBlob.Properties.ContentType; + + public long Length => this.cloudBlob.Properties.Length; + + public string ETag => this.cloudBlob.Properties.ETag; + + public IDictionary Metadata => this.cloudBlob.Metadata; + } +} diff --git a/src/GeekLearning.Storage.Azure/Internal/AzureFileReference.cs b/src/GeekLearning.Storage.Azure/Internal/AzureFileReference.cs index 92e7a5d..65f6024 100644 --- a/src/GeekLearning.Storage.Azure/Internal/AzureFileReference.cs +++ b/src/GeekLearning.Storage.Azure/Internal/AzureFileReference.cs @@ -3,65 +3,44 @@ using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Blob; using System; - using System.Collections.Generic; using System.IO; using System.Threading.Tasks; public class AzureFileReference : IFileReference { - private ICloudBlob cloudBlob; + private Lazy propertiesLazy; - public AzureFileReference(string path, ICloudBlob cloudBlob) + public AzureFileReference(string path, ICloudBlob cloudBlob, bool withMetadata) { this.Path = path; - this.cloudBlob = cloudBlob; - } + this.CloudBlob = cloudBlob; + this.propertiesLazy = new Lazy(() => + { + if (withMetadata && cloudBlob.Metadata != null && cloudBlob.Properties != null) + { + return new AzureFileProperties(cloudBlob); + } - public AzureFileReference(IListBlobItem blobItem) - : this(blobItem as ICloudBlob) - { + throw new InvalidOperationException("Metadata are not loaded, please use withMetadata option"); + }); } - public AzureFileReference(string path, IListBlobItem blobItem) - : this(path, blobItem as ICloudBlob) - { - } - - public AzureFileReference(ICloudBlob cloudBlob) : - this(cloudBlob.Name, cloudBlob) + public AzureFileReference(ICloudBlob cloudBlob, bool withMetadata) : + this(cloudBlob.Name, cloudBlob, withMetadata) { } public string Path { get; } - public DateTimeOffset? LastModified => this.cloudBlob.Properties?.LastModified; - - public string ContentType => this.cloudBlob.Properties?.ContentType; - - public long? Length => this.cloudBlob.Properties?.Length; + public IFileProperties Properties => this.propertiesLazy.Value; - public string ETag => this.cloudBlob.Properties?.ETag; + public string PublicUrl => this.CloudBlob.Uri.ToString(); - public string PublicUrl => cloudBlob.Uri.ToString(); - - public ICloudBlob CloudBlob => this.cloudBlob; - - public IDictionary Metadata - { - get - { - if (this.cloudBlob.Metadata == null) - { - throw new InvalidOperationException("Metadata are not loaded, please use withMetadata option"); - } - - return this.cloudBlob.Metadata; - } - } + public ICloudBlob CloudBlob { get; } public Task DeleteAsync() { - return this.cloudBlob.DeleteAsync(); + return this.CloudBlob.DeleteAsync(); } public async Task ReadAsync() @@ -79,7 +58,7 @@ public async Task ReadInMemoryAsync() public Task UpdateAsync(Stream stream) { - return this.cloudBlob.UploadFromStreamAsync(stream); + return this.CloudBlob.UploadFromStreamAsync(stream); } public Task GetExpirableUriAsync() @@ -94,7 +73,7 @@ public async Task ReadToStreamAsync(Stream targetStream) public async Task ReadAllTextAsync() { - using (var reader = new StreamReader(await cloudBlob.OpenReadAsync(AccessCondition.GenerateEmptyCondition(), new BlobRequestOptions(), new OperationContext()))) + using (var reader = new StreamReader(await this.CloudBlob.OpenReadAsync(AccessCondition.GenerateEmptyCondition(), new BlobRequestOptions(), new OperationContext()))) { return await reader.ReadToEndAsync(); } @@ -105,19 +84,10 @@ public async Task ReadAllBytesAsync() return (await this.ReadInMemoryAsync()).ToArray(); } - public async Task AddMetadataAsync(IDictionary metadata) - { - foreach (var pair in metadata) - { - this.cloudBlob.Metadata[pair.Key] = pair.Value; - } - - await this.cloudBlob.SetMetadataAsync(); - } - - public Task SaveMetadataAsync() + public async Task SavePropertiesAsync() { - return this.cloudBlob.SetMetadataAsync(); + await this.CloudBlob.SetPropertiesAsync(); + await this.CloudBlob.SetMetadataAsync(); } } } diff --git a/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs b/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs index b67f0dd..d784ef8 100644 --- a/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs +++ b/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs @@ -121,11 +121,6 @@ public Task SaveAsync(byte[] data, IPrivateFileReference file, s return Task.FromResult((IFileReference)fileReference); } - public Task AddMetadataAsync(IPrivateFileReference file, IDictionary metadata) - { - throw new NotImplementedException(); - } - private void EnsurePathExists(string path) { var directoryPath = Path.GetDirectoryName(path); diff --git a/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileProperties.cs b/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileProperties.cs new file mode 100644 index 0000000..cfb24c4 --- /dev/null +++ b/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileProperties.cs @@ -0,0 +1,49 @@ +namespace GeekLearning.Storage.FileSystem.Internal +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + + public class FileSystemFileProperties : IFileProperties + { + private FileInfo fileInfo; + + public FileSystemFileProperties(FileInfo fileInfo) + { + this.fileInfo = fileInfo; + } + + public DateTimeOffset? LastModified => new DateTimeOffset(this.fileInfo.LastWriteTimeUtc, TimeZoneInfo.Local.BaseUtcOffset); + + public long Length => this.fileInfo.Length; + + public string ContentType + { + get + { + throw new NotImplementedException(); + } + } + + public string ETag + { + get + { + throw new NotImplementedException(); + } + } + + public IDictionary Metadata + { + get + { + throw new NotImplementedException(); + } + } + + + } +} diff --git a/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs b/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs index 5712330..7e762ee 100644 --- a/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs +++ b/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs @@ -10,36 +10,36 @@ public class FileSystemFileReference : IFileReference private IPublicUrlProvider publicUrlProvider; private string storeName; private FileInfo fileInfo; - - public FileSystemFileReference(string filePath, string path, string storeName, IPublicUrlProvider publicUrlProvider) + private Lazy propertiesLazy; + + public FileSystemFileReference( + string filePath, + string path, + string storeName, + IPublicUrlProvider publicUrlProvider, + bool withMetadata = false) { this.storeName = storeName; this.publicUrlProvider = publicUrlProvider; this.FileSystemPath = filePath; this.Path = path.Replace('\\', '/'); this.fileInfo = new FileInfo(this.FileSystemPath); + + this.propertiesLazy = new Lazy(() => + { + if (withMetadata) + { + return new FileSystemFileProperties(this.fileInfo); + } + + throw new InvalidOperationException("Metadata are not loaded, please use withMetadata option"); + }); } public string FileSystemPath { get; } public string Path { get; } - public IDictionary Metadata - { - get - { - throw new NotImplementedException(); - } - } - - public string ETag - { - get - { - throw new NotImplementedException(); - } - } - public string PublicUrl { get @@ -53,17 +53,7 @@ public string PublicUrl } } - public DateTimeOffset? LastModified => new DateTimeOffset(this.fileInfo.LastWriteTimeUtc, TimeZoneInfo.Local.BaseUtcOffset); - - public string ContentType - { - get - { - throw new NotImplementedException(); - } - } - - public long? Length => this.fileInfo.Length; + public IFileProperties Properties => this.propertiesLazy.Value; public Task DeleteAsync() { @@ -108,12 +98,7 @@ public async Task UpdateAsync(Stream stream) } } - public Task AddMetadataAsync(IDictionary metadata) - { - throw new NotImplementedException(); - } - - public Task SaveMetadataAsync() + public Task SavePropertiesAsync() { throw new NotImplementedException(); } diff --git a/src/GeekLearning.Storage/IFileProperties.cs b/src/GeekLearning.Storage/IFileProperties.cs new file mode 100644 index 0000000..c4307ac --- /dev/null +++ b/src/GeekLearning.Storage/IFileProperties.cs @@ -0,0 +1,18 @@ +namespace GeekLearning.Storage +{ + using System; + using System.Collections.Generic; + + public interface IFileProperties + { + DateTimeOffset? LastModified { get; } + + long Length { get; } + + string ContentType { get; } + + string ETag { get; } + + IDictionary Metadata { get; } + } +} diff --git a/src/GeekLearning.Storage/IFileReference.cs b/src/GeekLearning.Storage/IFileReference.cs index 2448f8a..b89f712 100644 --- a/src/GeekLearning.Storage/IFileReference.cs +++ b/src/GeekLearning.Storage/IFileReference.cs @@ -1,7 +1,5 @@ namespace GeekLearning.Storage { - using System; - using System.Collections.Generic; using System.IO; using System.Threading.Tasks; @@ -9,15 +7,7 @@ public interface IFileReference : IPrivateFileReference { string PublicUrl { get; } - DateTimeOffset? LastModified { get; } - - string ContentType { get; } - - long? Length { get; } - - string ETag { get; } - - IDictionary Metadata { get; } + IFileProperties Properties { get; } Task ReadToStreamAsync(Stream targetStream); @@ -33,8 +23,6 @@ public interface IFileReference : IPrivateFileReference Task GetExpirableUriAsync(); - Task AddMetadataAsync(IDictionary metadata); - - Task SaveMetadataAsync(); + Task SavePropertiesAsync(); } } diff --git a/src/GeekLearning.Storage/IStore.cs b/src/GeekLearning.Storage/IStore.cs index 831bad7..889d16f 100644 --- a/src/GeekLearning.Storage/IStore.cs +++ b/src/GeekLearning.Storage/IStore.cs @@ -1,7 +1,6 @@ namespace GeekLearning.Storage { using System; - using System.Collections.Generic; using System.IO; using System.Threading.Tasks; @@ -28,7 +27,5 @@ public interface IStore Task SaveAsync(byte[] data, IPrivateFileReference file, string contentType); Task SaveAsync(Stream data, IPrivateFileReference file, string contentType); - - Task AddMetadataAsync(IPrivateFileReference file, IDictionary metadata); } } diff --git a/tests/GeekLearning.Storage.Integration.Test/UpdateTests.cs b/tests/GeekLearning.Storage.Integration.Test/UpdateTests.cs index 31176df..aaa080d 100644 --- a/tests/GeekLearning.Storage.Integration.Test/UpdateTests.cs +++ b/tests/GeekLearning.Storage.Integration.Test/UpdateTests.cs @@ -61,18 +61,17 @@ public async Task AddMetatadaRoundtrip(string storeName) var testFile = "Metadata/TextFile.txt"; - var file = await store.GetAsync(testFile); + var file = await store.GetAsync(testFile, withMetadata: true); var id = Guid.NewGuid().ToString(); - await file.AddMetadataAsync(new Dictionary - { - ["id"] = id - }); + file.Properties.Metadata.Add("newid", id); + + await file.SavePropertiesAsync(); - file = await store.GetAsync(testFile); + file = await store.GetAsync(testFile, withMetadata: true); - var actualId = file.Metadata["id"]; + var actualId = file.Properties.Metadata["newid"]; Assert.Equal(id, actualId); } @@ -86,17 +85,17 @@ public async Task SaveMetatadaRoundtrip(string storeName) var testFile = "Metadata/TextFile.txt"; - var file = await store.GetAsync(testFile); + var file = await store.GetAsync(testFile, withMetadata: true); var id = Guid.NewGuid().ToString(); - file.Metadata["id"] = id; + file.Properties.Metadata["id"] = id; - await file.SaveMetadataAsync(); + await file.SavePropertiesAsync(); - file = await store.GetAsync(testFile); + file = await store.GetAsync(testFile, withMetadata: true); - var actualId = file.Metadata["id"]; + var actualId = file.Properties.Metadata["id"]; Assert.Equal(id, actualId); } @@ -110,13 +109,13 @@ public async Task ListMetatadaRoundtrip(string storeName) var testFile = "Metadata/TextFile.txt"; - var file = await store.GetAsync(testFile); + var file = await store.GetAsync(testFile, withMetadata: true); var id = Guid.NewGuid().ToString(); - file.Metadata["id"] = id; + file.Properties.Metadata["id"] = id; - await file.SaveMetadataAsync(); + await file.SavePropertiesAsync(); var files = await store.ListAsync("Metadata", withMetadata: true); @@ -126,7 +125,7 @@ public async Task ListMetatadaRoundtrip(string storeName) { if (aFile.Path == testFile) { - actualId = aFile.Metadata["id"]; + actualId = aFile.Properties.Metadata["id"]; } } From 291b9752a4d69ce9c148abdf250ceb70c1812074 Mon Sep 17 00:00:00 2001 From: Adrien Siffermann Date: Mon, 9 Jan 2017 18:09:30 +0100 Subject: [PATCH 04/12] Add IExtendedPropertiesProvider abstraction for the FileSystem provider --- src/GeekLearning.Storage.Azure/AzureStore.cs | 95 +++++----- .../Internal/AzureFileProperties.cs | 8 +- .../FileSystemStorageProvider.cs | 9 +- .../FileSystemStore.cs | 178 +++++++++++------- .../IExtendedPropertiesProvider.cs | 11 ++ .../Internal/FileExtendedProperties.cs | 18 ++ .../Internal/FileSystemFileProperties.cs | 35 +--- .../Internal/FileSystemFileReference.cs | 55 +++--- src/GeekLearning.Storage/IFileProperties.cs | 2 +- 9 files changed, 244 insertions(+), 167 deletions(-) create mode 100644 src/GeekLearning.Storage.FileSystem/IExtendedPropertiesProvider.cs create mode 100644 src/GeekLearning.Storage.FileSystem/Internal/FileExtendedProperties.cs diff --git a/src/GeekLearning.Storage.Azure/AzureStore.cs b/src/GeekLearning.Storage.Azure/AzureStore.cs index c3529e8..8d8ec0e 100644 --- a/src/GeekLearning.Storage.Azure/AzureStore.cs +++ b/src/GeekLearning.Storage.Azure/AzureStore.cs @@ -2,6 +2,7 @@ { using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Blob; + using Microsoft.WindowsAzure.Storage.Core; using System; using System.Collections.Generic; using System.IO; @@ -33,54 +34,6 @@ public AzureStore(string storeName, string connectionString, string containerNam public string Name { get; } - public async Task GetAsync(IPrivateFileReference file, bool withMetadata) - { - return await this.InternalGetAsync(file, withMetadata); - } - - public async Task GetAsync(Uri uri, bool withMetadata) - { - return await this.InternalGetAsync(uri, withMetadata); - } - - public async Task ReadAsync(IPrivateFileReference file) - { - var fileReference = await this.InternalGetAsync(file); - return await fileReference.ReadInMemoryAsync(); - } - - public async Task ReadAllBytesAsync(IPrivateFileReference file) - { - var fileReference = await this.InternalGetAsync(file); - return await fileReference.ReadAllBytesAsync(); - } - - public async Task ReadAllTextAsync(IPrivateFileReference file) - { - var fileReference = await this.InternalGetAsync(file); - return await fileReference.ReadAllTextAsync(); - } - - public async Task SaveAsync(Stream data, IPrivateFileReference file, string contentType) - { - var blockBlob = this.container.Value.GetBlockBlobReference(file.Path); - await blockBlob.UploadFromStreamAsync(data); - blockBlob.Properties.ContentType = contentType; - blockBlob.Properties.CacheControl = "max-age=300, must-revalidate"; - await blockBlob.SetPropertiesAsync(); - return new Internal.AzureFileReference(blockBlob, withMetadata: true); - } - - public async Task SaveAsync(byte[] data, IPrivateFileReference file, string contentType) - { - var blockBlob = this.container.Value.GetBlockBlobReference(file.Path); - await blockBlob.UploadFromByteArrayAsync(data, 0, data.Length); - blockBlob.Properties.ContentType = contentType; - blockBlob.Properties.CacheControl = "max-age=300, must-revalidate"; - await blockBlob.SetPropertiesAsync(); - return new Internal.AzureFileReference(blockBlob, withMetadata: true); - } - public async Task ListAsync(string path, bool recursive, bool withMetadata) { if (string.IsNullOrWhiteSpace(path)) @@ -155,12 +108,58 @@ public async Task ListAsync(string path, string searchPattern, return filteredResults.Files.Select(x => pathMap[path + x.Path]).ToArray(); } + public async Task GetAsync(IPrivateFileReference file, bool withMetadata) + { + return await this.InternalGetAsync(file, withMetadata); + } + + public async Task GetAsync(Uri uri, bool withMetadata) + { + return await this.InternalGetAsync(uri, withMetadata); + } + public async Task DeleteAsync(IPrivateFileReference file) { var fileReference = await this.InternalGetAsync(file); await fileReference.DeleteAsync(); } + public async Task ReadAsync(IPrivateFileReference file) + { + var fileReference = await this.InternalGetAsync(file); + return await fileReference.ReadInMemoryAsync(); + } + + public async Task ReadAllBytesAsync(IPrivateFileReference file) + { + var fileReference = await this.InternalGetAsync(file); + return await fileReference.ReadAllBytesAsync(); + } + + public async Task ReadAllTextAsync(IPrivateFileReference file) + { + var fileReference = await this.InternalGetAsync(file); + return await fileReference.ReadAllTextAsync(); + } + + public async Task SaveAsync(byte[] data, IPrivateFileReference file, string contentType) + { + using (var stream = new SyncMemoryStream(data, 0, data.Length)) + { + return await this.SaveAsync(stream, file, contentType); + } + } + + public async Task SaveAsync(Stream data, IPrivateFileReference file, string contentType) + { + var blockBlob = this.container.Value.GetBlockBlobReference(file.Path); + await blockBlob.UploadFromStreamAsync(data); + blockBlob.Properties.ContentType = contentType; + blockBlob.Properties.CacheControl = "max-age=300, must-revalidate"; + await blockBlob.SetPropertiesAsync(); + return new Internal.AzureFileReference(blockBlob, withMetadata: true); + } + private async Task InternalGetAsync(IPrivateFileReference file, bool withMetadata = false) { var azureFile = file as Internal.AzureFileReference; diff --git a/src/GeekLearning.Storage.Azure/Internal/AzureFileProperties.cs b/src/GeekLearning.Storage.Azure/Internal/AzureFileProperties.cs index 8cf609a..ebea78f 100644 --- a/src/GeekLearning.Storage.Azure/Internal/AzureFileProperties.cs +++ b/src/GeekLearning.Storage.Azure/Internal/AzureFileProperties.cs @@ -15,12 +15,16 @@ public AzureFileProperties(ICloudBlob cloudBlob) public DateTimeOffset? LastModified => this.cloudBlob.Properties.LastModified; - public string ContentType => this.cloudBlob.Properties.ContentType; + public string ContentType + { + get { return this.cloudBlob.Properties.ContentType; } + set { this.cloudBlob.Properties.ContentType = value; } + } public long Length => this.cloudBlob.Properties.Length; public string ETag => this.cloudBlob.Properties.ETag; - public IDictionary Metadata => this.cloudBlob.Metadata; + public IDictionary Metadata => this.cloudBlob.Metadata; } } diff --git a/src/GeekLearning.Storage.FileSystem/FileSystemStorageProvider.cs b/src/GeekLearning.Storage.FileSystem/FileSystemStorageProvider.cs index f729d18..5b7cb9d 100644 --- a/src/GeekLearning.Storage.FileSystem/FileSystemStorageProvider.cs +++ b/src/GeekLearning.Storage.FileSystem/FileSystemStorageProvider.cs @@ -21,7 +21,14 @@ public FileSystemStorageProvider(IOptions options, IServicePr public IStore BuildStore(string storeName, IStorageStoreOptions storeOptions) { var publicUrlProvider = this.serviceProvider.GetService(); - return new FileSystemStore(storeName, storeOptions.Parameters["Path"], this.options.Value.RootPath, publicUrlProvider); + var extendedPropertiesProvider = this.serviceProvider.GetService(); + + return new FileSystemStore( + storeName, + storeOptions.Parameters["Path"], + this.options.Value.RootPath, + publicUrlProvider, + extendedPropertiesProvider); } } } diff --git a/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs b/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs index d784ef8..2ce38ab 100644 --- a/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs +++ b/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs @@ -8,14 +8,12 @@ public class FileSystemStore : IStore { - private string absolutePath; - private IPublicUrlProvider publicUrlProvider; + private readonly string absolutePath; + private readonly IPublicUrlProvider publicUrlProvider; + private readonly IExtendedPropertiesProvider extendedPropertiesProvider; - public FileSystemStore(string storeName, string path, string rootPath, IPublicUrlProvider publicUrlProvider) + public FileSystemStore(string storeName, string path, string rootPath, IPublicUrlProvider publicUrlProvider, IExtendedPropertiesProvider extendedPropertiesProvider) { - this.publicUrlProvider = publicUrlProvider; - this.Name = storeName; - if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException("path"); @@ -29,122 +27,170 @@ public FileSystemStore(string storeName, string path, string rootPath, IPublicUr { this.absolutePath = Path.Combine(rootPath, path); } + + this.Name = storeName; + this.publicUrlProvider = publicUrlProvider; + this.extendedPropertiesProvider = extendedPropertiesProvider; } public string Name { get; } - public Task GetAsync(IPrivateFileReference file, bool withMetadata) + public async Task ListAsync(string path, bool recursive, bool withMetadata) { - IFileReference fileReference = this.InternalGetAsync(file); - return Task.FromResult(fileReference); - } + var directoryPath = (string.IsNullOrEmpty(path) || path == "/" || path == "\\") ? this.absolutePath : Path.Combine(this.absolutePath, path); - public Task GetAsync(Uri uri, bool withMetadata) - { - throw new NotImplementedException(); - } + var result = new List(); + if (Directory.Exists(directoryPath)) + { + var allResultPaths = Directory.GetFiles(directoryPath) + .Select(fp => fp.Replace(this.absolutePath, "").Trim('/', '\\')) + .ToList(); + + foreach (var resultPath in allResultPaths) + { + result.Add(await this.InternalGetAsync(resultPath, withMetadata)); + } + } - public Task DeleteAsync(IPrivateFileReference file) - { - var fileReference = InternalGetAsync(file); - return fileReference.DeleteAsync(); + return result.ToArray(); } - public Task ListAsync(string path, bool recursive, bool withMetadata) + public async Task ListAsync(string path, string searchPattern, bool recursive, bool withMetadata) { var directoryPath = (string.IsNullOrEmpty(path) || path == "/" || path == "\\") ? this.absolutePath : Path.Combine(this.absolutePath, path); - if (!Directory.Exists(directoryPath)) + + var result = new List(); + if (Directory.Exists(directoryPath)) { - return Task.FromResult(new IFileReference[0]); + var matcher = new Microsoft.Extensions.FileSystemGlobbing.Matcher(StringComparison.Ordinal); + matcher.AddInclude(searchPattern); + + var matches = matcher.Execute(new Microsoft.Extensions.FileSystemGlobbing.Abstractions.DirectoryInfoWrapper(new DirectoryInfo(directoryPath))); + var allResultPaths = matches.Files + .Select(match => Path.Combine(path, match.Path).Trim('/', '\\')) + .ToList(); + + foreach (var resultPath in allResultPaths) + { + result.Add(await this.InternalGetAsync(resultPath, withMetadata)); + } } - return Task.FromResult(Directory.GetFiles(directoryPath) - .Select(fullPath => - (IFileReference)new Internal.FileSystemFileReference(fullPath, fullPath.Replace(this.absolutePath, "") - .Trim('/', '\\'), this.Name, this.publicUrlProvider)) - .ToArray()); + return result.ToArray(); } - public Task ListAsync(string path, string searchPattern, bool recursive, bool withMetadata) + public async Task GetAsync(IPrivateFileReference file, bool withMetadata) { - var directoryPath = (string.IsNullOrEmpty(path) || path == "/" || path == "\\") ? this.absolutePath : Path.Combine(this.absolutePath, path); - if (!Directory.Exists(directoryPath)) + return await this.InternalGetAsync(file, withMetadata); + } + + public async Task GetAsync(Uri uri, bool withMetadata) + { + if (uri.IsAbsoluteUri) { - return Task.FromResult(new IFileReference[0]); + throw new InvalidOperationException("Cannot resolve an absolute URI with a FileSystem store."); } - Microsoft.Extensions.FileSystemGlobbing.Matcher matcher = new Microsoft.Extensions.FileSystemGlobbing.Matcher(StringComparison.Ordinal); - matcher.AddInclude(searchPattern); + return await this.InternalGetAsync(uri.ToString(), withMetadata); + } - var results = matcher.Execute(new Microsoft.Extensions.FileSystemGlobbing.Abstractions.DirectoryInfoWrapper(new DirectoryInfo(directoryPath))); + public async Task DeleteAsync(IPrivateFileReference file) + { + var fileReference = await this.InternalGetAsync(file); + await fileReference.DeleteAsync(); + } - return Task.FromResult(results.Files - .Select(match => (IFileReference)new Internal.FileSystemFileReference(Path.Combine(directoryPath, match.Path), Path.Combine(path, match.Path).Trim('/', '\\'), this.Name, this.publicUrlProvider)) - .ToArray()); + public async Task ReadAsync(IPrivateFileReference file) + { + var fileReference = await this.InternalGetAsync(file); + return await fileReference.ReadAsync(); } - public Task ReadAsync(IPrivateFileReference file) + public async Task ReadAllBytesAsync(IPrivateFileReference file) { - var fileReference = InternalGetAsync(file); - return fileReference.ReadAsync(); + var fileReference = await this.InternalGetAsync(file); + return await fileReference.ReadAllBytesAsync(); } - public Task ReadAllBytesAsync(IPrivateFileReference file) + public async Task ReadAllTextAsync(IPrivateFileReference file) { - var fileReference = InternalGetAsync(file); - return fileReference.ReadAllBytesAsync(); + var fileReference = await this.InternalGetAsync(file); + return await fileReference.ReadAllTextAsync(); } - public Task ReadAllTextAsync(IPrivateFileReference file) + public async Task SaveAsync(byte[] data, IPrivateFileReference file, string contentType) { - var fileReference = InternalGetAsync(file); - return fileReference.ReadAllTextAsync(); + using (var stream = new MemoryStream(data, 0, data.Length)) + { + return await this.SaveAsync(stream, file, contentType); + } } public async Task SaveAsync(Stream data, IPrivateFileReference file, string contentType) { - var fileReference = InternalGetOrCreateAsync(file); - EnsurePathExists(fileReference.FileSystemPath); + var fileReference = await this.InternalGetAsync(file, withMetadata: true, checkIfExists: false); + this.EnsurePathExists(fileReference.FileSystemPath); + using (var fileStream = File.Open(fileReference.FileSystemPath, FileMode.Create, FileAccess.Write)) { await data.CopyToAsync(fileStream); } + fileReference.Properties.ContentType = contentType; + await fileReference.SavePropertiesAsync(); + return fileReference; } - public Task SaveAsync(byte[] data, IPrivateFileReference file, string contentType) + private async Task InternalGetAsync(IPrivateFileReference file, bool withMetadata = false, bool checkIfExists = true) { - var fileReference = InternalGetOrCreateAsync(file); - EnsurePathExists(fileReference.FileSystemPath); - File.WriteAllBytes(fileReference.FileSystemPath, data); - return Task.FromResult((IFileReference)fileReference); + var fileSystemFile = file as Internal.FileSystemFileReference; + if (fileSystemFile != null) + { + return fileSystemFile; + } + + return await this.InternalGetAsync(file.Path, withMetadata, checkIfExists); } - private void EnsurePathExists(string path) + private async Task InternalGetAsync(string path, bool withMetadata, bool checkIfExists = true) { - var directoryPath = Path.GetDirectoryName(path); - if (!Directory.Exists(directoryPath)) + var fullPath = Path.Combine(this.absolutePath, path); + if (checkIfExists && !File.Exists(fullPath)) { - Directory.CreateDirectory(directoryPath); + return null; } - } - private Internal.FileSystemFileReference InternalGetAsync(IPrivateFileReference file) - { - var reference = InternalGetOrCreateAsync(file); - if (File.Exists(reference.FileSystemPath)) + Internal.FileExtendedProperties extendedProperties = null; + if (withMetadata) { - return reference; + if (this.extendedPropertiesProvider == null) + { + throw new InvalidOperationException("There is no FileSystem extended properties provider."); + } + + extendedProperties = await this.extendedPropertiesProvider.GetExtendedPropertiesAsync( + this.Name, + new Storage.Internal.PrivateFileReference(path)); } - return null; + return new Internal.FileSystemFileReference( + fullPath, + path, + this.Name, + withMetadata, + extendedProperties, + this.publicUrlProvider, + this.extendedPropertiesProvider); } - private Internal.FileSystemFileReference InternalGetOrCreateAsync(IPrivateFileReference file) + private void EnsurePathExists(string path) { - var fullPath = Path.Combine(this.absolutePath, file.Path); - return new Internal.FileSystemFileReference(fullPath, file.Path, this.Name, this.publicUrlProvider); + var directoryPath = Path.GetDirectoryName(path); + if (!Directory.Exists(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } } } } diff --git a/src/GeekLearning.Storage.FileSystem/IExtendedPropertiesProvider.cs b/src/GeekLearning.Storage.FileSystem/IExtendedPropertiesProvider.cs new file mode 100644 index 0000000..d85b494 --- /dev/null +++ b/src/GeekLearning.Storage.FileSystem/IExtendedPropertiesProvider.cs @@ -0,0 +1,11 @@ +namespace GeekLearning.Storage.FileSystem +{ + using System.Threading.Tasks; + + public interface IExtendedPropertiesProvider + { + Task GetExtendedPropertiesAsync(string storeName, IPrivateFileReference file); + + Task SaveExtendedPropertiesAsync(string storeName, IPrivateFileReference file, Internal.FileExtendedProperties extendedProperties); + } +} diff --git a/src/GeekLearning.Storage.FileSystem/Internal/FileExtendedProperties.cs b/src/GeekLearning.Storage.FileSystem/Internal/FileExtendedProperties.cs new file mode 100644 index 0000000..d108f30 --- /dev/null +++ b/src/GeekLearning.Storage.FileSystem/Internal/FileExtendedProperties.cs @@ -0,0 +1,18 @@ +namespace GeekLearning.Storage.FileSystem.Internal +{ + using System.Collections.Generic; + + public class FileExtendedProperties + { + public FileExtendedProperties() + { + this.Metadata = new Dictionary(); + } + + public string ContentType { get; set; } + + public string ETag { get; set; } + + public IDictionary Metadata { get; set; } + } +} diff --git a/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileProperties.cs b/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileProperties.cs index cfb24c4..5f61046 100644 --- a/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileProperties.cs +++ b/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileProperties.cs @@ -3,17 +3,16 @@ using System; using System.Collections.Generic; using System.IO; - using System.Linq; - using System.Text; - using System.Threading.Tasks; public class FileSystemFileProperties : IFileProperties { - private FileInfo fileInfo; + private readonly FileInfo fileInfo; + private readonly FileExtendedProperties extendedProperties; - public FileSystemFileProperties(FileInfo fileInfo) + public FileSystemFileProperties(string fileSystemPath, FileExtendedProperties extendedProperties) { - this.fileInfo = fileInfo; + this.fileInfo = new FileInfo(fileSystemPath); + this.extendedProperties = extendedProperties; } public DateTimeOffset? LastModified => new DateTimeOffset(this.fileInfo.LastWriteTimeUtc, TimeZoneInfo.Local.BaseUtcOffset); @@ -22,28 +21,14 @@ public FileSystemFileProperties(FileInfo fileInfo) public string ContentType { - get - { - throw new NotImplementedException(); - } + get { return this.extendedProperties.ContentType; } + set { this.extendedProperties.ContentType = value; } } - public string ETag - { - get - { - throw new NotImplementedException(); - } - } - - public IDictionary Metadata - { - get - { - throw new NotImplementedException(); - } - } + public string ETag => this.extendedProperties.ETag; + public IDictionary Metadata => this.extendedProperties.Metadata; + internal FileExtendedProperties ExtendedProperties => this.extendedProperties; } } diff --git a/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs b/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs index 7e762ee..9495033 100644 --- a/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs +++ b/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs @@ -1,58 +1,57 @@ namespace GeekLearning.Storage.FileSystem.Internal { using System; - using System.Collections.Generic; using System.IO; using System.Threading.Tasks; public class FileSystemFileReference : IFileReference { - private IPublicUrlProvider publicUrlProvider; - private string storeName; - private FileInfo fileInfo; - private Lazy propertiesLazy; + private readonly string storeName; + private readonly Lazy propertiesLazy; + private readonly Lazy publicUrlLazy; + private readonly IExtendedPropertiesProvider extendedPropertiesProvider; public FileSystemFileReference( - string filePath, - string path, - string storeName, + string filePath, + string path, + string storeName, + bool withMetadata, + FileExtendedProperties extendedProperties, IPublicUrlProvider publicUrlProvider, - bool withMetadata = false) + IExtendedPropertiesProvider extendedPropertiesProvider) { - this.storeName = storeName; - this.publicUrlProvider = publicUrlProvider; this.FileSystemPath = filePath; this.Path = path.Replace('\\', '/'); - this.fileInfo = new FileInfo(this.FileSystemPath); + this.storeName = storeName; + this.extendedPropertiesProvider = extendedPropertiesProvider; this.propertiesLazy = new Lazy(() => { if (withMetadata) { - return new FileSystemFileProperties(this.fileInfo); + return new FileSystemFileProperties(this.FileSystemPath, extendedProperties); } throw new InvalidOperationException("Metadata are not loaded, please use withMetadata option"); }); - } - - public string FileSystemPath { get; } - public string Path { get; } - - public string PublicUrl - { - get + this.publicUrlLazy = new Lazy(() => { if (publicUrlProvider != null) { return publicUrlProvider.GetPublicUrl(storeName, this); } - throw new NotSupportedException("There is not FileSystemServer enabled."); - } + throw new InvalidOperationException("There is not FileSystemServer enabled."); + }); } + public string FileSystemPath { get; } + + public string Path { get; } + + public string PublicUrl => this.publicUrlLazy.Value; + public IFileProperties Properties => this.propertiesLazy.Value; public Task DeleteAsync() @@ -100,7 +99,15 @@ public async Task UpdateAsync(Stream stream) public Task SavePropertiesAsync() { - throw new NotImplementedException(); + if (this.extendedPropertiesProvider == null) + { + throw new InvalidOperationException("There is no FileSystem extended properties provider."); + } + + return this.extendedPropertiesProvider.SaveExtendedPropertiesAsync( + this.storeName, + this, + (this.Properties as FileSystemFileProperties).ExtendedProperties); } } } diff --git a/src/GeekLearning.Storage/IFileProperties.cs b/src/GeekLearning.Storage/IFileProperties.cs index c4307ac..f0faa68 100644 --- a/src/GeekLearning.Storage/IFileProperties.cs +++ b/src/GeekLearning.Storage/IFileProperties.cs @@ -9,7 +9,7 @@ public interface IFileProperties long Length { get; } - string ContentType { get; } + string ContentType { get; set; } string ETag { get; } From 5fdd82ff3f918969b919e23e2f061338e2dfb167 Mon Sep 17 00:00:00 2001 From: Adrien Siffermann Date: Mon, 9 Jan 2017 19:47:55 +0100 Subject: [PATCH 05/12] FileSystem implementation of Extended Properties provider --- GeekLearning.Storage.sln | 7 +++ src/GeekLearning.Storage.Azure/AzureStore.cs | 17 ++++-- .../Internal/AzureFileProperties.cs | 17 +++++- .../FileSystemExtendedPropertiesExtensions.cs | 18 ++++++ .../FileSystemExtendedPropertiesOptions.cs | 7 +++ ...System.ExtendedProperties.FileSystem.xproj | 21 +++++++ .../Internal/ExtendedPropertiesProvider.cs | 60 +++++++++++++++++++ .../Properties/AssemblyInfo.cs | 19 ++++++ .../project.json | 22 +++++++ .../FileSystemStorageServerMiddleware.cs | 10 +++- .../FileSystemStore.cs | 41 +++++++++---- .../IExtendedPropertiesProvider.cs | 4 +- .../Internal/FileExtendedProperties.cs | 2 + .../Internal/FileSystemFileProperties.cs | 6 ++ .../Internal/FileSystemFileReference.cs | 10 ++-- src/GeekLearning.Storage/IFileProperties.cs | 2 + .../StoresFixture.cs | 21 ++++++- .../UpdateTests.cs | 6 +- .../appsettings.json | 3 +- .../project.json | 3 +- 20 files changed, 263 insertions(+), 33 deletions(-) create mode 100644 src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/FileSystemExtendedPropertiesExtensions.cs create mode 100644 src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/FileSystemExtendedPropertiesOptions.cs create mode 100644 src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem.xproj create mode 100644 src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/Internal/ExtendedPropertiesProvider.cs create mode 100644 src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/Properties/AssemblyInfo.cs create mode 100644 src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/project.json diff --git a/GeekLearning.Storage.sln b/GeekLearning.Storage.sln index bc2f558..1c39f88 100644 --- a/GeekLearning.Storage.sln +++ b/GeekLearning.Storage.sln @@ -31,6 +31,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{520AB1D3-C50 EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "GeekLearning.Storage.Integration.Test", "tests\GeekLearning.Storage.Integration.Test\GeekLearning.Storage.Integration.Test.xproj", "{590B21B0-2AFA-4329-82AD-EF180C50EB5C}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem", "src\GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem\GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem.xproj", "{8C02EBBE-9EC8-4F47-9464-5A94BDE25A8F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -61,6 +63,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 + {8C02EBBE-9EC8-4F47-9464-5A94BDE25A8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C02EBBE-9EC8-4F47-9464-5A94BDE25A8F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C02EBBE-9EC8-4F47-9464-5A94BDE25A8F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C02EBBE-9EC8-4F47-9464-5A94BDE25A8F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -72,5 +78,6 @@ Global {63416AEA-DA51-4D62-B566-DB7D9BC800DC} = {FBAC4C17-D755-49A9-959D-18FD6B95B543} {9D94CD6C-9451-449A-BED2-1C07D624A8E0} = {520AB1D3-C501-40FD-ACEB-7CC0D1F00B90} {590B21B0-2AFA-4329-82AD-EF180C50EB5C} = {2DAF5EF9-8F8E-4C51-BE2D-8D63CA143360} + {8C02EBBE-9EC8-4F47-9464-5A94BDE25A8F} = {520AB1D3-C501-40FD-ACEB-7CC0D1F00B90} EndGlobalSection EndGlobal diff --git a/src/GeekLearning.Storage.Azure/AzureStore.cs b/src/GeekLearning.Storage.Azure/AzureStore.cs index 8d8ec0e..ff125a7 100644 --- a/src/GeekLearning.Storage.Azure/AzureStore.cs +++ b/src/GeekLearning.Storage.Azure/AzureStore.cs @@ -153,11 +153,20 @@ public async Task SaveAsync(byte[] data, IPrivateFileReference f public async Task SaveAsync(Stream data, IPrivateFileReference file, string contentType) { var blockBlob = this.container.Value.GetBlockBlobReference(file.Path); + + if (await blockBlob.ExistsAsync()) + { + await blockBlob.FetchAttributesAsync(); + } + await blockBlob.UploadFromStreamAsync(data); - blockBlob.Properties.ContentType = contentType; - blockBlob.Properties.CacheControl = "max-age=300, must-revalidate"; - await blockBlob.SetPropertiesAsync(); - return new Internal.AzureFileReference(blockBlob, withMetadata: true); + + var reference = new Internal.AzureFileReference(blockBlob, withMetadata: true); + + reference.Properties.ContentType = contentType; + await reference.SavePropertiesAsync(); + + return reference; } private async Task InternalGetAsync(IPrivateFileReference file, bool withMetadata = false) diff --git a/src/GeekLearning.Storage.Azure/Internal/AzureFileProperties.cs b/src/GeekLearning.Storage.Azure/Internal/AzureFileProperties.cs index ebea78f..47a1614 100644 --- a/src/GeekLearning.Storage.Azure/Internal/AzureFileProperties.cs +++ b/src/GeekLearning.Storage.Azure/Internal/AzureFileProperties.cs @@ -6,25 +6,36 @@ public class AzureFileProperties : IFileProperties { - private ICloudBlob cloudBlob; + private const string DefaultCacheControl = "max-age=300, must-revalidate"; + private readonly ICloudBlob cloudBlob; public AzureFileProperties(ICloudBlob cloudBlob) { this.cloudBlob = cloudBlob; + if (string.IsNullOrEmpty(this.cloudBlob.Properties.CacheControl)) + { + this.cloudBlob.Properties.CacheControl = DefaultCacheControl; + } } public DateTimeOffset? LastModified => this.cloudBlob.Properties.LastModified; + public long Length => this.cloudBlob.Properties.Length; + public string ContentType { get { return this.cloudBlob.Properties.ContentType; } set { this.cloudBlob.Properties.ContentType = value; } } - public long Length => this.cloudBlob.Properties.Length; - public string ETag => this.cloudBlob.Properties.ETag; + public string CacheControl + { + get { return this.cloudBlob.Properties.CacheControl; } + set { this.cloudBlob.Properties.CacheControl = value; } + } + public IDictionary Metadata => this.cloudBlob.Metadata; } } diff --git a/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/FileSystemExtendedPropertiesExtensions.cs b/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/FileSystemExtendedPropertiesExtensions.cs new file mode 100644 index 0000000..5d489bd --- /dev/null +++ b/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/FileSystemExtendedPropertiesExtensions.cs @@ -0,0 +1,18 @@ +namespace GeekLearning.Storage +{ + using FileSystem; + using FileSystem.ExtendedProperties.FileSystem; + using FileSystem.ExtendedProperties.FileSystem.Internal; + using Microsoft.Extensions.DependencyInjection; + using System; + + public static class FileSystemExtendedPropertiesExtensions + { + public static IServiceCollection AddFileSystemExtendedProperties(this IServiceCollection services, Action configure) + { + services.Configure(configure); + services.AddTransient(); + return services; + } + } +} diff --git a/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/FileSystemExtendedPropertiesOptions.cs b/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/FileSystemExtendedPropertiesOptions.cs new file mode 100644 index 0000000..2e0ca0d --- /dev/null +++ b/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/FileSystemExtendedPropertiesOptions.cs @@ -0,0 +1,7 @@ +namespace GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem +{ + public class FileSystemExtendedPropertiesOptions + { + public string FolderNameFormat { get; set; } = ".{0}-extended-properties"; + } +} diff --git a/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem.xproj b/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem.xproj new file mode 100644 index 0000000..7354067 --- /dev/null +++ b/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem.xproj @@ -0,0 +1,21 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + 8c02ebbe-9ec8-4f47-9464-5a94bde25a8f + GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem + .\obj + .\bin\ + v4.6.2 + + + + 2.0 + + + diff --git a/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/Internal/ExtendedPropertiesProvider.cs b/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/Internal/ExtendedPropertiesProvider.cs new file mode 100644 index 0000000..afdf947 --- /dev/null +++ b/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/Internal/ExtendedPropertiesProvider.cs @@ -0,0 +1,60 @@ +namespace GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem.Internal +{ + using Microsoft.Extensions.Options; + using Newtonsoft.Json; + using Storage.FileSystem.Internal; + using System.IO; + using System.Threading.Tasks; + + public class ExtendedPropertiesProvider : IExtendedPropertiesProvider + { + private readonly FileSystemExtendedPropertiesOptions options; + private readonly IStorageFactory storageFactory; + + public ExtendedPropertiesProvider( + IOptions options) + { + this.options = options.Value; + } + + public Task GetExtendedPropertiesAsync(string storeAbsolutePath, IPrivateFileReference file) + { + var extendedPropertiesPath = this.GetExtendedPropertiesPath(storeAbsolutePath, file); + if (!File.Exists(extendedPropertiesPath)) + { + return Task.FromResult(new FileExtendedProperties()); + } + + var content = File.ReadAllText(extendedPropertiesPath); + return Task.FromResult(JsonConvert.DeserializeObject(content)); + } + + public Task SaveExtendedPropertiesAsync(string storeAbsolutePath, IPrivateFileReference file, FileExtendedProperties extendedProperties) + { + var extendedPropertiesPath = this.GetExtendedPropertiesPath(storeAbsolutePath, file); + var toStore = JsonConvert.SerializeObject(extendedProperties); + File.WriteAllText(extendedPropertiesPath, toStore); + return Task.FromResult(0); + } + + private string GetExtendedPropertiesPath(string storeAbsolutePath, IPrivateFileReference file) + { + var fullPath = Path.GetFullPath(storeAbsolutePath).TrimEnd(Path.DirectorySeparatorChar); + var rootPath = Path.GetDirectoryName(fullPath); + var storeName = Path.GetFileName(fullPath); + + var extendedPropertiesPath = Path.Combine(rootPath, string.Format(this.options.FolderNameFormat, storeName), file.Path + ".json"); + this.EnsurePathExists(extendedPropertiesPath); + return extendedPropertiesPath; + } + + private void EnsurePathExists(string path) + { + var directoryPath = Path.GetDirectoryName(path); + if (!Directory.Exists(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } + } + } +} diff --git a/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/Properties/AssemblyInfo.cs b/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..6c872e6 --- /dev/null +++ b/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8c02ebbe-9ec8-4f47-9464-5a94bde25a8f")] diff --git a/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/project.json b/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/project.json new file mode 100644 index 0000000..af100df --- /dev/null +++ b/src/GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem/project.json @@ -0,0 +1,22 @@ +{ + "version": "0.0.1-*", + "description": "File System based extended properties storage provider for the FileSystem provider.", + "authors": [ "Geek Learning", "Adrien Siffermann", "Cyprien Autexier" ], + "packOptions": { + "tags": [], + "projectUrl": "", + "licenseUrl": "" + }, + + "dependencies": { + "NETStandard.Library": "1.6.1", + "Newtonsoft.Json": "9.0.1", + + "GeekLearning.Storage.FileSystem": "*" + }, + + "frameworks": { + "net45": {}, + "netstandard1.3": {} + } +} diff --git a/src/GeekLearning.Storage.FileSystem.Server/FileSystemStorageServerMiddleware.cs b/src/GeekLearning.Storage.FileSystem.Server/FileSystemStorageServerMiddleware.cs index 862611f..d9387f8 100644 --- a/src/GeekLearning.Storage.FileSystem.Server/FileSystemStorageServerMiddleware.cs +++ b/src/GeekLearning.Storage.FileSystem.Server/FileSystemStorageServerMiddleware.cs @@ -46,11 +46,17 @@ public async Task Invoke(HttpContext context) IStore store = storageFactory.GetStore(storeName, storeOptions); - var file = await store.GetAsync(context.Request.Path.Value.Substring(subPathStart + 1)); + var file = await store.GetAsync(context.Request.Path.Value.Substring(subPathStart + 1), withMetadata: true); if (file != null) { - context.Response.ContentType = "application/octet-stream"; + context.Response.ContentType = file.Properties.ContentType; context.Response.StatusCode = StatusCodes.Status200OK; + + if (!string.IsNullOrEmpty(file.Properties.ETag)) + { + context.Response.Headers.Add("ETag", new[] { file.Properties.ETag }); + } + await file.ReadToStreamAsync(context.Response.Body); return; } diff --git a/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs b/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs index 2ce38ab..9916140 100644 --- a/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs +++ b/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs @@ -4,11 +4,11 @@ using System.Collections.Generic; using System.IO; using System.Linq; + using System.Security.Cryptography; using System.Threading.Tasks; public class FileSystemStore : IStore { - private readonly string absolutePath; private readonly IPublicUrlProvider publicUrlProvider; private readonly IExtendedPropertiesProvider extendedPropertiesProvider; @@ -21,11 +21,11 @@ public FileSystemStore(string storeName, string path, string rootPath, IPublicUr if (Path.IsPathRooted(path)) { - this.absolutePath = path; + this.AbsolutePath = path; } else { - this.absolutePath = Path.Combine(rootPath, path); + this.AbsolutePath = Path.Combine(rootPath, path); } this.Name = storeName; @@ -35,15 +35,17 @@ public FileSystemStore(string storeName, string path, string rootPath, IPublicUr public string Name { get; } + internal string AbsolutePath { get; } + public async Task ListAsync(string path, bool recursive, bool withMetadata) { - var directoryPath = (string.IsNullOrEmpty(path) || path == "/" || path == "\\") ? this.absolutePath : Path.Combine(this.absolutePath, path); + var directoryPath = (string.IsNullOrEmpty(path) || path == "/" || path == "\\") ? this.AbsolutePath : Path.Combine(this.AbsolutePath, path); var result = new List(); if (Directory.Exists(directoryPath)) { var allResultPaths = Directory.GetFiles(directoryPath) - .Select(fp => fp.Replace(this.absolutePath, "").Trim('/', '\\')) + .Select(fp => fp.Replace(this.AbsolutePath, "").Trim('/', '\\')) .ToList(); foreach (var resultPath in allResultPaths) @@ -57,7 +59,7 @@ public async Task ListAsync(string path, bool recursive, bool public async Task ListAsync(string path, string searchPattern, bool recursive, bool withMetadata) { - var directoryPath = (string.IsNullOrEmpty(path) || path == "/" || path == "\\") ? this.absolutePath : Path.Combine(this.absolutePath, path); + var directoryPath = (string.IsNullOrEmpty(path) || path == "/" || path == "\\") ? this.AbsolutePath : Path.Combine(this.AbsolutePath, path); var result = new List(); if (Directory.Exists(directoryPath)) @@ -136,7 +138,11 @@ public async Task SaveAsync(Stream data, IPrivateFileReference f await data.CopyToAsync(fileStream); } - fileReference.Properties.ContentType = contentType; + var properties = fileReference.Properties as Internal.FileSystemFileProperties; + + properties.ContentType = contentType; + properties.ExtendedProperties.ETag = GenerateEtag(fileReference.FileSystemPath); + await fileReference.SavePropertiesAsync(); return fileReference; @@ -155,7 +161,7 @@ public async Task SaveAsync(Stream data, IPrivateFileReference f private async Task InternalGetAsync(string path, bool withMetadata, bool checkIfExists = true) { - var fullPath = Path.Combine(this.absolutePath, path); + var fullPath = Path.Combine(this.AbsolutePath, path); if (checkIfExists && !File.Exists(fullPath)) { return null; @@ -170,14 +176,14 @@ public async Task SaveAsync(Stream data, IPrivateFileReference f } extendedProperties = await this.extendedPropertiesProvider.GetExtendedPropertiesAsync( - this.Name, + this.AbsolutePath, new Storage.Internal.PrivateFileReference(path)); } return new Internal.FileSystemFileReference( fullPath, path, - this.Name, + this, withMetadata, extendedProperties, this.publicUrlProvider, @@ -192,5 +198,20 @@ private void EnsurePathExists(string path) Directory.CreateDirectory(directoryPath); } } + + private static string GenerateEtag(string fileSystemPath) + { + var data = File.ReadAllBytes(fileSystemPath); + var etag = string.Empty; + + using (var md5 = MD5.Create()) + { + var hash = md5.ComputeHash(data); + string hex = BitConverter.ToString(hash); + etag = hex.Replace("-", ""); + } + + return $"\"{etag}\""; + } } } diff --git a/src/GeekLearning.Storage.FileSystem/IExtendedPropertiesProvider.cs b/src/GeekLearning.Storage.FileSystem/IExtendedPropertiesProvider.cs index d85b494..843de53 100644 --- a/src/GeekLearning.Storage.FileSystem/IExtendedPropertiesProvider.cs +++ b/src/GeekLearning.Storage.FileSystem/IExtendedPropertiesProvider.cs @@ -4,8 +4,8 @@ public interface IExtendedPropertiesProvider { - Task GetExtendedPropertiesAsync(string storeName, IPrivateFileReference file); + Task GetExtendedPropertiesAsync(string storeAbsolutePath, IPrivateFileReference file); - Task SaveExtendedPropertiesAsync(string storeName, IPrivateFileReference file, Internal.FileExtendedProperties extendedProperties); + Task SaveExtendedPropertiesAsync(string storeAbsolutePath, IPrivateFileReference file, Internal.FileExtendedProperties extendedProperties); } } diff --git a/src/GeekLearning.Storage.FileSystem/Internal/FileExtendedProperties.cs b/src/GeekLearning.Storage.FileSystem/Internal/FileExtendedProperties.cs index d108f30..b644a6f 100644 --- a/src/GeekLearning.Storage.FileSystem/Internal/FileExtendedProperties.cs +++ b/src/GeekLearning.Storage.FileSystem/Internal/FileExtendedProperties.cs @@ -13,6 +13,8 @@ public FileExtendedProperties() public string ETag { get; set; } + public string CacheControl { get; set; } + public IDictionary Metadata { get; set; } } } diff --git a/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileProperties.cs b/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileProperties.cs index 5f61046..4f8288a 100644 --- a/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileProperties.cs +++ b/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileProperties.cs @@ -27,6 +27,12 @@ public string ContentType public string ETag => this.extendedProperties.ETag; + public string CacheControl + { + get { return this.extendedProperties.CacheControl; } + set { this.extendedProperties.CacheControl = value; } + } + public IDictionary Metadata => this.extendedProperties.Metadata; internal FileExtendedProperties ExtendedProperties => this.extendedProperties; diff --git a/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs b/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs index 9495033..6ed1d9a 100644 --- a/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs +++ b/src/GeekLearning.Storage.FileSystem/Internal/FileSystemFileReference.cs @@ -6,7 +6,7 @@ public class FileSystemFileReference : IFileReference { - private readonly string storeName; + private readonly FileSystemStore store; private readonly Lazy propertiesLazy; private readonly Lazy publicUrlLazy; private readonly IExtendedPropertiesProvider extendedPropertiesProvider; @@ -14,7 +14,7 @@ public class FileSystemFileReference : IFileReference public FileSystemFileReference( string filePath, string path, - string storeName, + FileSystemStore store, bool withMetadata, FileExtendedProperties extendedProperties, IPublicUrlProvider publicUrlProvider, @@ -22,7 +22,7 @@ public FileSystemFileReference( { this.FileSystemPath = filePath; this.Path = path.Replace('\\', '/'); - this.storeName = storeName; + this.store = store; this.extendedPropertiesProvider = extendedPropertiesProvider; this.propertiesLazy = new Lazy(() => @@ -39,7 +39,7 @@ public FileSystemFileReference( { if (publicUrlProvider != null) { - return publicUrlProvider.GetPublicUrl(storeName, this); + return publicUrlProvider.GetPublicUrl(this.store.Name, this); } throw new InvalidOperationException("There is not FileSystemServer enabled."); @@ -105,7 +105,7 @@ public Task SavePropertiesAsync() } return this.extendedPropertiesProvider.SaveExtendedPropertiesAsync( - this.storeName, + this.store.AbsolutePath, this, (this.Properties as FileSystemFileProperties).ExtendedProperties); } diff --git a/src/GeekLearning.Storage/IFileProperties.cs b/src/GeekLearning.Storage/IFileProperties.cs index f0faa68..a786d1b 100644 --- a/src/GeekLearning.Storage/IFileProperties.cs +++ b/src/GeekLearning.Storage/IFileProperties.cs @@ -13,6 +13,8 @@ public interface IFileProperties string ETag { get; } + string CacheControl { get; set; } + IDictionary Metadata { get; } } } diff --git a/tests/GeekLearning.Storage.Integration.Test/StoresFixture.cs b/tests/GeekLearning.Storage.Integration.Test/StoresFixture.cs index d89422f..4787584 100644 --- a/tests/GeekLearning.Storage.Integration.Test/StoresFixture.cs +++ b/tests/GeekLearning.Storage.Integration.Test/StoresFixture.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; + using System.IO; public class StoresFixture : IDisposable { @@ -35,7 +36,8 @@ public StoresFixture() services.AddStorage() .AddAzureStorage() - .AddFileSystemStorage(BasePath); + .AddFileSystemStorage(BasePath) + .AddFileSystemExtendedProperties(o => { }); services.Configure(Configuration.GetSection("Storage")); @@ -55,7 +57,7 @@ private void ResetFileSystemStore() var directoryName = Configuration["Storage:Stores:filesystem:Parameters:Path"]; var process = Process.Start(new ProcessStartInfo("robocopy.exe") { - Arguments = $"\"{System.IO.Path.Combine(BasePath, "SampleDirectory")}\" \"{System.IO.Path.Combine(BasePath, directoryName)}\" /MIR" + Arguments = $"\"{Path.Combine(BasePath, "SampleDirectory")}\" \"{Path.Combine(BasePath, directoryName)}\" /MIR" }); if (!process.WaitForExit(30000)) @@ -100,6 +102,21 @@ private void ResetAzureStore() public void Dispose() { container.DeleteIfExistsAsync().Wait(); + + var fileSystemPath = Configuration["Storage:Stores:filesystem:Parameters:Path"]; + var folderNameFormat = Configuration["Storage:ExtendedPropertiesFolderNameFormat"]; + + var directoryName = Path.Combine(BasePath, fileSystemPath); + if (Directory.Exists(directoryName)) + { + Directory.Delete(directoryName, true); + } + + directoryName = Path.Combine(BasePath, string.Format(folderNameFormat, fileSystemPath)); + if (Directory.Exists(directoryName)) + { + Directory.Delete(directoryName, true); + } } } } diff --git a/tests/GeekLearning.Storage.Integration.Test/UpdateTests.cs b/tests/GeekLearning.Storage.Integration.Test/UpdateTests.cs index aaa080d..254028a 100644 --- a/tests/GeekLearning.Storage.Integration.Test/UpdateTests.cs +++ b/tests/GeekLearning.Storage.Integration.Test/UpdateTests.cs @@ -52,7 +52,7 @@ public async Task SaveStream(string storeName) Assert.Equal(textToWrite, readFromWrittenFile); } - [Theory(DisplayName = nameof(AddMetatadaRoundtrip)), InlineData("azure")] + [Theory(DisplayName = nameof(AddMetatadaRoundtrip)), InlineData("azure"), InlineData("filesystem")] public async Task AddMetatadaRoundtrip(string storeName) { var storageFactory = this.storeFixture.Services.GetRequiredService(); @@ -76,7 +76,7 @@ public async Task AddMetatadaRoundtrip(string storeName) Assert.Equal(id, actualId); } - [Theory(DisplayName = nameof(SaveMetatadaRoundtrip)), InlineData("azure")] + [Theory(DisplayName = nameof(SaveMetatadaRoundtrip)), InlineData("azure"), InlineData("filesystem")] public async Task SaveMetatadaRoundtrip(string storeName) { var storageFactory = this.storeFixture.Services.GetRequiredService(); @@ -100,7 +100,7 @@ public async Task SaveMetatadaRoundtrip(string storeName) Assert.Equal(id, actualId); } - [Theory(DisplayName = nameof(ListMetatadaRoundtrip)), InlineData("azure")] + [Theory(DisplayName = nameof(ListMetatadaRoundtrip)), InlineData("azure"), InlineData("filesystem")] public async Task ListMetatadaRoundtrip(string storeName) { var storageFactory = this.storeFixture.Services.GetRequiredService(); diff --git a/tests/GeekLearning.Storage.Integration.Test/appsettings.json b/tests/GeekLearning.Storage.Integration.Test/appsettings.json index 22a101c..c016376 100644 --- a/tests/GeekLearning.Storage.Integration.Test/appsettings.json +++ b/tests/GeekLearning.Storage.Integration.Test/appsettings.json @@ -15,6 +15,7 @@ "Container": "templates" } } - } + }, + "ExtendedPropertiesFolderNameFormat": ".{0}-extended-properties" } } diff --git a/tests/GeekLearning.Storage.Integration.Test/project.json b/tests/GeekLearning.Storage.Integration.Test/project.json index 5f6f1f5..56f3c44 100644 --- a/tests/GeekLearning.Storage.Integration.Test/project.json +++ b/tests/GeekLearning.Storage.Integration.Test/project.json @@ -27,7 +27,8 @@ "GeekLearning.Storage": "*", "GeekLearning.Storage.Azure": "*", - "GeekLearning.Storage.FileSystem": "*" + "GeekLearning.Storage.FileSystem": "*", + "GeekLearning.Storage.FileSystem.ExtendedProperties.FileSystem": "*" }, "frameworks": { From 2c497d29a7e1b7fe59baf2bc5eda0f1941bbf3bc Mon Sep 17 00:00:00 2001 From: Adrien Siffermann Date: Tue, 10 Jan 2017 12:39:35 +0100 Subject: [PATCH 06/12] Compute ETag on Stream, and add tests for etag --- .../FileSystemStore.cs | 5 ++- .../UpdateTests.cs | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs b/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs index 9916140..32c0fd6 100644 --- a/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs +++ b/src/GeekLearning.Storage.FileSystem/FileSystemStore.cs @@ -201,12 +201,11 @@ private void EnsurePathExists(string path) private static string GenerateEtag(string fileSystemPath) { - var data = File.ReadAllBytes(fileSystemPath); var etag = string.Empty; - + using (var stream = File.Open(fileSystemPath, FileMode.Open, FileAccess.Read)) using (var md5 = MD5.Create()) { - var hash = md5.ComputeHash(data); + var hash = md5.ComputeHash(stream); string hex = BitConverter.ToString(hash); etag = hex.Replace("-", ""); } diff --git a/tests/GeekLearning.Storage.Integration.Test/UpdateTests.cs b/tests/GeekLearning.Storage.Integration.Test/UpdateTests.cs index 254028a..4d5124e 100644 --- a/tests/GeekLearning.Storage.Integration.Test/UpdateTests.cs +++ b/tests/GeekLearning.Storage.Integration.Test/UpdateTests.cs @@ -36,6 +36,37 @@ public async Task WriteAllText(string storeName) Assert.Equal(textToWrite, readFromWrittenFile); } + [Theory(DisplayName = nameof(ETagShouldBeTheSameWithSameContent)), InlineData("azure"), InlineData("filesystem")] + public async Task ETagShouldBeTheSameWithSameContent(string storeName) + { + var storageFactory = this.storeFixture.Services.GetRequiredService(); + + var store = storageFactory.GetStore(storeName); + var textToWrite = "ETag Test Compute"; + var filePath = "Update/etag-same.txt"; + + var savedReference = await store.SaveAsync(Encoding.UTF8.GetBytes(textToWrite), filePath, "text/plain"); + var readReference = await store.GetAsync(filePath, withMetadata: true); + + Assert.Equal(savedReference.Properties.ETag, readReference.Properties.ETag); + } + + [Theory(DisplayName = nameof(ETagShouldBeDifferentWithDifferentContent)), InlineData("azure"), InlineData("filesystem")] + public async Task ETagShouldBeDifferentWithDifferentContent(string storeName) + { + var storageFactory = this.storeFixture.Services.GetRequiredService(); + + var store = storageFactory.GetStore(storeName); + var textToWrite = "ETag Test Compute"; + var filePath = "Update/etag-different.txt"; + var textToUpdate = "ETag Test Compute 2"; + + var savedReference = await store.SaveAsync(Encoding.UTF8.GetBytes(textToWrite), filePath, "text/plain"); + var updatedReference = await store.SaveAsync(Encoding.UTF8.GetBytes(textToUpdate), filePath, "text/plain"); + + Assert.NotEqual(savedReference.Properties.ETag, updatedReference.Properties.ETag); + } + [Theory(DisplayName = nameof(SaveStream)), InlineData("azure"), InlineData("filesystem")] public async Task SaveStream(string storeName) { From 98b68300c290cf0c4f49bbf369e3be2039eed4c9 Mon Sep 17 00:00:00 2001 From: Cyprien Autexier Date: Sun, 5 Feb 2017 02:46:16 +0100 Subject: [PATCH 07/12] add readme pointing to the wiki #32 --- README.md | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c121e78..4673ae7 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,28 @@ # gl-dotnet-storage -Coming Soon! +This library abstracts physical data storage in a way which allows you to transparently switch the underlying provider +by configuration. -#Storage Abstraction +## Features -#FileSystem provider +* List files, with globbing support +* Read, Write, Delete files +* Public file url -#Azure blob provider +## Providers + +The library currently supports: +* Azure Blob Storage +* File System Storage + +We don't support for Amazon S3, but it is one of our high priority objective. + +## Getting Started + +You can head to our introduction [blog post](http://geeklearning.io/dotnet-core-storage-cloud-or-file-system-storage-made-easy/), +or to the [wiki](https://github.com/geeklearningio/gl-dotnet-storage/wiki). + +## Roadmap + +A rough roadmap is available [here(https://github.com/geeklearningio/gl-dotnet-storage/wiki/Roadmap). \ No newline at end of file From add46a7424f8ff52b24ea77cfa015e357bbd1b95 Mon Sep 17 00:00:00 2001 From: Cyprien Autexier Date: Sun, 5 Feb 2017 07:34:59 +0100 Subject: [PATCH 08/12] Support for IStore #26 --- src/GeekLearning.Storage/IStore{TOptions}.cs | 8 ++ .../Internal/GenericStoreProxy.cs | 78 +++++++++++++++++++ src/GeekLearning.Storage/StorageExtensions.cs | 1 + .../GenericIStoreTests.cs | 37 +++++++++ .../StoresFixture.cs | 6 +- .../TestStore.cs | 14 ++++ .../appsettings.json | 6 ++ 7 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 src/GeekLearning.Storage/IStore{TOptions}.cs create mode 100644 src/GeekLearning.Storage/Internal/GenericStoreProxy.cs create mode 100644 tests/GeekLearning.Storage.Integration.Test/GenericIStoreTests.cs create mode 100644 tests/GeekLearning.Storage.Integration.Test/TestStore.cs diff --git a/src/GeekLearning.Storage/IStore{TOptions}.cs b/src/GeekLearning.Storage/IStore{TOptions}.cs new file mode 100644 index 0000000..eefd7bd --- /dev/null +++ b/src/GeekLearning.Storage/IStore{TOptions}.cs @@ -0,0 +1,8 @@ +namespace GeekLearning.Storage +{ + public interface IStore : IStore + where TOptions : class, IStorageStoreOptions, new() + { + + } +} diff --git a/src/GeekLearning.Storage/Internal/GenericStoreProxy.cs b/src/GeekLearning.Storage/Internal/GenericStoreProxy.cs new file mode 100644 index 0000000..acda790 --- /dev/null +++ b/src/GeekLearning.Storage/Internal/GenericStoreProxy.cs @@ -0,0 +1,78 @@ +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace GeekLearning.Storage.Internal +{ + public class GenericStoreProxy : IStore, IStore + where TOptions : class, IStorageStoreOptions, new() + { + private IStore innerStore; + + public GenericStoreProxy(IStorageFactory factory, IOptions options) + { + this.innerStore = factory.GetStore(nameof(TOptions), options.Value); + } + + public string Name + { + get + { + return innerStore.Name; + } + } + + public Task DeleteAsync(IPrivateFileReference file) + { + return innerStore.DeleteAsync(file); + } + + public Task GetAsync(Uri file, bool withMetadata) + { + return innerStore.GetAsync(file, withMetadata); + } + + public Task GetAsync(IPrivateFileReference file, bool withMetadata) + { + return innerStore.GetAsync(file, withMetadata); + } + + public Task ListAsync(string path, bool recursive, bool withMetadata) + { + return innerStore.ListAsync(path, recursive, withMetadata); + } + + public Task ListAsync(string path, string searchPattern, bool recursive, bool withMetadata) + { + return innerStore.ListAsync(path, searchPattern, recursive, withMetadata); + } + + public Task ReadAllBytesAsync(IPrivateFileReference file) + { + return innerStore.ReadAllBytesAsync(file); + } + + public Task ReadAllTextAsync(IPrivateFileReference file) + { + return innerStore.ReadAllTextAsync(file); + } + + public Task ReadAsync(IPrivateFileReference file) + { + return innerStore.ReadAsync(file); + } + + public Task SaveAsync(Stream data, IPrivateFileReference file, string contentType) + { + return innerStore.SaveAsync(data, file, contentType); + } + + public Task SaveAsync(byte[] data, IPrivateFileReference file, string contentType) + { + return innerStore.SaveAsync(data, file, contentType); + } + } +} diff --git a/src/GeekLearning.Storage/StorageExtensions.cs b/src/GeekLearning.Storage/StorageExtensions.cs index e6e5909..7fabe92 100644 --- a/src/GeekLearning.Storage/StorageExtensions.cs +++ b/src/GeekLearning.Storage/StorageExtensions.cs @@ -8,6 +8,7 @@ public static class StorageExtensions public static IServiceCollection AddStorage(this IServiceCollection services) { services.TryAddTransient(); + services.TryAdd(ServiceDescriptor.Transient(typeof(IStore<>), typeof(Internal.GenericStoreProxy<>))); return services; } } diff --git a/tests/GeekLearning.Storage.Integration.Test/GenericIStoreTests.cs b/tests/GeekLearning.Storage.Integration.Test/GenericIStoreTests.cs new file mode 100644 index 0000000..94299db --- /dev/null +++ b/tests/GeekLearning.Storage.Integration.Test/GenericIStoreTests.cs @@ -0,0 +1,37 @@ +namespace GeekLearning.Storage.Integration.Test +{ + using Microsoft.Extensions.DependencyInjection; + using Storage; + using System.Linq; + using System.Threading.Tasks; + using Xunit; + + [Collection(nameof(IntegrationCollection))] + [Trait("Kind", "Integration")] + public class GenericIStoreTests + { + private StoresFixture storeFixture; + + public GenericIStoreTests(StoresFixture fixture) + { + this.storeFixture = fixture; + } + + [Fact] + public async Task GenericListRootFiles() + { + var store = this.storeFixture.Services.GetRequiredService>(); + + var expected = new string[] { "TextFile.txt", "template.hbs" }; + + var results = await store.ListAsync(null); + + var missingFiles = expected.Except(results.Select(f => f.Path)).ToArray(); + + var unexpectedFiles = results.Select(f => f.Path).Except(expected).ToArray(); + + Assert.Empty(missingFiles); + Assert.Empty(unexpectedFiles); + } + } +} diff --git a/tests/GeekLearning.Storage.Integration.Test/StoresFixture.cs b/tests/GeekLearning.Storage.Integration.Test/StoresFixture.cs index 4787584..19e3e75 100644 --- a/tests/GeekLearning.Storage.Integration.Test/StoresFixture.cs +++ b/tests/GeekLearning.Storage.Integration.Test/StoresFixture.cs @@ -20,12 +20,15 @@ public StoresFixture() { this.BasePath = PlatformServices.Default.Application.ApplicationBasePath; + var containerId = Guid.NewGuid().ToString("N").ToLower(); + var builder = new ConfigurationBuilder() .SetBasePath(BasePath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.development.json", optional: true) .AddInMemoryCollection(new KeyValuePair[] { - new KeyValuePair("Storage:Stores:azure:Parameters:Container", Guid.NewGuid().ToString("N").ToLower()) + new KeyValuePair("Storage:Stores:azure:Parameters:Container", containerId), + new KeyValuePair("TestStore:Parameters:Container", containerId) }); this.Configuration = builder.Build(); @@ -40,6 +43,7 @@ public StoresFixture() .AddFileSystemExtendedProperties(o => { }); services.Configure(Configuration.GetSection("Storage")); + services.Configure(Configuration.GetSection("TestStore")); this.Services = services.BuildServiceProvider(); diff --git a/tests/GeekLearning.Storage.Integration.Test/TestStore.cs b/tests/GeekLearning.Storage.Integration.Test/TestStore.cs new file mode 100644 index 0000000..701237e --- /dev/null +++ b/tests/GeekLearning.Storage.Integration.Test/TestStore.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace GeekLearning.Storage.Integration.Test +{ + public class TestStore : IStorageStoreOptions + { + public string Provider { get; set; } + + public Dictionary Parameters { get; set; } + } +} diff --git a/tests/GeekLearning.Storage.Integration.Test/appsettings.json b/tests/GeekLearning.Storage.Integration.Test/appsettings.json index c016376..7b59261 100644 --- a/tests/GeekLearning.Storage.Integration.Test/appsettings.json +++ b/tests/GeekLearning.Storage.Integration.Test/appsettings.json @@ -17,5 +17,11 @@ } }, "ExtendedPropertiesFolderNameFormat": ".{0}-extended-properties" + }, + "TestStore": { + "Provider": "FileSystem", + "Parameters": { + "Path": "Templates" + } } } From 7528a1c30c9c58b61c7ba4eea7c8c3479efce04a Mon Sep 17 00:00:00 2001 From: Cyprien Autexier Date: Sun, 5 Feb 2017 07:43:33 +0100 Subject: [PATCH 09/12] delete developement settings --- .../appsettings.development.json | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 tests/GeekLearning.Storage.Integration.Test/appsettings.development.json diff --git a/tests/GeekLearning.Storage.Integration.Test/appsettings.development.json b/tests/GeekLearning.Storage.Integration.Test/appsettings.development.json deleted file mode 100644 index 739585f..0000000 --- a/tests/GeekLearning.Storage.Integration.Test/appsettings.development.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "Storage": { - "Stores": { - "filesystem": { - "Provider": "FileSystem", - "Parameters": { - "Path": "Templates" - } - }, - "azure": { - "Provider": "Azure", - "Parameters": { - "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=glstoragetests;AccountKey=91+UllcfvxK/ghaN3tFUD6/QJZ7t/A4hL0vN9ha587syUxcD3SzCmYuAybBcwbwx77NjV+4/1WXqFTlwwxdA5Q==;", - "Container": "templates" - } - } - } - } -} \ No newline at end of file From e1379985ba1816b3c511ab22e8807d9dbc3c19b4 Mon Sep 17 00:00:00 2001 From: Cyprien Autexier Date: Sun, 5 Feb 2017 07:44:47 +0100 Subject: [PATCH 10/12] gitignore dev file --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a7f4a50..6288930 100644 --- a/.gitignore +++ b/.gitignore @@ -243,4 +243,4 @@ ModelManifest.xml # FAKE - F# Make .fake/ -/tests/GeekLearning.Integration.Test/appsettings.development.json +/tests/GeekLearning.Storage.Integration.Test/appsettings.development.json From 2e4416df9fb7279373c1a85fc58bd997135b1dda Mon Sep 17 00:00:00 2001 From: Adrien Siffermann Date: Mon, 6 Feb 2017 10:52:57 +0100 Subject: [PATCH 11/12] CR --- .gitignore | 2 +- src/GeekLearning.Storage/IStore{TOptions}.cs | 1 - .../Internal/GenericStoreProxy.cs | 14 ++++++-------- .../TestStore.cs | 9 +++------ 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 6288930..0df7221 100644 --- a/.gitignore +++ b/.gitignore @@ -243,4 +243,4 @@ ModelManifest.xml # FAKE - F# Make .fake/ -/tests/GeekLearning.Storage.Integration.Test/appsettings.development.json +appsettings.development.json diff --git a/src/GeekLearning.Storage/IStore{TOptions}.cs b/src/GeekLearning.Storage/IStore{TOptions}.cs index eefd7bd..709f787 100644 --- a/src/GeekLearning.Storage/IStore{TOptions}.cs +++ b/src/GeekLearning.Storage/IStore{TOptions}.cs @@ -3,6 +3,5 @@ public interface IStore : IStore where TOptions : class, IStorageStoreOptions, new() { - } } diff --git a/src/GeekLearning.Storage/Internal/GenericStoreProxy.cs b/src/GeekLearning.Storage/Internal/GenericStoreProxy.cs index acda790..228bea9 100644 --- a/src/GeekLearning.Storage/Internal/GenericStoreProxy.cs +++ b/src/GeekLearning.Storage/Internal/GenericStoreProxy.cs @@ -1,12 +1,10 @@ -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; - -namespace GeekLearning.Storage.Internal +namespace GeekLearning.Storage.Internal { + using Microsoft.Extensions.Options; + using System; + using System.IO; + using System.Threading.Tasks; + public class GenericStoreProxy : IStore, IStore where TOptions : class, IStorageStoreOptions, new() { diff --git a/tests/GeekLearning.Storage.Integration.Test/TestStore.cs b/tests/GeekLearning.Storage.Integration.Test/TestStore.cs index 701237e..1df5a25 100644 --- a/tests/GeekLearning.Storage.Integration.Test/TestStore.cs +++ b/tests/GeekLearning.Storage.Integration.Test/TestStore.cs @@ -1,10 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace GeekLearning.Storage.Integration.Test +namespace GeekLearning.Storage.Integration.Test { + using System.Collections.Generic; + public class TestStore : IStorageStoreOptions { public string Provider { get; set; } From 2629260327f72a8bab7001c45de4cad924ba8320 Mon Sep 17 00:00:00 2001 From: Sandor Date: Thu, 9 Feb 2017 05:52:21 +0100 Subject: [PATCH 12/12] Update README.md Remove roadmap from the readme, as it will be managed with milestones. --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 4673ae7..920c59c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![NuGet Version](http://img.shields.io/nuget/v/GeekLearning.Storage.Azure.svg?style=flat-square&label=nuget:%20azure%20 storage)](https://www.nuget.org/packages/GeekLearning.Storage.Azure/) [![Build Status](https://geeklearning.visualstudio.com/_apis/public/build/definitions/f841b266-7595-4d01-9ee1-4864cf65aa73/27/badge)](#) -# gl-dotnet-storage +# Geek Learning Cloud Storage Abstraction This library abstracts physical data storage in a way which allows you to transparently switch the underlying provider by configuration. @@ -26,7 +26,3 @@ We don't support for Amazon S3, but it is one of our high priority objective. You can head to our introduction [blog post](http://geeklearning.io/dotnet-core-storage-cloud-or-file-system-storage-made-easy/), or to the [wiki](https://github.com/geeklearningio/gl-dotnet-storage/wiki). - -## Roadmap - -A rough roadmap is available [here(https://github.com/geeklearningio/gl-dotnet-storage/wiki/Roadmap). \ No newline at end of file