Last active
April 11, 2016 13:53
-
-
Save jijiechen/2b5e88923c156ed17e29cf6900d6cfd5 to your computer and use it in GitHub Desktop.
Configure Mvc to use a synchronous IFileProvider instance to prevent from hangs when generating Razor view result. See https://github.com/aspnet/Hosting/issues/604
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.AspNet.Builder; | |
using Microsoft.AspNet.FileProviders; | |
using Microsoft.AspNet.Hosting; | |
using Microsoft.AspNet.Mvc.Razor; | |
using Microsoft.Extensions.Configuration; | |
using Microsoft.Extensions.DependencyInjection; | |
using Microsoft.Extensions.Logging; | |
using Microsoft.Extensions.PlatformAbstractions; | |
using Microsoft.Extensions.Primitives; | |
using System; | |
using System.IO; | |
public class Startup | |
{ | |
public IConfigurationRoot Configuration { get; } | |
public IHostingEnvironment HostingEnvironment { get; } | |
public IApplicationEnvironment ApplicationEnvironment { get; } | |
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv) | |
{ | |
HostingEnvironment = env; | |
ApplicationEnvironment = appEnv; | |
Configuration = BuildConfiguration(env, appEnv); | |
} | |
public void ConfigureServices(IServiceCollection services) | |
{ | |
services.AddLogging(); | |
services.AddMvc(); | |
if (IsMono()) | |
{ | |
Console.WriteLine("Replaced default FileProvider with a wrapped synchronous one\n Since Mono has a bug on asynchronous filestream.\n See https://github.com/aspnet/Hosting/issues/604"); | |
UseSynchronousFileProvider(services, ApplicationEnvironment); | |
} | |
} | |
private static IConfigurationRoot BuildConfiguration(IHostingEnvironment env, IApplicationEnvironment appEnv) | |
{ | |
var builder = new ConfigurationBuilder() | |
.SetBasePath(appEnv.ApplicationBasePath) | |
.AddJsonFile("appsettings.json", optional: true) | |
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); | |
builder.AddEnvironmentVariables(); | |
return builder.Build(); | |
} | |
static void UseSynchronousFileProvider(IServiceCollection services, IApplicationEnvironment appEnv) | |
{ | |
services.Configure<RazorViewEngineOptions>(opt => | |
{ | |
var physicalFileProvider = new PhysicalFileProvider(appEnv.ApplicationBasePath); | |
opt.FileProvider = new WrappedSynchronousFileProvider(physicalFileProvider); | |
}); | |
} | |
static bool IsMono() | |
{ | |
return Type.GetType("Mono.Runtime") != null; | |
} | |
} | |
public class WrappedSynchronousFileProvider : IFileProvider | |
{ | |
IFileProvider _original; | |
public WrappedSynchronousFileProvider(IFileProvider original) | |
{ | |
_original = original; | |
} | |
public IDirectoryContents GetDirectoryContents(string subpath) | |
{ | |
return _original.GetDirectoryContents(subpath); | |
} | |
public IFileInfo GetFileInfo(string subpath) | |
{ | |
var originalFileInfo = _original.GetFileInfo(subpath); | |
var isPhysical = originalFileInfo.GetType().FullName.EndsWith("PhysicalFileInfo"); | |
if (!isPhysical) | |
{ | |
return originalFileInfo; | |
} | |
return new WrappedSynchronousFileInfo(originalFileInfo); | |
} | |
public IChangeToken Watch(string filter) | |
{ | |
return _original.Watch(filter); | |
} | |
public class WrappedSynchronousFileInfo : IFileInfo | |
{ | |
IFileInfo _original; | |
public WrappedSynchronousFileInfo(IFileInfo original) | |
{ | |
_original = original; | |
} | |
public bool Exists | |
{ | |
get | |
{ | |
return _original.Exists; | |
} | |
} | |
public bool IsDirectory | |
{ | |
get | |
{ | |
return _original.IsDirectory; | |
} | |
} | |
public DateTimeOffset LastModified | |
{ | |
get | |
{ | |
return _original.LastModified; | |
} | |
} | |
public long Length | |
{ | |
get | |
{ | |
return _original.Length; | |
} | |
} | |
public string Name | |
{ | |
get | |
{ | |
return _original.Name; | |
} | |
} | |
public string PhysicalPath | |
{ | |
get | |
{ | |
return _original.PhysicalPath; | |
} | |
} | |
public Stream CreateReadStream() | |
{ | |
// @jijiechen: replaced implemention from https://github.com/aspnet/FileSystem/blob/32822deef3fd59b848842a500a3e989182687318/src/Microsoft.Extensions.FileProviders.Physical/PhysicalFileInfo.cs#L30 | |
//return new FileStream( | |
// PhysicalPath, | |
// FileMode.Open, | |
// FileAccess.Read, | |
// FileShare.ReadWrite, | |
// 1024 * 64, | |
// FileOptions.Asynchronous | FileOptions.SequentialScan); | |
// Note: Buffer size must be greater than zero, even if the file size is zero. | |
return new FileStream( | |
PhysicalPath, | |
FileMode.Open, | |
FileAccess.Read, | |
FileShare.ReadWrite, | |
1024 * 64, | |
FileOptions.SequentialScan); | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment