简体   繁体   English

在不经过OWIN的情况下提供静态文件

[英]Serving static files without going through OWIN

Short: For each and every request a new OWIN context is created, I would like to be able to prevent this for certain resource types or paths (images, css, js). 简短:对于每个请求创建一个新的OWIN上下文,我希望能够针对某些资源类型或路径(图像,css,js)阻止这种情况。

Full: In our application start-up we register a dbcontext creation delegate so that the dbcontext will be created just once per request. 完全:在我们的应用程序启动中,我们注册了一个dbcontext创建委托,以便每个请求只创建一次dbcontext。

public virtual void Configuration(IAppBuilder app)
{
    app.CreatePerOwinContext(Factory.DbContextCreateDelegate);
}

If a client makes a request for the style sheet, an OWIN context will be created an thus a new dbcontext will also be created. 如果客户端请求样式表,则将创建OWIN上下文,因此还将创建新的dbcontext。 I would like to be able to either not create the OwinContext at all, or at least to be able to prevent some of it's "on create" callbacks to be executed for certain request types/paths. 我希望能够根本不创建OwinContext,或者至少能够阻止某些请求类型/路径执行某些“on create”回调。

Alternatively, as I can see why the approach of (partially) "disabling" OWIN would lead to problems, I would like to hear what the best practice would be? 或者,正如我所知,为什么(部分)“禁用”OWIN的方法会导致问题,我想听听最佳做法是什么? How can I serve a static file without creating a database context for each request? 如何在不为每个请求创建数据库上下文的情况下提供静态文件? ( small remark here is that our static files are embedded resources served using a virtual path provider... The problem also occurs for "normal" static files. ) 这里小小的一点是我们的静态文件是使用虚拟路径提供程序提供的嵌入式资源...“普通”静态文件也会出现问题。

Background: Yesterday I started noticing that every now and then some parts of our application did not load. 背景:昨天我开始注意到我们的应用程序的某些部分偶尔没有加载。 Sometimes it was single image, sometimes the entire CSS file. 有时它是单个图像,有时是整个CSS文件。 After some investigation I saw that some requests were throwing http 500 errors, the exception thrown was often things like a SQL connection time out (but also other exceptions). 经过一些调查后,我看到一些请求抛出了http 500错误,抛出的异常通常是SQL连接超时(但也有其他异常)。

While we are of course trying to fix those exceptions. 虽然我们当然试图修复这些例外。 I do believe it to be complete nonsense for our application to set up a database connection when a client makes a request for a single image... That's about 10 database connections for a single page request??? 我确实认为,当客户端请求单个图像时,我们的应用程序设置数据库连接完全是胡说八道...这是单个页面请求的大约10个数据库连接???

Seems to me like such an obvious problem but I have been Googling all of yesterday and found nothing close to a solution or work around. 对我来说就像这样一个明显的问题,但我昨天一直在谷歌搜索,没有找到任何接近解决方案或解决方法。 What am I missing stack? 我错过了什么堆栈?

EDIT: I just tried an approach where I did not actually create the dbcontext but a stub instead. 编辑:我只是尝试了一种方法,我没有实际创建dbcontext而是创建存根。 In hindsight this obviously is not the solution to this problem as the OwinContext tries to continue it's process and will critically fail when it tries to get the user from the database using that stub dbcontext. 事后看来,这显然不是这个问题的解决方案,因为OwinContext试图继续它的进程,并且当它试图使用该存根dbcontext从数据库中获取用户时将严重失败。 The dbcontext is not the problem, I need to completely bypass Owin... I think... dbcontext不是问题,我需要完全绕过Owin ......我想......

Microsoft.Owin.StaticFiles to the rescue! Microsoft.Owin.StaticFiles来救援!

I would still like to know why this is not enabled by default in the MVC OWIN template application. 我仍然想知道为什么在MVC OWIN模板应用程序中默认不启用它。 But for most cases it is just a matter of a single line of code to enable static files in OWIN. 但是对于大多数情况,在OWIN中启用静态文件只需要一行代码。

BASIC SCENARIO 基本情景

Setting up Owin to treat a folder and its contents as static files: 设置Owin将文件夹及其内容视为静态文件:

public virtual void Configuration(IAppBuilder app)
{
    app.UseStaticFiles("/PathToYourStaticFilesFolder");
}

