Skip to content

Instantly share code, notes, and snippets.

@choudeshell
Created March 16, 2013 01:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save choudeshell/5174495 to your computer and use it in GitHub Desktop.
Save choudeshell/5174495 to your computer and use it in GitHub Desktop.
Embedded Resource Provider for Katana
using Microsoft.Owin.FileSystems;
using System;
using System.Reflection;
namespace Metrical.Providers
{
public class ResourceFileInfo : IFileInfo
{
private string _filePath;
private Assembly _assembly;
public ResourceFileInfo(string file)
{
_filePath = file;
_assembly = Assembly.GetExecutingAssembly();
}
public System.IO.Stream CreateReadStream()
{
return _assembly.GetManifestResourceStream(_filePath);
}
public bool IsDirectory
{
get
{
return false;
}
}
public DateTime LastModified
{
get
{
return DateTime.Now;
}
}
public long Length
{
get
{
using (var stream = CreateReadStream())
{
return stream.Length;
}
}
}
public string Name
{
get
{
return _filePath;
}
}
public string PhysicalPath
{
get
{
return _filePath;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.Owin.FileSystems;
namespace Metrical.Providers
{
public class ResourceFileSystemProvider : IFileSystem
{
public bool TryGetDirectoryContents(string subpath, out IEnumerable<IFileInfo> contents)
{
throw new NotImplementedException();
}
public bool TryGetFileInfo(string subpath, out IFileInfo fileInfo)
{
var flatPath = subpath.Replace('/', '.');
var assembly = Assembly.GetExecutingAssembly();
var assemblyName = assembly.GetName().Name;
var path = String.Format("{0}{1}", assemblyName, flatPath);
var resourceNames = assembly.GetManifestResourceNames();
if (resourceNames.Contains(path))
{
fileInfo = new ResourceFileInfo(path);
return true;
}
fileInfo = null;
return false;
}
}
}
app.UseStaticFiles(options =>
{
options.WithFileSystem(new ResourceFileSystemProvider());
});
@loudej
Copy link

loudej commented Mar 17, 2013

Looks great! We're thinking of adding something like this to the Microsoft.Owin.FileSystems eventually, but who knows when that'll happen - things are pretty busy. Are you thinking of turning this into a nuget pkg?

Let's see... For notes...

It would be nice if the ResourceFileSystemProvider had _assembly field, and something like a _namespaceBase or _pathBase string... That way you could have static files in any assembly. Also you could use the _namespaceBase to specify a "sub-folder" for embedded files, so you're not exposing all your resources.

Is there a different way to know if a resource exists other than enumerating GetManifestResourceNames? I guess of the other ways throw an exception that's no good. What if the ResourceFileSystemProvider did the enumeration once when it was initialized? It could even filter where they start with the base at the same time - so that list would be the full "known-servable" set off the bat.

For LastModified consider using the last modified date of the assembly file? That should help get 304-not modified responses, and feed into etag response header well, and should work well with static compression module.

Ah! You should return null for PhysicalPath - that property is used to know if a file can be sent directly from a disk or network path - doesn't apply in this case. (Sorry for lack of documentation :) )

The _name is also an odd one - it is used by directory browser... Probably should return the last path segment of the original url?

Good luck!

@choudeshell
Copy link
Author

It would be nice if the ResourceFileSystemProvider had _assembly field, and something like a _namespaceBase or _pathBase string... That way you could have static files in any assembly. Also you could use the _namespaceBase to specify a "sub-folder" for embedded files, so you're not exposing all your resources.

Good idea. I'll add a constructor for ResourceFileSystemProvider that takes in either a string array of assembly names or an array of type assembly. I would rather have them explicitly defined than to pull all assemblies in a certain path.

Is there a different way to know if a resource exists other than enumerating GetManifestResourceNames? I guess of the other ways throw an exception that's no good. What if the ResourceFileSystemProvider did the enumeration once when it was initialized? It could even filter where they start with the base at the same time - so that list would be the full "known-servable" set off the bat.

In the final version I only enumerate the files in an assembly once then I cache the results.

For LastModified consider using the last modified date of the assembly file? That should help get 304-not modified responses, and feed into etag response header well, and should work well with static compression module.

Heh. Why didn't I think of that.

Ah! You should return null for PhysicalPath - that property is used to know if a file can be sent directly from a disk or network path - doesn't apply in this case. (Sorry for lack of documentation :) )

Where is the best place to pull-request documentation? I don't mind contributing.

@Tratcher
Copy link

We're pulling StaticFiles off the shelf now, want to revisit this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment