Browse Source

Resolved #306: Allow to add js/css files to Pages/Views folders on development.

pull/395/head
Halil ibrahim Kalkan 8 years ago
parent
commit
c625561b95
  1. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Styles/CssRelativePathAdjuster.cs
  2. 17
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Styles/StyleBundler.cs
  3. 25
      framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/VirtualFileSystemApplicationBuilderExtensions.cs
  4. 28
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AspNetCoreContentOptions.cs
  5. 82
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/FileProviderSubFolderWrapper.cs
  6. 71
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/HybridWebRootFileProvider.cs
  7. 2
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/IHybridWebRootFileProvider.cs
  8. 2
      framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/DictionaryBasedFileProvider.cs
  9. 39
      framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/FileProviderSubFolderWrapper.cs
  10. 2
      modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/Index.cshtml
  11. 0
      modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/index.js
  12. 2
      modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/Index.cshtml
  13. 0
      modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/index.js
  14. 4
      modules/identity/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj

5
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Styles/CssRelativePathAdjuster.cs

@ -8,7 +8,10 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.Styles
{
private static readonly Regex _rxUrl = new Regex(@"url\s*\(\s*([""']?)([^:)]+)\1\s*\)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
public static string Adjust(string cssFileContents, string absoluteInputFilePath, string absoluteOutputPath)
public static string Adjust(
string cssFileContents,
string absoluteInputFilePath,
string absoluteOutputPath)
{
var matches = _rxUrl.Matches(cssFileContents);

17
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Styles/StyleBundler.cs

@ -1,3 +1,6 @@
using System;
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Volo.Abp.AspNetCore.Mvc.UI.Minification.Styles;
using Volo.Abp.AspNetCore.VirtualFileSystem;
@ -5,21 +8,27 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.Styles
{
public class StyleBundler : BundlerBase, IStyleBundler
{
private readonly IHostingEnvironment _hostingEnvironment;
public override string FileExtension => "css";
public StyleBundler(IHybridWebRootFileProvider webRootFileProvider, ICssMinifier minifier)
public StyleBundler(IHybridWebRootFileProvider webRootFileProvider, ICssMinifier minifier, IHostingEnvironment hostingEnvironment)
: base(webRootFileProvider, minifier)
{
_hostingEnvironment = hostingEnvironment;
}
protected override string GetFileContent(IBundlerContext context, string file)
{
return CssRelativePath.Adjust(
base.GetFileContent(context, file),
WebRootFileProvider.GetAbsolutePath(file),
WebRootFileProvider.GetAbsolutePath(context.BundleRelativePath)
GetAbsolutePath(file),
GetAbsolutePath(context.BundleRelativePath)
);
}
public string GetAbsolutePath(string relativePath)
{
return Path.Combine(_hostingEnvironment.ContentRootPath, "wwwroot", relativePath.RemovePreFix("/"));
}
}
}

25
framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/VirtualFileSystemApplicationBuilderExtensions.cs

@ -1,5 +1,8 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.VirtualFileSystem;
using Volo.Abp.VirtualFileSystem;
namespace Microsoft.AspNetCore.Builder
@ -8,15 +11,23 @@ namespace Microsoft.AspNetCore.Builder
{
public static void UseVirtualFiles(this IApplicationBuilder app)
{
IFileProvider fileProvider = new FileProviderSubFolderWrapper(
app.ApplicationServices.GetRequiredService<IVirtualFileProvider>(),
"/wwwroot"
);
//var options = app.ApplicationServices.GetRequiredService<IOptions<AspNetCoreContentOptions>>().Value;
//var hostingEnvironment = app.ApplicationServices.GetRequiredService<IHostingEnvironment>();
//var fileProvider = new FileProviderSubFolderWrapper(
// new CompositeFileProvider(
// new PhysicalFileProvider(hostingEnvironment.ContentRootPath),
// app.ApplicationServices.GetRequiredService<IVirtualFileProvider>()
// ),
// "/wwwroot",
// options.AllowedExtraWebContentFolders.ToArray(),
// options.AllowedExtraWebContentFileExtensions.ToArray()
//);
app.UseStaticFiles(
new StaticFileOptions
{
FileProvider = fileProvider
FileProvider = app.ApplicationServices.GetRequiredService<IHybridWebRootFileProvider>()
}
);
}

28
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AspNetCoreContentOptions.cs

@ -0,0 +1,28 @@
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.VirtualFileSystem
{
public class AspNetCoreContentOptions
{
public List<string> AllowedExtraWebContentFolders { get; }
public List<string> AllowedExtraWebContentFileExtensions { get; }
public AspNetCoreContentOptions()
{
AllowedExtraWebContentFolders = new List<string>
{
"/Pages",
"/Views"
};
AllowedExtraWebContentFileExtensions = new List<string>
{
".js",
".css",
".png",
".jpg",
".jpeg"
};
}
}
}

82
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/FileProviderSubFolderWrapper.cs

@ -0,0 +1,82 @@
//using System;
//using System.Linq;
//using JetBrains.Annotations;
//using Microsoft.Extensions.FileProviders;
//using Microsoft.Extensions.Primitives;
//namespace Volo.Abp.VirtualFileSystem
//{
// //TODO: Ensure that merging such subfolders is secure! (anyone can add /.. to the beginning!)..?
// public class FileProviderSubFolderWrapper : IFileProvider
// {
// private readonly IFileProvider _fileProvider;
// private readonly string _rootPath;
// private readonly string[] _allowedExtraFolders;
// private readonly string[] _allowedExtraFileExtensions;
// public FileProviderSubFolderWrapper(
// IFileProvider fileProvider,
// string rootPath,
// string[] allowedExtraFolders = null,
// string[] allowedExtraFileExtensions = null)
// {
// _fileProvider = fileProvider;
// _rootPath = rootPath;
// _allowedExtraFileExtensions = allowedExtraFileExtensions ?? Array.Empty<string>();
// _allowedExtraFolders = allowedExtraFolders ?? Array.Empty<string>();
// }
// public IFileInfo GetFileInfo(string subpath)
// {
// Check.NotNullOrEmpty(subpath, nameof(subpath));
// if (ExtraAllowedPath(subpath))
// {
// var fileInfo = _fileProvider.GetFileInfo(subpath);
// if (fileInfo.Exists)
// {
// return fileInfo;
// }
// }
// return _fileProvider.GetFileInfo(_rootPath + subpath);
// }
// public IDirectoryContents GetDirectoryContents([NotNull] string subpath)
// {
// Check.NotNullOrEmpty(subpath, nameof(subpath));
// if (ExtraAllowedPath(subpath))
// {
// var directory = _fileProvider.GetDirectoryContents(subpath);
// if (directory.Exists)
// {
// return directory;
// }
// }
// return _fileProvider.GetDirectoryContents(_rootPath + subpath);
// }
// private bool ExtraAllowedPath(string path)
// {
// return ExtraAllowedFolder(path) && ExtraAllowedExtension(path);
// }
// private bool ExtraAllowedFolder(string path)
// {
// return _allowedExtraFolders.Any(s => path.StartsWith(s, StringComparison.OrdinalIgnoreCase));
// }
// private bool ExtraAllowedExtension(string path)
// {
// return _allowedExtraFileExtensions.Any(e => path.EndsWith(e, StringComparison.OrdinalIgnoreCase));
// }
// public IChangeToken Watch(string filter)
// {
// return _fileProvider.Watch(filter); //TODO: Why this does not use NormalizePath?
// }
// }
//}

71
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/HybridWebRootFileProvider.cs

@ -1,53 +1,102 @@
using System;
using System.IO;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Volo.Abp.DependencyInjection;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.AspNetCore.VirtualFileSystem
{
//TODO: How to handle wwwroot naming?
public class HybridWebRootFileProvider : IHybridWebRootFileProvider, ISingletonDependency
{
private readonly IVirtualFileProvider _virtualFileProvider;
private readonly IFileProvider _fileProvider;
private readonly IHostingEnvironment _hostingEnvironment;
private string _rootPath = "/wwwroot";
public HybridWebRootFileProvider(IVirtualFileProvider virtualFileProvider, IHostingEnvironment hostingEnvironment)
protected AspNetCoreContentOptions Options { get; }
public HybridWebRootFileProvider(
IVirtualFileProvider virtualFileProvider,
IHostingEnvironment hostingEnvironment,
IOptions<AspNetCoreContentOptions> options)
{
_virtualFileProvider = virtualFileProvider;
_hostingEnvironment = hostingEnvironment;
Options = options.Value;
_fileProvider = CreateHybridProvider();
}
public virtual IFileInfo GetFileInfo(string subpath)
public IFileInfo GetFileInfo(string subpath)
{
return _fileProvider.GetFileInfo("/wwwroot" + subpath); //TODO: Hard-coded "/wwwroot" is not good!
Check.NotNullOrEmpty(subpath, nameof(subpath));
if (ExtraAllowedFolder(subpath) && ExtraAllowedExtension(subpath))
{
var fileInfo = _fileProvider.GetFileInfo(subpath);
if (fileInfo.Exists)
{
return fileInfo;
}
}
return _fileProvider.GetFileInfo(_rootPath + subpath);
}
public virtual IDirectoryContents GetDirectoryContents(string subpath)
public IDirectoryContents GetDirectoryContents([NotNull] string subpath)
{
return _fileProvider.GetDirectoryContents("/wwwroot" + subpath);
Check.NotNullOrEmpty(subpath, nameof(subpath));
if (ExtraAllowedFolder(subpath))
{
var directory = _fileProvider.GetDirectoryContents(subpath);
if (directory.Exists)
{
return directory;
}
}
return _fileProvider.GetDirectoryContents(_rootPath + subpath);
}
public virtual IChangeToken Watch(string filter)
{
return _fileProvider.Watch("/wwwroot" + filter);
}
if (!ExtraAllowedFolder(filter))
{
return _fileProvider.Watch("/wwwroot" + filter);
}
public string GetAbsolutePath(string relativePath)
{
return Path.Combine(_hostingEnvironment.ContentRootPath, "wwwroot", relativePath.RemovePreFix("/"));
return new CompositeChangeToken(
new[]
{
_fileProvider.Watch("/wwwroot" + filter),
_fileProvider.Watch(filter)
}
);
}
protected virtual IFileProvider CreateHybridProvider()
{
return new CompositeFileProvider(
_hostingEnvironment.ContentRootFileProvider,
new PhysicalFileProvider(_hostingEnvironment.ContentRootPath),
_virtualFileProvider
);
}
protected virtual bool ExtraAllowedFolder(string path)
{
return Options.AllowedExtraWebContentFolders.Any(s => path.StartsWith(s, StringComparison.OrdinalIgnoreCase));
}
protected virtual bool ExtraAllowedExtension(string path)
{
return Options.AllowedExtraWebContentFileExtensions.Any(e => path.EndsWith(e, StringComparison.OrdinalIgnoreCase));
}
}
}

2
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/IHybridWebRootFileProvider.cs

@ -4,6 +4,6 @@ namespace Volo.Abp.AspNetCore.VirtualFileSystem
{
public interface IHybridWebRootFileProvider : IFileProvider
{
string GetAbsolutePath(string relativePath);
}
}

2
framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/DictionaryBasedFileProvider.cs

@ -31,7 +31,7 @@ namespace Volo.Abp.VirtualFileSystem
var directory = GetFileInfo(subpath);
if (!directory.IsDirectory)
{
return new NotFoundDirectoryContents();
return NotFoundDirectoryContents.Singleton;
}
var fileList = new List<IFileInfo>();

39
framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/FileProviderSubFolderWrapper.cs

@ -1,39 +0,0 @@
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives;
namespace Volo.Abp.VirtualFileSystem
{
public class FileProviderSubFolderWrapper : IFileProvider
{
private readonly IFileProvider _fileProvider;
private readonly string _contentPath;
public FileProviderSubFolderWrapper(IFileProvider fileProvider, string contentPath = null)
{
_contentPath = contentPath;
_fileProvider = fileProvider;
}
public IFileInfo GetFileInfo(string subpath)
{
return _fileProvider.GetFileInfo(NormalizePath(subpath));
}
public IDirectoryContents GetDirectoryContents(string subpath)
{
return _fileProvider.GetDirectoryContents(NormalizePath(subpath));
}
private string NormalizePath(string subpath)
{
return _contentPath == null
? subpath
: _contentPath + subpath;
}
public IChangeToken Watch(string filter)
{
return _fileProvider.Watch(filter); //TODO: Why this does not use NormalizePath?
}
}
}

2
modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/Index.cshtml

@ -7,7 +7,7 @@
@section scripts {
<abp-script-bundle name="@typeof(IndexModel).FullName">
<abp-script src="/pages/abp-permission-management/permission-management-modal.js" />
<abp-script src="/pages/identity/roles/index.js" />
<abp-script src="/Pages/identity/roles/index.js" />
</abp-script-bundle>
}
<abp-card id="IdentityRolesWrapper">

0
modules/identity/src/Volo.Abp.Identity.Web/wwwroot/pages/identity/roles/index.js → modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/index.js

2
modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/Index.cshtml

@ -10,7 +10,7 @@
@section scripts {
<abp-script-bundle name="@typeof(IndexModel).FullName">
<abp-script src="/pages/abp-permission-management/permission-management-modal.js" />
<abp-script src="/pages/identity/users/index.js" />
<abp-script src="/Pages/identity/users/index.js" />
</abp-script-bundle>
}

0
modules/identity/src/Volo.Abp.Identity.Web/wwwroot/pages/identity/users/index.js → modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/index.js

4
modules/identity/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj

@ -15,18 +15,18 @@
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="wwwroot\**\*.*" />
<EmbeddedResource Include="Pages\**\*.cshtml" Exclude="*.cs" />
<EmbeddedResource Include="Localization\Resources\**\*.json" />
</ItemGroup>
<ItemGroup>
<Content Remove="wwwroot\**\*.*" />
<Content Remove="Pages\**\*.cshtml" />
<Content Remove="Localization\Resources\**\*.json" />
<Content Remove="compilerconfig.json" />
<Content Remove="compilerconfig.json.defaults" />
<Content Remove="Properties\launchSettings.json" />
<EmbeddedResource Include="Pages\Identity\Roles\index.js" />
<EmbeddedResource Include="Pages\Identity\Users\index.js" />
<None Include="compilerconfig.json" />
<None Include="Properties\launchSettings.json" />
</ItemGroup>

Loading…
Cancel
Save