SCENARIO WITH EMBEDDED RESOURCES 具有嵌入资源的场景

Unfortunately for me we are serving most of our static content as embedded resources using an implementation of a VirtualPathProvider . 不幸的是,我们使用VirtualPathProvider的实现将大部分静态内容作为嵌入式资源提供。 Luckily this is also relatively easy to implement, though it does require writing a wrapper around your VirtualPathProvider to implement the required IFileSystem and IFileInfo interfaces that OWIN requires. 幸运的是,这也相对容易实现,但它确实需要在VirtualPathProvider周围编写一个包装器来实现OWIN所需的IFileSystem和IFileInfo接口。

Relevant parts of code from my final solution, not posting the entire VirtualPathProvider as there are plenty of examples for that online. 我的最终解决方案的代码的相关部分,而不是发布整个VirtualPathProvider,因为有大量的在线示例。

The wrapper around the VirtualPathProvider: VirtualPathProvider周围的包装器:

/// <summary>
/// Represents a virtual file system.
/// A wrapper around <see cref="MyCustomVirtualPathProvider"/> implementing
/// IFileSystem for use in Owin StaticFiles.
/// </summary>
public class VirtualFileSystem : IFileSystem
{
    /// <summary>
    /// Locate the path in the virtual path provider
    /// </summary>
    /// <param name="subpath">The path that identifies the file</param>
    /// <param name="fileInfo">The discovered file if any</param>
    /// <returns>
    /// True if a file was located at the given path
    /// </returns>
    public bool TryGetFileInfo(string subpath, out IFileInfo fileInfo)
    {
        MyCustomVirtualPathProvider virtualPathProvider = 
            (MyCustomVirtualPathProvider) HostingEnvironment.VirtualPathProvider;

        if (!virtualPathProvider.FileExists(subpath))
        {
            fileInfo = null;
            return false;
        }

        try
        {
            EmbeddedResourceVirtualFile virtualFile = 
                (EmbeddedResourceVirtualFile) virtualPathProvider.GetFile(subpath);

            fileInfo = new EmbeddedResourceFileInfo(virtualFile);

            return true;
        }
        catch (InvalidCastException)
        {
            fileInfo = null;
            return false;
        }
    }

    /// <summary>
    /// Not used in our implementation
    /// </summary>
    /// <param name="subpath"></param>
    /// <param name="contents"></param>
    /// <returns></returns>
    public bool TryGetDirectoryContents(string subpath, out IEnumerable<IFileInfo> contents)
    {
        throw new NotImplementedException();
    }
}

The wrapper around the embedded resource: 嵌入资源的包装器:

/// <summary>
/// Represents the file info of an embedded resource
/// </summary>
public class EmbeddedResourceFileInfo : IFileInfo
{
    /// <summary>
    /// Return file contents as readonly stream. Caller should dispose stream when complete.
    /// </summary>
    /// <returns>
    /// The file stream
    /// </returns>
    public Stream CreateReadStream()
    {
        return virtualFile.Open();
    }

    /// <summary>
    /// The length of the file in bytes, or -1 for a directory info
    /// </summary>
    public long Length => virtualFile.Length;

    /// <summary>
    /// The name of the file
    /// </summary>
    public string Name => virtualFile.Name;

    /// <summary>
    /// When the file was last modified
    /// </summary>
    public DateTime LastModified => virtualFile.LastModified;

    /// <summary>
    /// Returns null as these are virtual files
    /// </summary>
    public string PhysicalPath => null;

    /// <summary>
    /// True for the case TryGetDirectoryContents has enumerated a sub-directory
    /// </summary>
    public bool IsDirectory => virtualFile.IsDirectory;

    private readonly EmbeddedResourceVirtualFile virtualFile;

    /// <summary>
    /// Construct using a <see cref="EmbeddedResourceVirtualFile"/>
    /// </summary>
    /// <param name="virtualFile"></param>
    public EmbeddedResourceFileInfo(EmbeddedResourceVirtualFile virtualFile)
    {
        this.virtualFile = virtualFile;
    }
}

And lastly, setting up Owin to use our virtual file system: 最后,设置Owin以使用我们的虚拟文件系统:

public virtual void Configuration(IAppBuilder app)
{
    var staticFilesOptions = new StaticFileOptions
    {
        FileSystem = new VirtualFileSystem()
    };
    app.UseStaticFiles(staticFilesOptions);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM