mirror of https://github.com/abpframework/abp.git
50 changed files with 658 additions and 401 deletions
@ -1,14 +0,0 @@ |
|||
using AbpDesk.Web.Mvc.Temp; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace AbpDesk.Web.Mvc.Controllers |
|||
{ |
|||
public class HomeController : AbpController |
|||
{ |
|||
public IActionResult Index(MyClassToTestAutofacCustomRegistration obj) |
|||
{ |
|||
return View(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
@page |
|||
@model AbpDesk.Web.Mvc.Pages.IndexModel |
|||
<h2>Home page!</h2> |
|||
@ -0,0 +1,12 @@ |
|||
using Microsoft.AspNetCore.Mvc.RazorPages; |
|||
|
|||
namespace AbpDesk.Web.Mvc.Pages |
|||
{ |
|||
public class IndexModel : PageModel |
|||
{ |
|||
public void OnGet() |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,4 @@ |
|||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap |
|||
@addTagHelper *, AbpDesk.Web.Mvc |
|||
@ -0,0 +1,4 @@ |
|||
@{ |
|||
//TODO: Move this to ~/Pages/Abp/_AppLayout.cshtml..? |
|||
Layout = "~/Views/Shared/_AppLayout.cshtml"; |
|||
} |
|||
@ -1,7 +0,0 @@ |
|||
namespace AbpDesk.Web.Mvc.Temp |
|||
{ |
|||
/* Will be removed later */ |
|||
public class MyClassToTestAutofacCustomRegistration |
|||
{ |
|||
} |
|||
} |
|||
@ -1 +0,0 @@ |
|||
<h2>Home</h2> |
|||
Binary file not shown.
@ -1,16 +1,17 @@ |
|||
using Volo.Abp.AspNetCore.EmbeddedFiles; |
|||
using Volo.Abp.AspNetCore.VirtualFileSystem; |
|||
|
|||
namespace Microsoft.AspNetCore.Builder |
|||
{ |
|||
public static class EmbeddedFilesApplicationBuilderExtensions |
|||
public static class VirtualFileSystemApplicationBuilderExtensions |
|||
{ |
|||
public static void UseEmbeddedFiles(this IApplicationBuilder app) |
|||
public static void UseVirtualFiles(this IApplicationBuilder app) |
|||
{ |
|||
//TODO: Can improve it or create a custom middleware?
|
|||
app.UseStaticFiles( |
|||
new StaticFileOptions |
|||
{ |
|||
FileProvider = new EmbeddedResourceFileProvider( |
|||
FileProvider = new AspNetCoreVirtualFileProvider( |
|||
app.ApplicationServices |
|||
) |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using System; |
|||
using Volo.Abp.AspNetCore.VirtualFileSystem; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.VirtualFileSystem |
|||
{ |
|||
//TODO: Move to Volo.Abp.AspNetCore.Mvc project!
|
|||
public class AspNetCoreVirtualViewFileProvider : AspNetCoreVirtualFileProvider |
|||
{ |
|||
public AspNetCoreVirtualViewFileProvider(IObjectAccessor<IServiceProvider> serviceProviderAccessor) |
|||
: base(serviceProviderAccessor) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,34 +0,0 @@ |
|||
using System; |
|||
using System.IO; |
|||
using Microsoft.Extensions.FileProviders; |
|||
using Volo.Abp.EmbeddedFiles; |
|||
|
|||
namespace Volo.Abp.AspNetCore.EmbeddedFiles |
|||
{ |
|||
public class EmbeddedResourceItemFileInfo : IFileInfo |
|||
{ |
|||
public bool Exists => true; |
|||
|
|||
public long Length => _fileInfo.Content.Length; |
|||
|
|||
public string PhysicalPath => null; |
|||
|
|||
public string Name => _fileInfo.FileName; |
|||
|
|||
public DateTimeOffset LastModified => _fileInfo.LastModifiedUtc; |
|||
|
|||
public bool IsDirectory => false; |
|||
|
|||
private readonly EmbeddedFileInfo _fileInfo; |
|||
|
|||
public EmbeddedResourceItemFileInfo(EmbeddedFileInfo fileInfo) |
|||
{ |
|||
_fileInfo = fileInfo; |
|||
} |
|||
|
|||
public Stream CreateReadStream() |
|||
{ |
|||
return new MemoryStream(_fileInfo.Content); |
|||
} |
|||
} |
|||
} |
|||
@ -1,20 +0,0 @@ |
|||
using System; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EmbeddedFiles; |
|||
|
|||
namespace Volo.Abp.AspNetCore.EmbeddedFiles |
|||
{ |
|||
//TODO: Remove to Volo.Abp.AspNetCore.Mvc project!
|
|||
public class EmbeddedResourceViewFileProvider : EmbeddedResourceFileProvider |
|||
{ |
|||
public EmbeddedResourceViewFileProvider(IObjectAccessor<IServiceProvider> serviceProviderAccessor) |
|||
: base(serviceProviderAccessor) |
|||
{ |
|||
} |
|||
|
|||
protected override bool IsIgnoredFile(EmbeddedFileInfo resource) |
|||
{ |
|||
return resource.FileExtension != "cshtml"; |
|||
} |
|||
} |
|||
} |
|||
@ -1,17 +1,17 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.AspNetCore.EmbeddedFiles |
|||
namespace Volo.Abp.AspNetCore.VirtualFileSystem |
|||
{ |
|||
internal class AspNetCoreEmbeddedFileOptions |
|||
internal class AspNetCoreVirtualFileOptions //TODO: and use this!
|
|||
{ |
|||
public HashSet<string> IgnoredFileExtensions { get; } |
|||
|
|||
public AspNetCoreEmbeddedFileOptions() |
|||
public AspNetCoreVirtualFileOptions() |
|||
{ |
|||
IgnoredFileExtensions = new HashSet<string> |
|||
{ |
|||
"cshtml", |
|||
"config" |
|||
".cshtml", |
|||
".config" |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
@page |
|||
@model Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Identity.Web.Areas.Identity.Localization.Resource |
|||
@inject IHtmlLocalizer<IdentityResource> L |
|||
@section styles { |
|||
<!-- TODO: Use minified on production, normal in development --> |
|||
<link rel="stylesheet" type="text/css" href="~/modules/identity/libs/datatables/datatables.css" /> |
|||
<link rel="stylesheet" type="text/css" href="~/modules/identity/views/users/index.css" /> |
|||
} |
|||
|
|||
@section scripts { |
|||
<!-- TODO: Use minified on production, normal in development --> |
|||
<script type="text/javascript" src="~/modules/identity/libs/datatables/datatables.min.js"></script> |
|||
<script type="text/javascript" src="~/modules/identity/views/users/index.js"></script> |
|||
} |
|||
|
|||
<div class="row"> |
|||
<div class="col-md-6"> |
|||
<h2>@L["Users"]</h2> |
|||
</div> |
|||
<div class="col-md-6 text-right"> |
|||
<!-- Button trigger modal --> |
|||
<button type="button" class="btn btn-primary create-user" data-toggle="modal"> |
|||
@L["CreateUser"] |
|||
</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<table id="IdentityUsersTable" class="table table-striped table-bordered table-hover nowrap"> |
|||
<thead> |
|||
<tr> |
|||
<th>@L["Actions"]</th> |
|||
<th>@L["UserName"]</th> |
|||
<th>@L["EmailAddress"]</th> |
|||
<th>@L["PhoneNumber"]</th> |
|||
</tr> |
|||
</thead> |
|||
</table> |
|||
|
|||
<!-- Modal --> |
|||
<div class="modal fade" id="createUpdateUserModal" tabindex="-1" role="dialog" aria-labelledby="userModalLabel" aria-hidden="true"> |
|||
<div class="modal-dialog" role="document"> |
|||
<div class="modal-content"> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,12 @@ |
|||
using Microsoft.AspNetCore.Mvc.RazorPages; |
|||
|
|||
namespace Volo.Abp.Identity.Web.Pages.Identity.Users |
|||
{ |
|||
public class IndexModel : PageModel |
|||
{ |
|||
public void OnGet() |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<AssemblyName>Volo.Abp.VirtualFileSystem</AssemblyName> |
|||
<PackageId>Volo.Abp.VirtualFileSystem</PackageId> |
|||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Microsoft.Extensions.FileProviders.Abstractions" Version="2.0.0" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.Abp\Volo.Abp.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,13 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.VirtualFileSystem |
|||
{ |
|||
public class AbpVirtualFileSystemModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(IServiceCollection services) |
|||
{ |
|||
services.AddAssemblyOf<AbpVirtualFileSystemModule>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,129 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using Microsoft.Extensions.FileProviders; |
|||
|
|||
namespace Volo.Abp.VirtualFileSystem.Embedded |
|||
{ |
|||
public class EmbeddedFileSet : IVirtualFileSet |
|||
{ |
|||
public string RootPath { get; } |
|||
|
|||
public Assembly Assembly { get; } |
|||
|
|||
public string ResourceNamespace { get; } |
|||
|
|||
public EmbeddedFileSet(string rootPath, Assembly assembly, string resourceNamespace) |
|||
{ |
|||
RootPath = rootPath.EnsureEndsWith('/'); |
|||
Assembly = assembly; |
|||
ResourceNamespace = resourceNamespace; |
|||
} |
|||
|
|||
public void AddFiles(Dictionary<string, IFileInfo> files) |
|||
{ |
|||
var lastModificationTime = GetLastModificationTime(); |
|||
|
|||
foreach (var resourcePath in Assembly.GetManifestResourceNames()) |
|||
{ |
|||
if (!resourcePath.StartsWith(ResourceNamespace)) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
var fullPath = RootPath + ConvertToRelativePath(resourcePath); |
|||
|
|||
if (fullPath.Contains("/")) |
|||
{ |
|||
AddDirectoriesRecursively(files, fullPath.Substring(0, fullPath.LastIndexOf('/')), lastModificationTime); |
|||
} |
|||
|
|||
files[fullPath] = new EmbeddedResourceFileInfo( |
|||
Assembly, |
|||
resourcePath, |
|||
fullPath, |
|||
CalculateFileName(fullPath), |
|||
lastModificationTime, |
|||
false |
|||
); |
|||
} |
|||
} |
|||
|
|||
private void AddDirectoriesRecursively(Dictionary<string, IFileInfo> files, string directoryPath, DateTimeOffset lastModificationTime) |
|||
{ |
|||
if (files.ContainsKey(directoryPath)) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
files[directoryPath] = new EmbeddedResourceFileInfo( //TODO: Create a different simpler class!
|
|||
Assembly, |
|||
null, |
|||
directoryPath, |
|||
CalculateFileName(directoryPath), |
|||
lastModificationTime, |
|||
true |
|||
); |
|||
|
|||
if (directoryPath.Contains("/")) |
|||
{ |
|||
AddDirectoriesRecursively(files, directoryPath.Substring(0, directoryPath.LastIndexOf('/')), lastModificationTime); |
|||
} |
|||
} |
|||
|
|||
private DateTimeOffset GetLastModificationTime() |
|||
{ |
|||
var lastModified = DateTimeOffset.UtcNow; |
|||
|
|||
if (!string.IsNullOrEmpty(Assembly.Location)) |
|||
{ |
|||
try |
|||
{ |
|||
lastModified = File.GetLastWriteTimeUtc(Assembly.Location); |
|||
} |
|||
catch (PathTooLongException) |
|||
{ |
|||
} |
|||
catch (UnauthorizedAccessException) |
|||
{ |
|||
} |
|||
} |
|||
|
|||
return lastModified; |
|||
} |
|||
|
|||
private string ConvertToRelativePath(string resourceName) |
|||
{ |
|||
resourceName = resourceName.Substring(ResourceNamespace.Length + 1); |
|||
|
|||
var pathParts = resourceName.Split('.'); |
|||
if (pathParts.Length <= 2) |
|||
{ |
|||
return resourceName; |
|||
} |
|||
|
|||
var folder = pathParts.Take(pathParts.Length - 2).Select(NormalizeFolderName).JoinAsString("/"); |
|||
var fileName = pathParts[pathParts.Length - 2] + "." + pathParts[pathParts.Length - 1]; |
|||
|
|||
return folder + "/" + fileName; |
|||
} |
|||
|
|||
private static string NormalizeFolderName(string pathPart) |
|||
{ |
|||
//TODO: Implement all rules of .NET
|
|||
return pathPart.Replace('-', '_'); |
|||
} |
|||
|
|||
private static string CalculateFileName(string filePath) |
|||
{ |
|||
if (!filePath.Contains("/")) |
|||
{ |
|||
return filePath; |
|||
} |
|||
|
|||
return filePath.Substring(filePath.LastIndexOf("/", StringComparison.Ordinal) + 1); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,90 @@ |
|||
using System; |
|||
using System.IO; |
|||
using System.Reflection; |
|||
using Microsoft.Extensions.FileProviders; |
|||
|
|||
namespace Volo.Abp.VirtualFileSystem.Embedded |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a file embedded in an assembly.
|
|||
/// </summary>
|
|||
public class EmbeddedResourceFileInfo : IFileInfo |
|||
{ |
|||
public bool Exists => true; |
|||
|
|||
public long Length |
|||
{ |
|||
get |
|||
{ |
|||
if (!_length.HasValue) |
|||
{ |
|||
using (var stream = _assembly.GetManifestResourceStream(_resourcePath)) |
|||
{ |
|||
_length = stream.Length; |
|||
} |
|||
} |
|||
|
|||
return _length.Value; |
|||
} |
|||
} |
|||
private long? _length; |
|||
|
|||
public string PhysicalPath { get; } |
|||
|
|||
public string Name { get; } |
|||
|
|||
public ManifestResourceInfo ManifestResourceInfo { get; } |
|||
|
|||
/// <summary>
|
|||
/// The time, in UTC.
|
|||
/// </summary>
|
|||
public DateTimeOffset LastModified { get; } |
|||
|
|||
public bool IsDirectory { get; } |
|||
|
|||
private readonly Assembly _assembly; |
|||
private readonly string _resourcePath; |
|||
|
|||
public EmbeddedResourceFileInfo( |
|||
Assembly assembly, |
|||
string resourcePath, |
|||
string physicalPath, |
|||
string name, |
|||
DateTimeOffset lastModified, |
|||
bool isDirectory) |
|||
{ |
|||
_assembly = assembly; |
|||
_resourcePath = resourcePath; |
|||
|
|||
PhysicalPath = physicalPath; |
|||
Name = name; |
|||
|
|||
if (_resourcePath != null) |
|||
{ |
|||
ManifestResourceInfo = _assembly.GetManifestResourceInfo(_resourcePath); |
|||
} |
|||
|
|||
LastModified = lastModified; |
|||
IsDirectory = isDirectory; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Stream CreateReadStream() |
|||
{ |
|||
|
|||
var stream = _assembly.GetManifestResourceStream(_resourcePath); |
|||
|
|||
if (!_length.HasValue) |
|||
{ |
|||
_length = stream.Length; |
|||
} |
|||
|
|||
return stream; |
|||
} |
|||
|
|||
public override string ToString() |
|||
{ |
|||
return $"[EmbeddedResourceFileInfo] {Name} ({PhysicalPath})"; |
|||
} |
|||
} |
|||
} |
|||
@ -1,8 +1,8 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.EmbeddedFiles |
|||
namespace Volo.Abp.VirtualFileSystem |
|||
{ |
|||
public static class EmbeddedFilePathHelper |
|||
internal static class VirtualFilePathHelper |
|||
{ |
|||
public static string NormalizePath(string fullPath) |
|||
{ |
|||
@ -0,0 +1,31 @@ |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using JetBrains.Annotations; |
|||
using Microsoft.Extensions.FileProviders; |
|||
|
|||
namespace Volo.Abp.VirtualFileSystem |
|||
{ |
|||
internal class EnumerableDirectoryContents : IDirectoryContents |
|||
{ |
|||
private readonly IEnumerable<IFileInfo> _entries; |
|||
|
|||
public EnumerableDirectoryContents([NotNull] IEnumerable<IFileInfo> entries) |
|||
{ |
|||
Check.NotNull(entries, nameof(entries)); |
|||
|
|||
_entries = entries; |
|||
} |
|||
|
|||
public bool Exists => true; |
|||
|
|||
public IEnumerator<IFileInfo> GetEnumerator() |
|||
{ |
|||
return _entries.GetEnumerator(); |
|||
} |
|||
|
|||
IEnumerator IEnumerable.GetEnumerator() |
|||
{ |
|||
return _entries.GetEnumerator(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
using Microsoft.Extensions.FileProviders; |
|||
|
|||
namespace Volo.Abp.VirtualFileSystem |
|||
{ |
|||
public interface IVirtualFileProvider : IFileProvider |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System.Collections.Generic; |
|||
using Microsoft.Extensions.FileProviders; |
|||
|
|||
namespace Volo.Abp.VirtualFileSystem |
|||
{ |
|||
public interface IVirtualFileSet |
|||
{ |
|||
void AddFiles(Dictionary<string, IFileInfo> files); |
|||
} |
|||
} |
|||
@ -0,0 +1,89 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Microsoft.Extensions.FileProviders; |
|||
using Microsoft.Extensions.Options; |
|||
using Microsoft.Extensions.Primitives; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.VirtualFileSystem |
|||
{ |
|||
public class VirtualFileProvider : IVirtualFileProvider, ISingletonDependency |
|||
{ |
|||
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 |
|||
); |
|||
} |
|||
|
|||
public IFileInfo GetFileInfo(string subpath) |
|||
{ |
|||
if (string.IsNullOrEmpty(subpath)) |
|||
{ |
|||
return new NotFoundFileInfo(subpath); |
|||
} |
|||
|
|||
var file = _files.Value.GetOrDefault(VirtualFilePathHelper.NormalizePath(subpath)); |
|||
|
|||
if (file == null) |
|||
{ |
|||
return new NotFoundFileInfo(subpath); |
|||
} |
|||
|
|||
return file; |
|||
} |
|||
|
|||
public IDirectoryContents GetDirectoryContents(string subpath) |
|||
{ |
|||
var directory = GetFileInfo(subpath); |
|||
if (!directory.IsDirectory) |
|||
{ |
|||
return new NotFoundDirectoryContents(); |
|||
} |
|||
|
|||
var fileList = new List<IFileInfo>(); |
|||
|
|||
var directoryPath = subpath + "/"; |
|||
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); |
|||
} |
|||
|
|||
public IChangeToken Watch(string filter) |
|||
{ |
|||
return NullChangeToken.Singleton; |
|||
} |
|||
|
|||
private Dictionary<string, IFileInfo> CreateResourcesDictionary() |
|||
{ |
|||
var files = new Dictionary<string, IFileInfo>(StringComparer.OrdinalIgnoreCase); |
|||
|
|||
foreach (var set in _options.FileSets) |
|||
{ |
|||
set.AddFiles(files); |
|||
} |
|||
|
|||
return files; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.VirtualFileSystem |
|||
{ |
|||
public class VirtualFileSystemOptions |
|||
{ |
|||
public List<IVirtualFileSet> FileSets { get; } |
|||
|
|||
public VirtualFileSystemOptions() |
|||
{ |
|||
FileSets = new List<IVirtualFileSet>(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,68 +0,0 @@ |
|||
using System; |
|||
using System.IO; |
|||
using System.Reflection; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.EmbeddedFiles |
|||
{ |
|||
/// <summary>
|
|||
/// Stores needed information of an embedded resource.
|
|||
/// </summary>
|
|||
public class EmbeddedFileInfo |
|||
{ |
|||
/// <summary>
|
|||
/// File name including extension.
|
|||
/// </summary>
|
|||
[NotNull] |
|||
public string FileName { get; } |
|||
|
|||
/// <summary>
|
|||
/// File extension (without dot) if available.
|
|||
/// </summary>
|
|||
[CanBeNull] |
|||
public string FileExtension { get; } |
|||
|
|||
/// <summary>
|
|||
/// Content of the file.
|
|||
/// </summary>
|
|||
[NotNull] |
|||
public byte[] Content { get; } |
|||
|
|||
/// <summary>
|
|||
/// The assembly that contains the file.
|
|||
/// </summary>
|
|||
[NotNull] |
|||
public Assembly Assembly { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Last modification time of the file.
|
|||
/// </summary>
|
|||
public DateTime LastModifiedUtc { get; } |
|||
|
|||
internal EmbeddedFileInfo([NotNull] string fileName, [NotNull] byte[] content, [NotNull] Assembly assembly) |
|||
{ |
|||
Check.NotNull(fileName, nameof(fileName)); |
|||
Check.NotNull(content, nameof(content)); |
|||
Check.NotNull(assembly, nameof(assembly)); |
|||
|
|||
FileName = fileName; |
|||
Content = content; |
|||
Assembly = assembly; |
|||
|
|||
FileExtension = CalculateFileExtension(FileName); |
|||
LastModifiedUtc = Assembly.Location != null |
|||
? new FileInfo(Assembly.Location).LastWriteTimeUtc |
|||
: DateTime.UtcNow; |
|||
} |
|||
|
|||
private static string CalculateFileExtension(string fileName) |
|||
{ |
|||
if (!fileName.Contains(".")) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
return fileName.Substring(fileName.LastIndexOf(".", StringComparison.Ordinal) + 1); |
|||
} |
|||
} |
|||
} |
|||
@ -1,43 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.EmbeddedFiles |
|||
{ |
|||
public class EmbeddedFileManager : IEmbeddedFileManager, ISingletonDependency |
|||
{ |
|||
private readonly EmbeddedFileOptions _options; |
|||
private readonly Lazy<Dictionary<string, EmbeddedFileInfo>> _resources; |
|||
|
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
public EmbeddedFileManager(IOptions<EmbeddedFileOptions> options) |
|||
{ |
|||
_options = options.Value; |
|||
_resources = new Lazy<Dictionary<string, EmbeddedFileInfo>>( |
|||
CreateResourcesDictionary, |
|||
true |
|||
); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public EmbeddedFileInfo FindFile(string fullPath) |
|||
{ |
|||
return _resources.Value.GetOrDefault(EmbeddedFilePathHelper.NormalizePath(fullPath)); |
|||
} |
|||
|
|||
private Dictionary<string, EmbeddedFileInfo> CreateResourcesDictionary() |
|||
{ |
|||
var resources = new Dictionary<string, EmbeddedFileInfo>(StringComparer.OrdinalIgnoreCase); |
|||
|
|||
foreach (var source in _options.Sources) |
|||
{ |
|||
source.AddResources(resources); |
|||
} |
|||
|
|||
return resources; |
|||
} |
|||
} |
|||
} |
|||
@ -1,14 +0,0 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.EmbeddedFiles |
|||
{ |
|||
public class EmbeddedFileOptions |
|||
{ |
|||
public List<EmbeddedFileSet> Sources { get; } |
|||
|
|||
public EmbeddedFileOptions() |
|||
{ |
|||
Sources = new List<EmbeddedFileSet>(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,78 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
|
|||
namespace Volo.Abp.EmbeddedFiles |
|||
{ |
|||
public class EmbeddedFileSet |
|||
{ |
|||
public string RootPath { get; } |
|||
|
|||
public Assembly Assembly { get; } |
|||
|
|||
public string ResourceNamespace { get; } |
|||
|
|||
public EmbeddedFileSet(string rootPath, Assembly assembly, string resourceNamespace) |
|||
{ |
|||
RootPath = rootPath.EnsureEndsWith('/'); |
|||
Assembly = assembly; |
|||
ResourceNamespace = resourceNamespace; |
|||
} |
|||
|
|||
internal void AddResources(Dictionary<string, EmbeddedFileInfo> resources) |
|||
{ |
|||
foreach (var resourceName in Assembly.GetManifestResourceNames()) |
|||
{ |
|||
if (!resourceName.StartsWith(ResourceNamespace)) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
using (var stream = Assembly.GetManifestResourceStream(resourceName)) |
|||
{ |
|||
var filePath = RootPath + ConvertToRelativePath(resourceName); |
|||
|
|||
resources[filePath] = new EmbeddedFileInfo( |
|||
CalculateFileName(filePath), |
|||
stream.GetAllBytes(), |
|||
Assembly |
|||
); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private string ConvertToRelativePath(string resourceName) |
|||
{ |
|||
resourceName = resourceName.Substring(ResourceNamespace.Length + 1); |
|||
|
|||
var pathParts = resourceName.Split('.'); |
|||
if (pathParts.Length <= 2) |
|||
{ |
|||
return resourceName; |
|||
} |
|||
|
|||
var folder = pathParts.Take(pathParts.Length - 2).Select(NormalizeFolderName).JoinAsString("/"); |
|||
var fileName = pathParts[pathParts.Length - 2] + "." + pathParts[pathParts.Length - 1]; |
|||
|
|||
return folder + "/" + fileName; |
|||
} |
|||
|
|||
private static string NormalizeFolderName(string pathPart) |
|||
{ |
|||
//TODO: Implement all rules of .NET
|
|||
return pathPart.Replace('-', '_'); |
|||
} |
|||
|
|||
private static string CalculateFileName(string filePath) |
|||
{ |
|||
if (!filePath.Contains("/")) |
|||
{ |
|||
return filePath; |
|||
} |
|||
|
|||
return filePath.Substring(filePath.LastIndexOf("/", StringComparison.Ordinal) + 1); |
|||
} |
|||
} |
|||
} |
|||
@ -1,21 +0,0 @@ |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.EmbeddedFiles |
|||
{ |
|||
//TODO: Move these classes to Volo.Abp.EmbeddedResources/EmbeddedFiles project?
|
|||
|
|||
/// <summary>
|
|||
/// Provides infrastructure to use any type of files embedded into assemblies.
|
|||
/// </summary>
|
|||
public interface IEmbeddedFileManager |
|||
{ |
|||
/// <summary>
|
|||
/// Used to get an embedded file.
|
|||
/// Can return null if file not found!
|
|||
/// </summary>
|
|||
/// <param name="fullResourcePath">Full path of the file</param>
|
|||
/// <returns>The resource</returns>
|
|||
[CanBeNull] |
|||
EmbeddedFileInfo FindFile([NotNull] string fullResourcePath); |
|||
} |
|||
} |
|||
@ -1,2 +0,0 @@ |
|||
/* This file is just a sample to use in tests */ |
|||
alert('hello world!'); |
|||
@ -0,0 +1,27 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netcoreapp2.0</TargetFramework> |
|||
<AssemblyName>Volo.Abp.VirtualFileSystem.Tests</AssemblyName> |
|||
<PackageId>Volo.Abp.VirtualFileSystem.Tests</PackageId> |
|||
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<EmbeddedResource Include="Volo\Abp\VirtualFileSystem\MyResources\js\jquery-3.1.1.min.js" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> |
|||
<ProjectReference Include="..\..\src\Volo.Abp.VirtualFileSystem\Volo.Abp.VirtualFileSystem.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -1,42 +1,52 @@ |
|||
using System.Reflection; |
|||
using System.IO; |
|||
using System.Reflection; |
|||
using System.Text; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Shouldly; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.TestBase; |
|||
using Volo.Abp.VirtualFileSystem.Embedded; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.EmbeddedFiles |
|||
namespace Volo.Abp.VirtualFileSystem |
|||
{ |
|||
public class EmbeddedFileManager_Tests : AbpIntegratedTest<EmbeddedFileManager_Tests.TestModule> |
|||
{ |
|||
private readonly IEmbeddedFileManager _embeddedFileManager; |
|||
private readonly IVirtualFileProvider _embeddedFileManager; |
|||
|
|||
public EmbeddedFileManager_Tests() |
|||
{ |
|||
_embeddedFileManager = ServiceProvider.GetRequiredService<IEmbeddedFileManager>(); |
|||
_embeddedFileManager = ServiceProvider.GetRequiredService<IVirtualFileProvider>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Define_And_Get_Embedded_Resources() |
|||
{ |
|||
var resource = _embeddedFileManager.FindFile("/MyApp/MyResources/js/MyScriptFile1.js"); |
|||
//Act
|
|||
var resource = _embeddedFileManager.GetFileInfo("/MyApp/MyResources/js/jquery-3.1.1.min.js"); |
|||
|
|||
//Assert
|
|||
resource.ShouldNotBeNull(); |
|||
Assert.Equal(resource.Assembly, GetType().GetTypeInfo().Assembly); |
|||
Assert.True(resource.Content.Length > 0); |
|||
resource.Exists.ShouldBeTrue(); |
|||
|
|||
using (var stream = resource.CreateReadStream()) |
|||
{ |
|||
Encoding.UTF8.GetString(stream.GetAllBytes()).ShouldBe("//jquery-3.1.1.min.js-contents"); |
|||
} |
|||
} |
|||
|
|||
[DependsOn(typeof(AbpVirtualFileSystemModule))] |
|||
public class TestModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(IServiceCollection services) |
|||
{ |
|||
services.Configure<EmbeddedFileOptions>(options => |
|||
services.Configure<VirtualFileSystemOptions>(options => |
|||
{ |
|||
options.Sources.Add( |
|||
options.FileSets.Add( |
|||
new EmbeddedFileSet( |
|||
"/MyApp/MyResources/", |
|||
GetType().GetTypeInfo().Assembly, |
|||
"Volo.Abp.EmbeddedFiles.MyResources" |
|||
"Volo.Abp.VirtualFileSystem.MyResources" |
|||
) |
|||
); |
|||
}); |
|||
@ -0,0 +1 @@ |
|||
//jquery-3.1.1.min.js-contents
|
|||
Loading…
Reference in new issue