Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Data;
- using System.IO;
- using System.Linq;
- using System.Reflection;
- using Microsoft.AspNet.FileSystems;
- using Microsoft.AspNet.Mvc;
- using Microsoft.AspNet.Mvc.Razor;
- using Microsoft.Framework.Expiration.Interfaces;
- using Microsoft.Framework.OptionsModel;
- using Microsoft.Framework.Runtime;
- namespace MvcFs
- {
- public class EmbeddedExpiringFileInfoCache:IFileSystem
- {
- private readonly ConcurrentDictionary<string,ExpiringFileInfo> _fileInfoCache=new ConcurrentDictionary<string,ExpiringFileInfo>(StringComparer.Ordinal);
- private readonly TimeSpan cacheDuration;
- private readonly List<Assembly> assemblyList;
- protected virtual IFileSystem FileSystem { get; }
- public EmbeddedExpiringFileInfoCache(IOptions<RazorViewEngineOptions> razorViewEngineOptions,ILibraryManager libraryManager)
- {
- //Defaults to DefaultRazorFileSystemCache which contains its own cache
- //Could also be new PhysicalFileSystem(env.ApplicationBasePath); or razorViewEngineOptions.Options.FileSystem (as used in DefaultRazorFileSystemCache)
- FileSystem=new DefaultRazorFileSystemCache(razorViewEngineOptions);
- //This is not relevant since Assemblies won't change over time; the cost to keep this is very low, so we just keep it
- //razorViewEngineOptions.Options.ExpirationBeforeCheckingFilesOnDisk is only 2 seconds or so by default
- cacheDuration=TimeSpan.FromDays(365);
- //Find all loadable assemblies
- assemblyList=libraryManager.GetLibraries()
- .Select(_library => _library.Name)
- .Distinct()
- .SelectMany(_assemblyName => {
- //Only select loadable assemblies
- try
- { return new[] { Assembly.Load(new AssemblyName(_assemblyName)) }; }
- catch
- { return new Assembly[0]; }
- })
- .ToList();
- }
- /// <inheritdoc />
- public IFileInfo GetFileInfo(string virtualPath)
- {
- if(FileSystem!=null)
- {
- //Ask the real FS first, so the user can override imported views
- IFileInfo fileInfo=FileSystem.GetFileInfo(virtualPath);
- if(fileInfo!=null && fileInfo.Exists)
- { return fileInfo; }
- }
- //Look in our cache first
- ExpiringFileInfo expiringFileInfo;
- DateTime utcNow=DateTime.UtcNow;
- if(_fileInfoCache.TryGetValue(virtualPath,out expiringFileInfo) && expiringFileInfo.ValidUntil>utcNow)
- { return expiringFileInfo.FileInfo; }
- //Search in assemblies
- string path=virtualPath.StartsWith("/")?virtualPath.Substring(1):virtualPath;
- foreach(Assembly assembly in assemblyList)
- {
- string name=assembly.GetManifestResourceNames().FirstOrDefault(_path => _path.Equals(path,StringComparison.OrdinalIgnoreCase));
- if(name!=null)
- {
- expiringFileInfo=new ExpiringFileInfo {
- FileInfo=new EmbeddedFileInfo(assembly,name/*,information*/),
- ValidUntil=utcNow.Add(cacheDuration)
- };
- }
- }
- //Make sure we don't save a null (would cause problem above with cache check)
- expiringFileInfo=expiringFileInfo??new ExpiringFileInfo {
- FileInfo=new NotFoundFileInfo(virtualPath),
- ValidUntil=utcNow.Add(cacheDuration)
- };
- _fileInfoCache[virtualPath]=expiringFileInfo;
- return expiringFileInfo.FileInfo;
- }
- private class ExpiringFileInfo
- {
- public IFileInfo FileInfo { get; set; }
- public DateTime ValidUntil { get; set; }
- }
- public IDirectoryContents GetDirectoryContents(string subpath)
- { return FileSystem.GetDirectoryContents(subpath); }
- }
- public class EmbeddedFileInfo:IFileInfo,IDisposable
- {
- private Assembly assembly;
- private Stream stream;
- public DateTime LastModified { get; }
- public long Length { get; }
- public string Name { get; }
- public string PhysicalPath { get; }
- public bool IsDirectory => false;
- public bool Exists => true;
- public bool IsReadOnly => true;
- public EmbeddedFileInfo(Assembly assembly,string name/*,ILibraryInformation libraryInformation*/)
- {
- this.assembly=assembly;
- stream=assembly.GetManifestResourceStream(name);
- Name=name;
- LastModified=DateTime.UtcNow;
- PhysicalPath=assembly.CodeBase;
- Length =stream?.Length??0;
- }
- public Stream CreateReadStream()
- { return stream; }
- public void WriteContent(byte[] content)
- { throw new ReadOnlyException("This is readonly"); }
- public void Delete()
- { throw new ReadOnlyException("This is readonly"); }
- public IExpirationTrigger CreateFileChangeTrigger()
- { throw new ReadOnlyException("This is readonly"); }
- public void Dispose()
- {
- stream?.Dispose();
- stream=null;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement