Browse Source

Resolved #24: Embedded Controller and View System.

pull/81/head
Halil İbrahim Kalkan 10 years ago
parent
commit
f4fd048a56
  1. 15
      Volo.Abp.sln
  2. 26
      src/Volo.Abp.AspNetCore.EmbeddedFiles/Microsoft/AspNetCore/Builder/EmbeddedFilesApplicationBuilderExtensions.cs
  3. 19
      src/Volo.Abp.AspNetCore.EmbeddedFiles/Properties/AssemblyInfo.cs
  4. 20
      src/Volo.Abp.AspNetCore.EmbeddedFiles/Volo.Abp.AspNetCore.EmbeddedFiles.xproj
  5. 14
      src/Volo.Abp.AspNetCore.EmbeddedFiles/Volo/Abp/AspNetCore/EmbeddedFiles/AbpAspNetCoreEmbeddedFilesModule.cs
  6. 18
      src/Volo.Abp.AspNetCore.EmbeddedFiles/Volo/Abp/AspNetCore/EmbeddedFiles/AspNetCoreEmbeddedFileOptions.cs
  7. 57
      src/Volo.Abp.AspNetCore.EmbeddedFiles/Volo/Abp/AspNetCore/EmbeddedFiles/EmbeddedResourceFileProvider.cs
  8. 34
      src/Volo.Abp.AspNetCore.EmbeddedFiles/Volo/Abp/AspNetCore/EmbeddedFiles/EmbeddedResourceItemFileInfo.cs
  9. 18
      src/Volo.Abp.AspNetCore.EmbeddedFiles/Volo/Abp/AspNetCore/EmbeddedFiles/EmbeddedResourceViewFileProvider.cs
  10. 14
      src/Volo.Abp.AspNetCore.EmbeddedFiles/project.json
  11. 27
      src/Volo.Abp.AspNetCore.Mvc.UI/Properties/launchSettings.json
  12. 22
      src/Volo.Abp.AspNetCore.Mvc.UI/Views/Shared/Components/Menu/Default.cshtml
  13. 22
      src/Volo.Abp.AspNetCore.Mvc.UI/Views/Shared/Components/Menu/MenuViewComponent.cs
  14. 23
      src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.xproj
  15. 14
      src/Volo.Abp.AspNetCore.Mvc.UI/project.json
  16. 14
      src/Volo.Abp.AspNetCore.Mvc.UI/web.config
  17. 68
      src/Volo.Abp/Volo/Abp/EmbeddedFiles/EmbeddedFileInfo.cs
  18. 44
      src/Volo.Abp/Volo/Abp/EmbeddedFiles/EmbeddedFileManager.cs
  19. 14
      src/Volo.Abp/Volo/Abp/EmbeddedFiles/EmbeddedFileOptions.cs
  20. 79
      src/Volo.Abp/Volo/Abp/EmbeddedFiles/EmbeddedFileSet.cs
  21. 19
      src/Volo.Abp/Volo/Abp/EmbeddedFiles/IEmbeddedFileManager.cs
  22. 16
      src/Volo.Abp/Volo/ExtensionMethods/StreamExtensions.cs
  23. 46
      test/Volo.Abp.Tests/Volo/Abp/EmbeddedFiles/EmbeddedFileManager_Tests.cs
  24. 2
      test/Volo.Abp.Tests/Volo/Abp/EmbeddedFiles/MyResources/js/MyScriptFile1.js
  25. 8
      test/Volo.Abp.Tests/project.json

15
Volo.Abp.sln

