Use virtual file provider to read embedded localization jsons.

pull/183/head
Halil İbrahim Kalkan 8 years ago
parent f1aa006403
commit 12e38bf7e0

@ -11,24 +11,25 @@ namespace Microsoft.AspNetCore.Builder
{
public static void UseVirtualFiles(this IApplicationBuilder app)
{
var options = app.ApplicationServices.GetRequiredService<IOptions<VirtualFileSystemOptions>>().Value;
//var options = app.ApplicationServices.GetRequiredService<IOptions<VirtualFileSystemOptions>>().Value;
IFileProvider fileProvider = new AspNetCoreVirtualFileProvider(
app.ApplicationServices,
"/wwwroot"
);
if (options.FileSets.PhysicalPaths.Any())
{
var fileProviders = options.FileSets.PhysicalPaths
.Select(p => new PhysicalFileProvider(p))
.Cast<IFileProvider>()
.ToList();
////TODO: This should not be needed!!!
//if (options.FileSets.PhysicalPaths.Any())
//{
// var fileProviders = options.FileSets.PhysicalPaths
// .Select(p => new PhysicalFileProvider(p))
// .Cast<IFileProvider>()
// .ToList();
fileProviders.Add(fileProvider);
// fileProviders.Add(fileProvider);
fileProvider = new CompositeFileProvider(fileProviders);
}
// fileProvider = new CompositeFileProvider(fileProviders);
//}
app.UseStaticFiles(
new StaticFileOptions

@ -1,7 +1,7 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Localization.Resource;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Localization.Resources.AbpBootstrap;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
@ -22,7 +22,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap
services.Configure<AbpLocalizationOptions>(options =>
{
options.Resources.AddJson<AbpBootstrapResource>("en");
options.Resources.AddVirtualJson<AbpBootstrapResource>("en", "/Localization/Resources/AbpBootstrap");
});
services.Configure<BundlingOptions>(options =>

@ -1,4 +1,4 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Localization.Resource
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Localization.Resources.AbpBootstrap
{
public class AbpBootstrapResource
{

@ -1,7 +1,7 @@
using System.Text;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Localization.Resource;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Localization.Resources.AbpBootstrap;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
{

@ -10,101 +10,18 @@
</PropertyGroup>
<ItemGroup>
<None Remove="Localization\Resource\en.json" />
<None Remove="Localization\Resource\tr.json" />
</ItemGroup>
<ItemGroup>
<Content Include="Localization\Resource\tr.json">
<Content Include="Localization\Resources\AbpBootstrap\tr.json">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="Localization\Resource\en.json">
<Content Include="Localization\Resources\AbpBootstrap\en.json">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\Resource\*.json" />
<EmbeddedResource Include="Views\Shared\Components\AbpMenu\Default.cshtml" />
<EmbeddedResource Include="Views\Shared\_AppLayout.cshtml" />
<EmbeddedResource Include="wwwroot\libs\datatables\datatables.css" />
<EmbeddedResource Include="wwwroot\libs\datatables\datatables.js" />
<EmbeddedResource Include="wwwroot\libs\datatables\datatables.min.css" />
<EmbeddedResource Include="wwwroot\libs\datatables\datatables.min.js" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Afrikaans.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Albanian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Arabic.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Armenian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Azerbaijan.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Bangla.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Basque.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Belarusian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Bulgarian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Catalan.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Chinese (Simplified, China).json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Chinese-traditional.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Croatian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Czech.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Danish.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Dutch.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\English.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Estonian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Filipino.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Finnish.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\French.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Galician.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Georgian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\German.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Greek.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Gujarati.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Hebrew.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Hindi.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Hungarian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Icelandic.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Indonesian-Alternative.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Indonesian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Irish.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Italian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Japanese.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Kazakh.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Korean.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Kyrgyz.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Latvian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Lithuanian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Macedonian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Malay.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Mongolian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Nepali.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Norwegian-Bokmal.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Norwegian-Nynorsk.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Pashto.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Persian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Polish.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Portuguese (Brazil).json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Portuguese.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Romanian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Russian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Serbian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Sinhala.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Slovak.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Slovenian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Spanish.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Swahili.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Swedish.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Tamil.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\telugu.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Thai.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Turkish.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Ukrainian.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Urdu.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Uzbek.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Vietnamese.json" />
<EmbeddedResource Include="wwwroot\libs\datatables\localizations\Welsh.json" />
<EmbeddedResource Include="wwwroot\views\shared\_AppLayout.css" />
<EmbeddedResource Include="Views\Shared\_ViewImports.cshtml" />
<EmbeddedResource Include="wwwroot\libs\jquery\jquery-3.1.1.js" />
<EmbeddedResource Include="wwwroot\libs\jquery\jquery-3.1.1.min.js" />
<EmbeddedResource Include="wwwroot\libs\jquery\jquery-3.1.1.min.map" />
<EmbeddedResource Include="Localization\Resources\**\*.json" />
<EmbeddedResource Include="Views\**\*.cshtml" />
<EmbeddedResource Include="wwwroot\**\*.*" />
</ItemGroup>
<ItemGroup>

@ -19,8 +19,6 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Composite" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Routing.Abstractions" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.0.0" />

@ -1,8 +1,6 @@
using System;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Volo.Abp.DependencyInjection;
using Volo.Abp.VirtualFileSystem;
@ -24,28 +22,8 @@ namespace Volo.Abp.AspNetCore.VirtualFileSystem
public AspNetCoreVirtualFileProvider(IObjectAccessor<IServiceProvider> serviceProviderAccessor)
{
_serviceProviderAccessor = serviceProviderAccessor;
_fileProvider = new Lazy<IFileProvider>(
() =>
{
var options = serviceProviderAccessor.Value.GetRequiredService<IOptions<VirtualFileSystemOptions>>().Value;
IFileProvider fileProvider = serviceProviderAccessor.Value.GetRequiredService<IVirtualFileProvider>();
if (options.FileSets.PhysicalPaths.Any())
{
var fileProviders = options.FileSets.PhysicalPaths
.Select(p => new PhysicalFileProvider(p))
.Cast<IFileProvider>()
.ToList();
fileProviders.Add(fileProvider);
fileProvider = new CompositeFileProvider(fileProviders);
}
return fileProvider;
},
() => serviceProviderAccessor.Value.GetRequiredService<IVirtualFileProvider>(),
true
);
}

@ -2,7 +2,7 @@
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap;
using Volo.Abp.AutoMapper;
using Volo.Abp.Identity.Web.Localization.Resource;
using Volo.Abp.Identity.Web.Localization.Resources.AbpIdentity;
using Volo.Abp.Identity.Web.Navigation;
using Volo.Abp.Identity.Web.ObjectMappings;
using Volo.Abp.Localization;
@ -41,7 +41,8 @@ namespace Volo.Abp.Identity.Web
services.Configure<AbpLocalizationOptions>(options =>
{
options.Resources.AddJson<IdentityResource>("en");
//options.Resources.AddVirtual<IdentityResource>("en");
options.Resources.AddVirtualJson<IdentityResource>("en", "/Localization/Resources/AbpIdentity");
});
services.Configure<AbpAutoMapperOptions>(options =>

@ -1,12 +0,0 @@
using Volo.Abp.Localization;
using Volo.Abp.Localization.Resources.Validation;
namespace Volo.Abp.Identity.Web.Localization.Resource
{
[ShortLocalizationResourceName("AbpIdentity")]
[InheritResource(typeof(AbpValidationResource))]
public class IdentityResource
{
}
}

@ -0,0 +1,12 @@
using Volo.Abp.Localization;
using Volo.Abp.Localization.Resources.AbpValidation;
namespace Volo.Abp.Identity.Web.Localization.Resources.AbpIdentity
{
[ShortLocalizationResourceName("AbpIdentity")]
[InheritResource(typeof(AbpValidationResource))]
public class IdentityResource //TODO: Rename to AbpIdentityResource
{
}
}

@ -1,6 +1,6 @@
@page
@using Microsoft.Extensions.Localization
@using Volo.Abp.Identity.Web.Localization.Resource
@using Volo.Abp.Identity.Web.Localization.Resources.AbpIdentity
@model Volo.Abp.Identity.Web.Pages.Identity.Users.CreateModalModel
@inject IStringLocalizer<IdentityResource> L
@{

@ -1,6 +1,6 @@
@page
@using Microsoft.Extensions.Localization
@using Volo.Abp.Identity.Web.Localization.Resource
@using Volo.Abp.Identity.Web.Localization.Resources.AbpIdentity
@model Volo.Abp.Identity.Web.Pages.Identity.Users.EditModalModel
@inject IStringLocalizer<IdentityResource> L
@{

@ -1,7 +1,7 @@
@page
@model Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Abp.Identity.Web.Localization.Resource
@using Volo.Abp.Identity.Web.Localization.Resources.AbpIdentity
@inject IHtmlLocalizer<IdentityResource> L
@section styles {
<link rel="stylesheet" type="text/css" href="~/modules/identity/views/users/index.css" />

@ -13,7 +13,7 @@
<ItemGroup>
<EmbeddedResource Include="wwwroot\**\*.*" />
<EmbeddedResource Include="Pages\**\*.cshtml" />
<EmbeddedResource Include="Localization\Resource\*.json" />
<EmbeddedResource Include="Localization\Resources\**\*.json" />
</ItemGroup>
<ItemGroup>
@ -27,7 +27,7 @@
<None Remove="wwwroot\modules\identity\helpers\datatables_helper.js" />
<None Remove="wwwroot\modules\identity\helpers\jquery.js" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.csproj" />
<ProjectReference Include="..\Volo.Abp.Identity.Application.Contracts\Volo.Abp.Identity.Application.Contracts.csproj" />

@ -19,6 +19,7 @@
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Core\Volo.Abp.Core.csproj" />
<ProjectReference Include="..\Volo.Abp.VirtualFileSystem\Volo.Abp.VirtualFileSystem.csproj" />
</ItemGroup>
</Project>

@ -1,18 +1,25 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Localization.Resources.Validation;
using Volo.Abp.Localization.Resources.AbpValidation;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.Localization
{
[DependsOn(typeof(AbpVirtualFileSystemModule))]
public class AbpLocalizationModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
AbpStringLocalizerFactory.Replace(services);
services.Configure<VirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpLocalizationModule>("Volo.Abp", "Volo/Abp");
});
services.Configure<AbpLocalizationOptions>(options =>
{
options.Resources.AddJson<AbpValidationResource>("en");
options.Resources.AddVirtualJson<AbpValidationResource>("en", "/Localization/Resources/AbpValidation");
});
services.AddAssemblyOf<AbpLocalizationModule>();

@ -1,50 +0,0 @@
using System.Reflection;
using Volo.Abp.Internal;
namespace Volo.Abp.Localization.Json
{
/// <summary>
/// Provides localization dictionaries from JSON files embedded into an <see cref="Assembly"/>.
/// </summary>
public class JsonEmbeddedFileLocalizationDictionaryProvider : LocalizationDictionaryProviderBase
{
private readonly Assembly _assembly;
private readonly string _rootNamespace;
public JsonEmbeddedFileLocalizationDictionaryProvider(Assembly assembly, string rootNamespace)
{
_assembly = assembly;
_rootNamespace = rootNamespace;
}
public override void Initialize(LocalizationResourceInitializationContext context) //TODO: Extract initialization to a factory..?
{
var rootNameSpaceWithDot = _rootNamespace + ".";
var resourceNames = _assembly.GetManifestResourceNames();
foreach (var resourceName in resourceNames)
{
if (resourceName.StartsWith(rootNameSpaceWithDot))
{
using (var stream = _assembly.GetManifestResourceStream(resourceName))
{
var jsonString = Utf8Helper.ReadStringFromStream(stream);
var dictionary = CreateJsonLocalizationDictionary(jsonString);
if (Dictionaries.ContainsKey(dictionary.CultureName))
{
throw new AbpException($"{resourceName} dictionary has a culture name '{dictionary.CultureName}' which is already defined!");
}
Dictionaries[dictionary.CultureName] = dictionary;
}
}
}
}
protected virtual ILocalizationDictionary CreateJsonLocalizationDictionary(string jsonString)
{
return JsonLocalizationDictionaryBuilder.BuildFromJsonString(jsonString);
}
}
}

@ -1,15 +1,23 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.Abp.Localization.Json;
using Volo.Abp.Localization.VirtualFiles.Json;
namespace Volo.Abp.Localization
{
public static class LocalizationResourceListExtensions
{
public static LocalizationResource AddJson<TResource>([NotNull] this LocalizationResourceDictionary resourceDictionary, [NotNull] string defaultCultureName)
public static LocalizationResource AddVirtualJson<TResource>(
[NotNull] this LocalizationResourceDictionary resourceDictionary,
[NotNull] string defaultCultureName,
[NotNull] string virtualPath)
{
Check.NotNull(resourceDictionary, nameof(resourceDictionary));
Check.NotNull(defaultCultureName, nameof(defaultCultureName));
Check.NotNull(virtualPath, nameof(virtualPath));
virtualPath = virtualPath.EnsureStartsWith('/');
var resourceType = typeof(TResource);
@ -22,18 +30,18 @@ namespace Volo.Abp.Localization
resourceType,
defaultCultureName,
new JsonEmbeddedFileLocalizationDictionaryProvider(
resourceType.Assembly,
resourceType.Namespace
virtualPath
)
);
}
public static void ExtendWithJson<TResource, TResourceExt>([NotNull] this LocalizationResourceDictionary resourceDictionary)
public static void ExtendWithVirtualJson<TResource>(
[NotNull] this LocalizationResourceDictionary resourceDictionary,
[NotNull] string virtualPath)
{
Check.NotNull(resourceDictionary, nameof(resourceDictionary));
var resourceType = typeof(TResource);
var resourceExtType = typeof(TResourceExt);
var resource = resourceDictionary.GetOrDefault(resourceType);
if (resource == null)
@ -42,8 +50,7 @@ namespace Volo.Abp.Localization
}
resource.Extensions.Add(new JsonEmbeddedFileLocalizationDictionaryProvider(
resourceExtType.Assembly,
resourceExtType.Namespace
virtualPath
));
}
}

@ -1,4 +1,4 @@
namespace Volo.Abp.Localization.Resources.Validation
namespace Volo.Abp.Localization.Resources.AbpValidation
{
[ShortLocalizationResourceName("AbpValidation")]
public class AbpValidationResource

@ -0,0 +1,25 @@
using Microsoft.Extensions.FileProviders;
using System;
using Volo.Abp.Localization.Json;
namespace Volo.Abp.Localization.VirtualFiles.Json
{
public class JsonEmbeddedFileLocalizationDictionaryProvider : VirtualFileLocalizationDictionaryProviderBase
{
public JsonEmbeddedFileLocalizationDictionaryProvider(string virtualPath)
: base(virtualPath)
{
}
protected override bool CanParseFile(IFileInfo file)
{
return file.Name.EndsWith(".json", StringComparison.OrdinalIgnoreCase);
}
protected override ILocalizationDictionary CreateDictionary(string jsonString)
{
return JsonLocalizationDictionaryBuilder.BuildFromJsonString(jsonString); //TODO: Use composition over inheritance!
}
}
}

@ -0,0 +1,48 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Volo.Abp.Internal;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.Localization.VirtualFiles
{
public abstract class VirtualFileLocalizationDictionaryProviderBase : LocalizationDictionaryProviderBase
{
private readonly string _virtualPath;
protected VirtualFileLocalizationDictionaryProviderBase(string virtualPath)
{
_virtualPath = virtualPath;
}
public override void Initialize(LocalizationResourceInitializationContext context) //TODO: Extract initialization to a factory..?
{
var virtualFileProvider = context.ServiceProvider.GetRequiredService<IVirtualFileProvider>();
var directoryContents = virtualFileProvider.GetDirectoryContents(_virtualPath);
foreach (var file in directoryContents)
{
if (file.IsDirectory || !CanParseFile(file))
{
continue;
}
using (var stream = file.CreateReadStream())
{
var fileContent = Utf8Helper.ReadStringFromStream(stream);
var dictionary = CreateDictionary(fileContent);
if (Dictionaries.ContainsKey(dictionary.CultureName))
{
throw new AbpException($"{file.PhysicalPath} dictionary has a culture name '{dictionary.CultureName}' which is already defined!");
}
Dictionaries[dictionary.CultureName] = dictionary;
}
}
}
protected abstract bool CanParseFile(IFileInfo file);
protected abstract ILocalizationDictionary CreateDictionary(string fileContent);
}
}

@ -14,6 +14,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Composite" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="2.0.0" />
</ItemGroup>

@ -19,7 +19,10 @@ namespace Volo.Abp.VirtualFileSystem.Embedded
[CanBeNull]
public string BaseFolderInProject { get; }
public EmbeddedFileSet([NotNull] Assembly assembly, [CanBeNull] string baseNamespace, [CanBeNull] string baseFolderInProject = null)
public EmbeddedFileSet(
[NotNull] Assembly assembly,
[CanBeNull] string baseNamespace,
[CanBeNull] string baseFolderInProject = null)
{
Check.NotNull(assembly, nameof(assembly));

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
@ -9,80 +10,126 @@ namespace Volo.Abp.VirtualFileSystem
{
public class VirtualFileProvider : IVirtualFileProvider, ISingletonDependency
{
private readonly IFileProvider _fileProvider;
private readonly VirtualFileSystemOptions _options;
private readonly Lazy<Dictionary<string, IFileInfo>> _files;
public VirtualFileProvider(IOptions<VirtualFileSystemOptions> options)
{
_options = options.Value;
_files = new Lazy<Dictionary<string, IFileInfo>>(
CreateResourcesDictionary,
true
);
_fileProvider = CreateHybridProvider();
}
public IFileInfo GetFileInfo(string subpath)
{
if (string.IsNullOrEmpty(subpath))
{
return new NotFoundFileInfo(subpath);
}
return _fileProvider.GetFileInfo(subpath);
}
public IDirectoryContents GetDirectoryContents(string subpath)
{
return _fileProvider.GetDirectoryContents(subpath);
}
public IChangeToken Watch(string filter)
{
return _fileProvider.Watch(filter);
}
var file = _files.Value.GetOrDefault(VirtualFilePathHelper.NormalizePath(subpath));
private IFileProvider CreateHybridProvider()
{
IFileProvider fileProvider = new InternalVirtualFileProvider(_options);
if (file == null)
if (_options.FileSets.PhysicalPaths.Any())
{
return new NotFoundFileInfo(subpath);
var fileProviders = _options.FileSets.PhysicalPaths
.Select(p => new PhysicalFileProvider(p))
.Cast<IFileProvider>()
.ToList();
fileProviders.Add(fileProvider);
fileProvider = new CompositeFileProvider(fileProviders);
}
return file;
return fileProvider;
}
public IDirectoryContents GetDirectoryContents(string subpath)
private class InternalVirtualFileProvider : IFileProvider
{
var directory = GetFileInfo(subpath);
if (!directory.IsDirectory)
private readonly VirtualFileSystemOptions _options;
private readonly Lazy<Dictionary<string, IFileInfo>> _files;
public InternalVirtualFileProvider(VirtualFileSystemOptions options)
{
return new NotFoundDirectoryContents();
_options = options;
_files = new Lazy<Dictionary<string, IFileInfo>>(
CreateResourcesDictionary,
true
);
}
var fileList = new List<IFileInfo>();
var directoryPath = subpath + "/";
foreach (var fileInfo in _files.Value.Values)
public IFileInfo GetFileInfo(string subpath)
{
if (!fileInfo.PhysicalPath.StartsWith(directoryPath))
if (string.IsNullOrEmpty(subpath))
{
continue;
return new NotFoundFileInfo(subpath);
}
var relativePath = fileInfo.PhysicalPath.Substring(directoryPath.Length);
if (relativePath.Contains("/"))
var file = _files.Value.GetOrDefault(VirtualFilePathHelper.NormalizePath(subpath));
if (file == null)
{
continue;
return new NotFoundFileInfo(subpath);
}
fileList.Add(fileInfo);
return file;
}
return new EnumerableDirectoryContents(fileList);
}
public IDirectoryContents GetDirectoryContents(string subpath)
{
var directory = GetFileInfo(subpath);
if (!directory.IsDirectory)
{
return new NotFoundDirectoryContents();
}
public IChangeToken Watch(string filter)
{
return NullChangeToken.Singleton;
}
var fileList = new List<IFileInfo>();
private Dictionary<string, IFileInfo> CreateResourcesDictionary()
{
var files = new Dictionary<string, IFileInfo>(StringComparer.OrdinalIgnoreCase);
var directoryPath = subpath.EnsureEndsWith('/');
foreach (var fileInfo in _files.Value.Values)
{
if (!fileInfo.PhysicalPath.StartsWith(directoryPath))
{
continue;
}
var relativePath = fileInfo.PhysicalPath.Substring(directoryPath.Length);
if (relativePath.Contains("/"))
{
continue;
}
fileList.Add(fileInfo);
}
return new EnumerableDirectoryContents(fileList);
}
foreach (var set in _options.FileSets)
public IChangeToken Watch(string filter)
{
set.AddFiles(files);
return NullChangeToken.Singleton;
}
return files;
private Dictionary<string, IFileInfo> CreateResourcesDictionary()
{
var files = new Dictionary<string, IFileInfo>(StringComparer.OrdinalIgnoreCase);
foreach (var set in _options.FileSets)
{
set.AddFiles(files);
}
return files;
}
}
}
}

@ -8,14 +8,15 @@ namespace Volo.Abp.VirtualFileSystem
{
public static class VirtualFileSetListExtensions
{
public static void AddEmbedded<T>([NotNull] this VirtualFileSetList list, [CanBeNull] string baseNamespace = null)
public static void AddEmbedded<T>([NotNull] this VirtualFileSetList list, [CanBeNull] string baseNamespace = null, string baseFolderInProject = null)
{
Check.NotNull(list, nameof(list));
list.Add(
new EmbeddedFileSet(
typeof(T).Assembly,
baseNamespace
baseNamespace,
baseFolderInProject
)
);
}

@ -2,12 +2,12 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Shouldly;
using Volo.Abp.Localization.Base.CountryNames;
using Volo.Abp.Localization.Base.Validation;
using Volo.Abp.Localization.Source;
using Volo.Abp.Localization.SourceExt;
using Volo.Abp.Localization.TestResources.Base.CountryNames;
using Volo.Abp.Localization.TestResources.Base.Validation;
using Volo.Abp.Localization.TestResources.Source;
using Volo.Abp.Modularity;
using Volo.Abp.TestBase;
using Volo.Abp.VirtualFileSystem;
using Xunit;
namespace Volo.Abp.Localization
@ -109,12 +109,17 @@ namespace Volo.Abp.Localization
{
public override void ConfigureServices(IServiceCollection services)
{
services.Configure<VirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<TestModule>();
});
services.Configure<AbpLocalizationOptions>(options =>
{
options.Resources.AddJson<LocalizationTestValidationResource>("en");
options.Resources.AddJson<LocalizationTestCountryNamesResource>("en");
options.Resources.AddJson<LocalizationTestResource>("en");
options.Resources.ExtendWithJson<LocalizationTestResource, LocalizationTestResourceExt>();
options.Resources.AddVirtualJson<LocalizationTestValidationResource>("en", "/Volo/Abp/Localization/TestResources/Base/Validation");
options.Resources.AddVirtualJson<LocalizationTestCountryNamesResource>("en", "/Volo/Abp/Localization/TestResources/Base/CountryNames");
options.Resources.AddVirtualJson<LocalizationTestResource>("en", "/Volo/Abp/Localization/TestResources/Source");
options.Resources.ExtendWithVirtualJson<LocalizationTestResource>("/Volo/Abp/Localization/TestResources/SourceExt");
});
}
}

@ -1,7 +0,0 @@
namespace Volo.Abp.Localization.SourceExt
{
internal sealed class LocalizationTestResourceExt
{
}
}

@ -1,4 +1,4 @@
namespace Volo.Abp.Localization.Base.CountryNames
namespace Volo.Abp.Localization.TestResources.Base.CountryNames
{
public sealed class LocalizationTestCountryNamesResource
{

@ -1,4 +1,4 @@
namespace Volo.Abp.Localization.Base.Validation
namespace Volo.Abp.Localization.TestResources.Base.Validation
{
public sealed class LocalizationTestValidationResource
{

@ -1,7 +1,7 @@
using Volo.Abp.Localization.Base.CountryNames;
using Volo.Abp.Localization.Base.Validation;
using Volo.Abp.Localization.TestResources.Base.CountryNames;
using Volo.Abp.Localization.TestResources.Base.Validation;
namespace Volo.Abp.Localization.Source
namespace Volo.Abp.Localization.TestResources.Source
{
[InheritResource(typeof(LocalizationTestValidationResource))]
[InheritResource(typeof(LocalizationTestCountryNamesResource))]
Loading…
Cancel
Save