get folder list in ASP.NET Core constructor

  • (2 Pages)
  • +
  • 1
  • 2

20 Replies - 559 Views - Last Post: 08 November 2018 - 08:54 AM Rate Topic: -----

#1 andrewsw   User is offline

  • head thrashing
  • member icon

Reputation: 6630
  • View blog
  • Posts: 27,105
  • Joined: 12-December 12

get folder list in ASP.NET Core constructor

Posted 06 November 2018 - 08:05 AM

[ASP.NET Core]

In my controller's constructor I want to get a list of subfolders in a folder of the site, so that I can inject this (as a static list) into controller-actions that need this list.

I cannot use Url.Content in the following code, because that does not exist until an Action is called:
    public class HomeController : Controller
    {
        private static List<string> folderNames;

        public HomeController()
        {
            folderNames = new List<string>();

            string path = this.Url.Content("~/Playlist");

            foreach (var folder in Directory.GetDirectories(path))
            {
                folderNames.Add(folder);
            }
        }

I cannot use just string path = "/Playlist"; because that, when testing locally, is looking for something in C:

How can I resolve this without putting in a full, absolute, path for the site? Nor with copying the code to several actions?

Actually, it does not work in an Action either:

Quote

DirectoryNotFoundException: Could not find a part of the path 'C:\Playlist'.


Is This A Good Question/Topic? 0
  • +

Replies To: get folder list in ASP.NET Core constructor

#2 modi123_1   User is offline

  • Suitor #2
  • member icon



Reputation: 14507
  • View blog
  • Posts: 58,158
  • Joined: 12-June 08

Re: get folder list in ASP.NET Core constructor

Posted 06 November 2018 - 08:18 AM

Is "playlist" in your wwwroot, or elsewhere?

Typically I abuse the HostingEnvironment object out of the constructor.

        public IndexModel(IHostingEnvironment env)
        {
            string a = env.WebRootPath;
            string b = env.ContentRootPath;
        }

Was This Post Helpful? 1
  • +
  • -

#3 andrewsw   User is offline

  • head thrashing
  • member icon

Reputation: 6630
  • View blog
  • Posts: 27,105
  • Joined: 12-December 12

Re: get folder list in ASP.NET Core constructor

Posted 06 November 2018 - 08:29 AM

Yes, Playlist is in wwwroot.

I'll give that a bash.
Was This Post Helpful? 0
  • +
  • -

#4 andrewsw   User is offline

  • head thrashing
  • member icon

Reputation: 6630
  • View blog
  • Posts: 27,105
  • Joined: 12-December 12

Re: get folder list in ASP.NET Core constructor

Posted 06 November 2018 - 08:36 AM

Great, thanks, works!

It is cheating though... the file provider should be dependency injected ;) No worries ;)

    public class HomeController : Controller
    {
        private static List<string> folderNames;

        public HomeController(IHostingEnvironment env)
        {
            folderNames = new List<string>();

            var provider = new PhysicalFileProvider(env.ContentRootPath + "\\wwwroot");
            var contents = provider.GetDirectoryContents("Playlist");

            foreach (var item in contents)
            {
                if (item.IsDirectory)
                    folderNames.Add(item.Name);
            }

        }

Was This Post Helpful? 1
  • +
  • -

#5 modi123_1   User is offline

  • Suitor #2
  • member icon



Reputation: 14507
  • View blog
  • Posts: 58,158
  • Joined: 12-June 08

Re: get folder list in ASP.NET Core constructor

Posted 06 November 2018 - 08:38 AM

Yeah there's a few of those "hidden and magic" things I pull out of the constructor. IConfiguration to get connection strings, those HostingEnvironment crap, etc. An annoyance, for sure, with Core 2.
Was This Post Helpful? 1
  • +
  • -

#6 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6508
  • View blog
  • Posts: 22,284
  • Joined: 05-May 12

Re: get folder list in ASP.NET Core constructor

Posted 06 November 2018 - 11:43 AM

Perhaps I'm missing something... Why not have an IFileProvider as a dependency that your controller needs?
Was This Post Helpful? 1
  • +
  • -

#7 andrewsw   User is offline

  • head thrashing
  • member icon

Reputation: 6630
  • View blog
  • Posts: 27,105
  • Joined: 12-December 12

Re: get folder list in ASP.NET Core constructor

Posted 06 November 2018 - 02:56 PM

Yes, you are right, that is the missing step that I was referring to, cf cheating.

[Under constant pressure to 'complete' and not getting the time to do things 'properly'...]

Still, I would like to spend a few minutes pursuing it. Startup.cs should lock, and inject, the provider access to subfolders from wwwroot. The Playlist action then looks in a named folder to list the available videos so needs access to the provider, not 'openly' via the hosting environment.

I'll look at it again tomorrow.
Was This Post Helpful? 0
  • +
  • -

#8 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6508
  • View blog
  • Posts: 22,284
  • Joined: 05-May 12

Re: get folder list in ASP.NET Core constructor

Posted 06 November 2018 - 07:48 PM

Also, isn't the constructor doing a lot of work enumerating the files/folder? Shouldn't that be delayed until the data is really needed or during an "initialize" method?
Was This Post Helpful? 0
  • +
  • -

#9 andrewsw   User is offline

  • head thrashing
  • member icon

Reputation: 6630
  • View blog
  • Posts: 27,105
  • Joined: 12-December 12

Re: get folder list in ASP.NET Core constructor

Posted 07 November 2018 - 02:01 AM

The data is needed on every page (although there are only a couple of pages currently) because it provides the navbar buttons-text. The navigation is to the folder-names and the playlist is then provided by the videos in that folder.

Basically, the idea is, that a colleague would create a folder inside /Playlist, put some videos in there, and then this folder appears as a navbar button in the UI.
Was This Post Helpful? 0
  • +
  • -

#10 andrewsw   User is offline

  • head thrashing
  • member icon

Reputation: 6630
  • View blog
  • Posts: 27,105
  • Joined: 12-December 12

Re: get folder list in ASP.NET Core constructor

Posted 07 November 2018 - 08:05 AM

I published this and VS only minimised the earliest version of my site.css, how annoying. You'd think it would always minimise, or not at all!?
Was This Post Helpful? 0
  • +
  • -

#11 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7295
  • View blog
  • Posts: 15,185
  • Joined: 16-October 07

Re: get folder list in ASP.NET Core constructor

Posted 07 November 2018 - 08:07 AM

Hmm... passing IHostingEnvironment to controllers feels a little like a global. I'd make a class that did what was needed and put that in the service environment for controllers to pluck out.

I was curious how far I could get with a .NET Core 2.1 console demo.

This is what I got.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
// using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;


// Not this, tis console Install-Package Microsoft.AspNetCore.Hosting
// this Install-Package Microsoft.Extensions.Hosting

namespace ConsoleApp1 {
    interface IFolderListProvider {
        IEnumerable<string> Folders { get; }
    }
    class HomeController {
        private readonly IFolderListProvider flp;

        public HomeController(IFolderListProvider flp) {
            this.flp = flp;
        }

        public void Test() {
            Debug.WriteLine("HomeController called");
            Debug.WriteLine(string.Join("\n", flp.Folders));
        }
    }
    class Program {

        static void Main(string[] args) {
            Run(InitServiceProvider());
        }
        static void Run(IServiceProvider servicesProvider) {
            var x = servicesProvider.GetRequiredService<HomeController>();
            x.Test();
        }

        class FolderListProvider : IFolderListProvider {
            private readonly IFileProvider provider;
            private string DirName { get; } = ".";
            public FolderListProvider(IHostingEnvironment env) {
                Debug.WriteLine("FolderListProvider called: " + env.ContentRootPath);
                // this.provider = new PhysicalFileProvider(env.ContentRootPath);
                this.provider = env.ContentRootFileProvider;
            }
            public IEnumerable<string> Folders => provider
                .GetDirectoryContents(DirName)
                .Where(x => x.IsDirectory)
                .Select(x => x.Name);
        }


        // because this is a console app, we're faking this
        class ConsoleHost : IHostingEnvironment {
            public string EnvironmentName { get; set; } = "Alice";
            public string ApplicationName { get; set; } = "Fred";
            public string ContentRootPath { get; set; } = @"C:\"; // System.IO.Directory.GetCurrentDirectory();
            public IFileProvider ContentRootFileProvider { get; set; }
            public ConsoleHost() { ContentRootFileProvider = new PhysicalFileProvider(ContentRootPath); }
        }


        private static IServiceProvider InitServiceProvider() {
            var services = new ServiceCollection();
            services.AddSingleton<IHostingEnvironment, ConsoleHost>();
            services.AddSingleton<IFolderListProvider, FolderListProvider>();
            services.AddTransient<HomeController>();
            return services.BuildServiceProvider();
        }

    }
}



In practice, I tend to have something like IWebApp or IRepo floating about that was initialized on startup and has all the moving parts of what I'm doing. The injection thing is neat, but it can get real messy real fast.
Was This Post Helpful? 1
  • +
  • -

#12 andrewsw   User is offline

  • head thrashing
  • member icon

Reputation: 6630
  • View blog
  • Posts: 27,105
  • Joined: 12-December 12

Re: get folder list in ASP.NET Core constructor

Posted 07 November 2018 - 11:13 AM

Thank you for this baavgai

Sometimes it is the little things that bring joy - I like your LINQ so introduced Where() for nicer code:

            var contents = provider.GetDirectoryContents("Playlist");

            foreach (var item in contents.Where(f => f.IsDirectory))
            {
                folderNames.Add(item.Name);
            }

Was This Post Helpful? 0
  • +
  • -

#13 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7295
  • View blog
  • Posts: 15,185
  • Joined: 16-October 07

Re: get folder list in ASP.NET Core constructor

Posted 07 November 2018 - 12:36 PM

Still not sure I approve of caching that list. :P

However, if you must, some alternate inits are:
folderNames.AddRange(provider.GetDirectoryContents("Playlist").Where(f => f.IsDirectory).Select(x => x.Name));
// or
folderNames = new List<string>(provider.GetDirectoryContents("Playlist").Where(f => f.IsDirectory).Select(x => x.Name));
// or 
folderNames = provider.GetDirectoryContents("Playlist").Where(f => f.IsDirectory).Select(x => x.Name).ToList();



Beware of that static. It can burn you. Or at least it could in older ASP.NET setups. Life cycles in such architecture can be a little wonky. If you really want to cache, you could cache in your injected instance. Of course, life cycles in DI add another level of odd. You might want to read this: https://blog.markvin...n-asp-net-core/
Was This Post Helpful? 1
  • +
  • -

#14 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6508
  • View blog
  • Posts: 22,284
  • Joined: 05-May 12

Re: get folder list in ASP.NET Core constructor

Posted 07 November 2018 - 02:10 PM

View Postandrewsw, on 07 November 2018 - 05:01 AM, said:

The data is needed on every page (although there are only a couple of pages currently) because it provides the navbar buttons-text. The navigation is to the folder-names and the playlist is then provided by the videos in that folder.

Why can't that data be pulled until it is actually needed? I personally think that constructors should be a simple as possible. It falls in line with MSDN's Constructor Design recommendations:

Quote

✓ DO minimal work in the constructor.

Constructors should not do much work other than capture the constructor parameters. The cost of any other processing should be delayed until required.


If for one reason or another, you really need to do some heavy lifting work in a constructor, then you'll need to start worrying about what happens if an exception is thrown within the constructor and what state the object will be in after such an exception. (In the same design guide above, Microsoft does suggest throwing exceptions from constructors if you need to.) If your team is under that much pressure to complete stuff, then you'll likely want to avoid the problems described here regarding exceptions:
Cleaner, more elegant, and wrong
Cleaner, more elegant, and harder to recognize

As a side note: Unless your HomeController is a singleton or only one instance is ever created for the entire lifetime of the application, the static folderNames list is going to start getting duplicates due to the second and succeeding calls to the constructor.
Was This Post Helpful? 0
  • +
  • -

#15 modi123_1   User is offline

  • Suitor #2
  • member icon



Reputation: 14507
  • View blog
  • Posts: 58,158
  • Joined: 12-June 08

Re: get folder list in ASP.NET Core constructor

Posted 07 November 2018 - 02:19 PM

Sure... You can pass pass off the 'IHostingEnvironment env' constructor param to a readonly variable and use it when ever. No need to decode it all until the onget. :^:
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2