Image Directories

Topics: Troubleshooting
Apr 22, 2011 at 3:49 AM

I am working on a site that handles a lot of images. I've created a virtual directory under the media folder and am trying to resolve the images. For example, I am trying to resolve media/myimages/1.jpg. I've added an ignore route in global.asax as Route.IgnoreRoute("media/myimages/{*pathinfo}).

The html is just <img src="media/myimages/1.jpg"/>

But I just get a 404. How should I be doing this?

Apr 22, 2011 at 4:36 AM

Maybe you could try the new Media Folder module were you can configure a specific url for those images, which will then be served y IIS directly, and you can also use it to define an external Media folder, on a CDN or static file server for instance.

Apr 22, 2011 at 1:24 PM

Where do I configure the specific URL for those images with the media module?

BTW, I got it to work by copying the web.config from the media folder into the route of my images directory.

Apr 22, 2011 at 1:56 PM
Edited Apr 22, 2011 at 1:57 PM

Hi sebastien,

I managed to get a Stack Overflow exception when I enabled both Media Folder and also a module I'm working on!

I *suspect* it's because I'm injecting an IStorageProvider dependency, and in your RemoteStorageProvider implementation you suppress the default FileSystemStorageProvider.

So I don't know if this is a fault in the suppression mechanism, or if it's in the way I'm using dependencies. Literally all I did was enable the features. The stack trace seemed to show that the system was circling around ContentHandlers and some of the Media Folder settings classes. I couldn't see any of my classes in the stack trace, but I do have a ContentHandler into which I'm injecting a service dependency, and one of that service's dependencies ultimately pulls in IStorageProvider; so I think that's where it might begin from.

Let me just explain about what I'm working on;

I don't know if you saw a discussion about a media system that myself and gkumik were proposing. I've been working on this for a couple of weeks; it's called Media Garden and I'm almost ready to launch the codeplex site. What it does is basically create some additional levels of abstraction for media content. So it treats media as actual content items, and hides away the storage mechanism. This means that (for instance) a "Video" content type could be playing video from a local file, or an external URL, or even an embedded Youtube video. Media sources can be defined to pull in media content from anything; file systems, feeds, URLs, or any implementations that people create; database storage would be a good example. For the default "file system media source" implementation I'm using IStorageProvider to read files from the disk. So your media folder module is really useful in this scenario if users want to mess with the file storage, without implementing an entirely new media source. Because of this I was interested in your module and wanted to check compatibility. Unfortunately it crashed IIS :(

Now I realise you might say I should be using IMediaService instead of IStorageProvider. But there are problems with this; IMediaService lacks any method to read a file's data, or even to get information about a specific file (it only has a GetMediaFiles method, not a GetMediaFile one). Finally IMediaService places restrictions on file extensions as configured in settings; whereas in my system each component declares its supported file extensions and I wanted to avoid an extra setup task of the user having to declare which types of files were ok.

If you want a copy of the code to find out where this stack overflow is coming from, or if you're just interested in the project anyway ;) - I could add you as a developer on the codeplex project so you can get at the repository in the meantime before it's published.

Apr 22, 2011 at 2:06 PM

There can be only one IStorageProvider. So why don't you provide yours as a feature, thus it could be disabled if someone wanted to switch it. Otherwise I can take a look at he issue.

Apr 22, 2011 at 2:18 PM

I'm not replacing it, I'm just trying to inject it as a dependency.

Apr 22, 2011 at 2:20 PM
Edited Apr 22, 2011 at 2:21 PM



    public class FileSystemQueryFilter : IMediaQueryFilter
        private readonly IOrchardServices _services;
        private readonly IMediaService _orchardMediaService;
        private readonly IStorageProvider _storageProvider;
        /// <summary>
        /// Injecting the default orchard media service and storage provider for file handling
        /// </summary>
        /// <param name="services"></param>
        /// <param name="orchardMediaService"></param>
        public FileSystemQueryFilter(
            IOrchardServices services, 
            IMediaService orchardMediaService,
            IStorageProvider storageProvider)
            _services = services;
            _orchardMediaService = orchardMediaService;
            _storageProvider = storageProvider;


Apr 22, 2011 at 3:48 PM

It should work then :/ Or maybe the package is bad. Can you try with the source code from codeplex instead ?

Apr 22, 2011 at 4:12 PM

Just tried; still the same. I emphasize that the module enables fine on its own, just when I enable my module as well the crash happens. Doesn't seem to matter what order I enable them in either. Unfortunately no error log is generated because the overflow crashes everything before the log could be saved!

Apr 22, 2011 at 5:32 PM

Try setting breakpoints in your constructor, or to the last known line in the stack trace.

Apr 22, 2011 at 6:21 PM
Edited Apr 22, 2011 at 6:28 PM

The breakpoint gets hit, but it only happens once and I think it's before the Media Folder feature even gets enabled. At that point the IStorageProvider being imported was the Orchard default one.

I've copied the entire call stack from VWD; it doesn't reference any of my classes. But it is repeatedly calling this line in the Contrib.MediaFolder.Services.RemoteStorageProvider constructor:


            var configuration = orchardServices.WorkContext.CurrentSite.As<RemoteStorageSettingsPart>().Record;


So I think what's happening is: because that code is accessing a ContentItem or Part, all the ContentHandlers are being invoked. And because my handler ultimately has a dependency on IStorageProvider, Autofac is trying to create another instance of RemoteStorageProvider to satisfy that dependency. Which then causes all the handlers to get instanced again ... and so ad infinitum. I'm thinking this would be a problem for any ContentHandler that imported either IStorageProvider or IMediaService. I guess the solution would be to move that call out of the constructor. It's actually a circular dependency but Autofac is unable to detect it because there's some indirection taking place via the WorkContext.CurrentSite call.

The call stack looks as follows. The calls are repeated indefinitely so I've cut it down to just one loop:


 	Contrib.MediaFolder.dll!Contrib.MediaFolder.Services.RemoteStorageProvider.RemoteStorageProvider(Orchard.Environment.Configuration.ShellSettings settings, Orchard.IOrchardServices orchardServices) Line 22 + 0x16 bytes	C#
 	[External Code]	
 	Orchard.Framework.DLL!Orchard.ContentManagement.DefaultContentManager.Handlers.get() Line 54 + 0x16 bytes	C#
 	Orchard.Framework.DLL!Orchard.ContentManagement.DefaultContentManager.New(string contentType) Line 77 + 0x8 bytes	C#
 	Orchard.Framework.DLL!Orchard.ContentManagement.DefaultContentManager.Get(int id, Orchard.ContentManagement.VersionOptions options) Line 139 + 0x4a bytes	C#
 	Orchard.Framework.DLL!Orchard.ContentManagement.DefaultContentQuery.Slice.AnonymousMethod__0(Orchard.ContentManagement.Records.ContentItemVersionRecord x) Line 141 + 0x41 bytes	C#
 	[External Code]	
 	Orchard.Framework.DLL!Orchard.Utility.Extensions.ReadOnlyCollectionExtensions.ToReadOnlyCollection(System.Collections.Generic.IEnumerable enumerable) Line 8 + 0x2e bytes	C#
 	Orchard.Framework.DLL!Orchard.ContentManagement.DefaultContentQuery.Slice(int skip, int count) Line 139 + 0x5c bytes	C#
 	Orchard.Framework.DLL!Orchard.ContentManagement.DefaultContentQuery.ContentQuery.Orchard.ContentManagement.IContentQuery.Slice(int skip, int count) Line 188 + 0x19 bytes	C#
 	Orchard.Core.DLL!Orchard.Core.Settings.Services.SiteService.GetSiteSettings.AnonymousMethod__0(Orchard.Caching.AcquireContext ctx) Line 30 + 0x4c bytes	C#
 	Orchard.Framework.DLL!Orchard.Caching.Cache.CreateEntry(string k, System.Func,int> acquire) Line 41 + 0x17 bytes	C#
 	Orchard.Framework.DLL!Orchard.Caching.Cache.Get.AnonymousMethod__0(string k) Line 17 + 0x43 bytes	C#
 	[External Code]	
 	Orchard.Framework.DLL!Orchard.Caching.Cache.Get(string key, System.Func,int> acquire) Line 15 + 0xa3 bytes	C#
 	Orchard.Framework.DLL!Orchard.Caching.DefaultCacheManager.Get(string key, System.Func,int> acquire) Line 33 + 0x69 bytes	C#
 	Orchard.Core.DLL!Orchard.Core.Settings.Services.SiteService.GetSiteSettings() Line 29 + 0x4b bytes	C#
 	Orchard.Framework.DLL!Orchard.Settings.CurrentSiteWorkContext.Get(string name) Line 13 + 0x12 bytes	C#
 	Orchard.Framework.DLL!Orchard.Environment.WorkContextImplementation.FindResolverForState.AnonymousMethod__0(Orchard.IWorkContextStateProvider wcsp) Line 32 + 0x4b bytes	C#
 	[External Code]	
 	Orchard.Framework.DLL!Orchard.Environment.WorkContextImplementation.FindResolverForState(string name) Line 32 + 0xe8 bytes	C#
 	[External Code]	
 	Orchard.Framework.DLL!Orchard.Environment.WorkContextImplementation.GetState(string name) Line 27 + 0x56 bytes	C#
 	Orchard.Framework.DLL!Orchard.WorkContext.CurrentSite.get() Line 25 + 0x22 bytes	C#
>	Contrib.MediaFolder.dll!Contrib.MediaFolder.Services.RemoteStorageProvider.RemoteStorageProvider(Orchard.Environment.Configuration.ShellSettings settings, Orchard.IOrchardServices orchardServices) Line 22 + 0x16 bytes	C#
 	[External Code]	
 	The maximum number of stack frames supported by Visual Studio has been exceeded.



BTW; I've now published the Media Garden project and it's up at: All you need to do to reproduce this is enable both the Media Garden and Media Folder features.

Thanks for looking at this!