@ -84,7 +84,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docker-files", "docker-file
docker\up.ps1 = docker\up.ps1
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Abp.UI", "Abp.UI", "{44F530AA-CF9B-4B73-8D9B-E9C6C66A01FE}"
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Volo.Abp.AspNetCore.Mvc.UI", "src\Volo.Abp.AspNetCore.Mvc.UI\Volo.Abp.AspNetCore.Mvc.UI.xproj", "{BF9AB22C-F48D-4DDE-A894-BC28EB37166B}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Volo.Abp.AspNetCore.EmbeddedFiles", "src\Volo.Abp.AspNetCore.EmbeddedFiles\Volo.Abp.AspNetCore.EmbeddedFiles.xproj", "{B6182BF1-9EC6-403D-A42C-D6441CF7B390}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -196,6 +198,14 @@ Global
{ADFAF85B-B785-41EA-B57D-422775989FA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ADFAF85B-B785-41EA-B57D-422775989FA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ADFAF85B-B785-41EA-B57D-422775989FA6}.Release|Any CPU.Build.0 = Release|Any CPU
{BF9AB22C-F48D-4DDE-A894-BC28EB37166B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BF9AB22C-F48D-4DDE-A894-BC28EB37166B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF9AB22C-F48D-4DDE-A894-BC28EB37166B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF9AB22C-F48D-4DDE-A894-BC28EB37166B}.Release|Any CPU.Build.0 = Release|Any CPU
{B6182BF1-9EC6-403D-A42C-D6441CF7B390}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B6182BF1-9EC6-403D-A42C-D6441CF7B390}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B6182BF1-9EC6-403D-A42C-D6441CF7B390}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B6182BF1-9EC6-403D-A42C-D6441CF7B390}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -234,6 +244,7 @@ Global
{63244DC7-34BE-44E1-BF6F-F2672E59AF36} = {1187F469-0063-4065-9419-A1D956C80145}
{ADFAF85B-B785-41EA-B57D-422775989FA6} = {1187F469-0063-4065-9419-A1D956C80145}
{0BEA55D6-E0B8-40DD-A256-B34C4DD990A5} = {CBCC288A-53C3-402F-99F7-E468738560F5}
{44F530AA-CF9B-4B73-8D9B-E9C6C66A01FE} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{BF9AB22C-F48D-4DDE-A894-BC28EB37166B} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8}
{B6182BF1-9EC6-403D-A42C-D6441CF7B390} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8}
EndGlobalSection
EndGlobal

26
src/Volo.Abp.AspNetCore.EmbeddedFiles/Microsoft/AspNetCore/Builder/EmbeddedFilesApplicationBuilderExtensions.cs

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Volo.Abp.AspNetCore.EmbeddedFiles;
namespace Volo.Abp.AspNetCore.Microsoft.AspNetCore.Builder
{
public static class EmbeddedFilesApplicationBuilderExtensions
{
public static void UseEmbeddedFiles(this IApplicationBuilder app)
{
//TODO: Can improve it or create a custom middleware?
app.UseStaticFiles(
new StaticFileOptions
{
FileProvider = new EmbeddedResourceFileProvider(
app.ApplicationServices
)
}
);
}
}
}

19
src/Volo.Abp.AspNetCore.EmbeddedFiles/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("Volo.Abp.AspNetCore.EmbeddedFiles")]
[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("b6182bf1-9ec6-403d-a42c-d6441cf7b390")]

20
src/Volo.Abp.AspNetCore.EmbeddedFiles/Volo.Abp.AspNetCore.EmbeddedFiles.xproj

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>b6182bf1-9ec6-403d-a42c-d6441cf7b390</ProjectGuid>
<RootNamespace>
</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

14
src/Volo.Abp.AspNetCore.EmbeddedFiles/Volo/Abp/AspNetCore/EmbeddedFiles/AbpAspNetCoreEmbeddedFilesModule.cs

@ -0,0 +1,14 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.EmbeddedFiles
{
[DependsOn(typeof(AbpAspNetCoreModule))]
public class AbpAspNetCoreEmbeddedFilesModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddAssemblyOf<AbpAspNetCoreEmbeddedFilesModule>();
}
}
}

18
src/Volo.Abp.AspNetCore.EmbeddedFiles/Volo/Abp/AspNetCore/EmbeddedFiles/AspNetCoreEmbeddedFileOptions.cs

@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.EmbeddedFiles
{
internal class AspNetCoreEmbeddedFileOptions
{
public HashSet<string> IgnoredFileExtensions { get; }
public AspNetCoreEmbeddedFileOptions()
{
IgnoredFileExtensions = new HashSet<string>
{
"cshtml",
"config"
};
}
}
}

57
src/Volo.Abp.AspNetCore.EmbeddedFiles/Volo/Abp/AspNetCore/EmbeddedFiles/EmbeddedResourceFileProvider.cs

@ -0,0 +1,57 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Volo.Abp.EmbeddedFiles;
namespace Volo.Abp.AspNetCore.EmbeddedFiles
{
public class EmbeddedResourceFileProvider : IFileProvider
{
private readonly Lazy<IEmbeddedFileManager> _embeddedResourceManager;
private readonly Lazy<AspNetCoreEmbeddedFileOptions> _options;
public EmbeddedResourceFileProvider(IServiceProvider serviceProvider)
{
_embeddedResourceManager = new Lazy<IEmbeddedFileManager>(
() => serviceProvider.GetRequiredService<IEmbeddedFileManager>(),
true
);
_options = new Lazy<AspNetCoreEmbeddedFileOptions>(
() => serviceProvider.GetRequiredService<IOptions<AspNetCoreEmbeddedFileOptions>>().Value,
true
);
}
public IFileInfo GetFileInfo(string subpath)
{
var resource = _embeddedResourceManager.Value.FindFile(subpath);
if (resource == null || IsIgnoredFile(resource))
{
return new NotFoundFileInfo(subpath);
}
return new EmbeddedResourceItemFileInfo(resource);
}
public IDirectoryContents GetDirectoryContents(string subpath)
{
//TODO: Implement...?
return new NotFoundDirectoryContents();
}
public IChangeToken Watch(string filter)
{
return NullChangeToken.Singleton;
}
protected virtual bool IsIgnoredFile(EmbeddedFileInfo resource)
{
return resource.FileExtension != null && _options.Value.IgnoredFileExtensions.Contains(resource.FileExtension);
}
}
}

34
src/Volo.Abp.AspNetCore.EmbeddedFiles/Volo/Abp/AspNetCore/EmbeddedFiles/EmbeddedResourceItemFileInfo.cs

@ -0,0 +1,34 @@
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);
}
}
}

18
src/Volo.Abp.AspNetCore.EmbeddedFiles/Volo/Abp/AspNetCore/EmbeddedFiles/EmbeddedResourceViewFileProvider.cs

@ -0,0 +1,18 @@
using System;
using Volo.Abp.EmbeddedFiles;
namespace Volo.Abp.AspNetCore.EmbeddedFiles
{
public class EmbeddedResourceViewFileProvider : EmbeddedResourceFileProvider
{
public EmbeddedResourceViewFileProvider(IServiceProvider serviceProvider)
: base(serviceProvider)
{
}
protected override bool IsIgnoredFile(EmbeddedFileInfo resource)
{
return resource.FileExtension != "cshtml";
}
}
}

14
src/Volo.Abp.AspNetCore.EmbeddedFiles/project.json

@ -0,0 +1,14 @@
{
"version": "1.0.0-*",
"dependencies": {
"Volo.Abp.AspNetCore": "1.0.0-*",
"Microsoft.AspNetCore.StaticFiles": "1.1.0"
},
"frameworks": {
"netstandard1.6": {
"imports": "dnxcore50"
}
}
}

27
src/Volo.Abp.AspNetCore.Mvc.UI/Properties/launchSettings.json

@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:55913/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore.Mvc.UI": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

22
src/Volo.Abp.AspNetCore.Mvc.UI/Views/Shared/Components/Menu/Default.cshtml

@ -0,0 +1,22 @@
@using System.Threading.Tasks
@model Volo.Abp.UI.Navigation.ApplicationMenu
<h2>@Model.DisplayName</h2>
<ul>
@foreach (var menuItem in Model.Items)
{
<li>
<a href="@menuItem.Url">@menuItem.DisplayName</a>
@if (menuItem.Items.Any())
{
<ul>
@foreach (var childMenuItem in menuItem.Items)
{
<li>
<a href="@childMenuItem.Url">@childMenuItem.DisplayName</a>
</li>
}
</ul>
}
</li>
}
</ul>

22
src/Volo.Abp.AspNetCore.Mvc.UI/Views/Shared/Components/Menu/MenuViewComponent.cs

@ -0,0 +1,22 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.UI.Navigation;
namespace Volo.Abp.AspNetCore.Mvc.Views.Shared.Components.Menu
{
public class MenuViewComponent : ViewComponent
{
private readonly IMenuManager _menuManager;
public MenuViewComponent(IMenuManager menuManager)
{
_menuManager = menuManager;
}
public async Task<IViewComponentResult> InvokeAsync(string menuName = StandardMenus.Main, string viewName = "Default")
{
var menu = await _menuManager.GetAsync(StandardMenus.Main);
return View(viewName, menu);
}
}
}

23
src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.xproj

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>bf9ab22c-f48d-4dde-a894-bc28eb37166b</ProjectGuid>
<RootNamespace>Volo.Abp.AspNetCore.Mvc</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<ItemGroup>
<DnxInvisibleContent Include="bower.json" />
<DnxInvisibleContent Include=".bowerrc" />
</ItemGroup>
<Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

14
src/Volo.Abp.AspNetCore.Mvc.UI/project.json

@ -0,0 +1,14 @@
{
"dependencies": {
"Volo.Abp.AspNetCore.Mvc": "1.0.0-*"
},
"tools": {
},
"frameworks": {
"netstandard1.6": {
"imports": "dnxcore50"
}
}
}

14
src/Volo.Abp.AspNetCore.Mvc.UI/web.config

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!--
Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380
-->
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
</system.webServer>
</configuration>

68
src/Volo.Abp/Volo/Abp/EmbeddedFiles/EmbeddedFileInfo.cs

@ -0,0 +1,68 @@
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);
}
}
}

44
src/Volo.Abp/Volo/Abp/EmbeddedFiles/EmbeddedFileManager.cs

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Options;
using Volo.DependencyInjection;
using Volo.ExtensionMethods.Collections.Generic;
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(fullPath);
}
private Dictionary<string, EmbeddedFileInfo> CreateResourcesDictionary()
{
var resources = new Dictionary<string, EmbeddedFileInfo>();
foreach (var source in _options.Sources)
{
source.AddResources(resources);
}
return resources;
}
}
}

14
src/Volo.Abp/Volo/Abp/EmbeddedFiles/EmbeddedFileOptions.cs

@ -0,0 +1,14 @@
using System.Collections.Generic;
namespace Volo.Abp.EmbeddedFiles
{
public class EmbeddedFileOptions
{
public List<EmbeddedFileSet> Sources { get; }
public EmbeddedFileOptions()
{
Sources = new List<EmbeddedFileSet>();
}
}
}

79
src/Volo.Abp/Volo/Abp/EmbeddedFiles/EmbeddedFileSet.cs

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Volo.ExtensionMethods;
using Volo.ExtensionMethods.Collections.Generic;
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);
}
}
}

19
src/Volo.Abp/Volo/Abp/EmbeddedFiles/IEmbeddedFileManager.cs

@ -0,0 +1,19 @@
using JetBrains.Annotations;
namespace Volo.Abp.EmbeddedFiles
{
/// <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);
}
}

16
src/Volo.Abp/Volo/ExtensionMethods/StreamExtensions.cs

@ -0,0 +1,16 @@
using System.IO;
namespace Volo.ExtensionMethods
{
public static class StreamExtensions
{
public static byte[] GetAllBytes(this Stream stream)
{
using (var memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
}
}

46
test/Volo.Abp.Tests/Volo/Abp/EmbeddedFiles/EmbeddedFileManager_Tests.cs

@ -0,0 +1,46 @@
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Modularity;
using Volo.Abp.TestBase;
using Xunit;
namespace Volo.Abp.EmbeddedFiles
{
public class EmbeddedFileManager_Tests : AbpIntegratedTest<EmbeddedFileManager_Tests.TestModule>
{
private readonly IEmbeddedFileManager _embeddedFileManager;
public EmbeddedFileManager_Tests()
{
_embeddedFileManager = ServiceProvider.GetRequiredService<IEmbeddedFileManager>();
}
[Fact]
public void Should_Define_And_Get_Embedded_Resources()
{
var resource = _embeddedFileManager.FindFile("/MyApp/MyResources/js/MyScriptFile1.js");
resource.ShouldNotBeNull();
Assert.Equal(resource.Assembly, GetType().GetTypeInfo().Assembly);
Assert.True(resource.Content.Length > 0);
}
public class TestModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
services.Configure<EmbeddedFileOptions>(options =>
{
options.Sources.Add(
new EmbeddedFileSet(
"/MyApp/MyResources/",
GetType().GetTypeInfo().Assembly,
"Volo.Abp.Tests.Volo.Abp.EmbeddedFiles.MyResources"
)
);
});
}
}
}
}

2
test/Volo.Abp.Tests/Volo/Abp/EmbeddedFiles/MyResources/js/MyScriptFile1.js

@ -0,0 +1,2 @@
/* This file is just a sample to use in tests */
alert('hello world!');

8
test/Volo.Abp.Tests/project.json

@ -17,5 +17,13 @@
}
}
}
},
"buildOptions": {
"embed": {
"include": [
"Volo/Abp/EmbeddedFiles/MyResources/js/*.js"
]
}
}
}

Loading…
Cancel
Save