get folder list in ASP.NET Core constructor

  • (2 Pages)
  • +
  • 1
  • 2

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

#16 andrewsw   User is offline

  • awks lol ffs
  • member icon

Reputation: 6697
  • View blog
  • Posts: 27,502
  • Joined: 12-December 12

Re: get folder list in ASP.NET Core constructor

Posted 07 November 2018 - 02:28 PM

I don't need it to be static, I can ditch that.

The folder list is used for nav buttons in _Layout so I thought it sensible to do that one job in the constructor ?

How else might it be done? I could create a function and call it in actions. Bear in mind that actions will also need to get the file list from the chosen folder.
Was This Post Helpful? 0
  • +
  • -

#17 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6719
  • View blog
  • Posts: 22,939
  • Joined: 05-May 12

Re: get folder list in ASP.NET Core constructor

Posted 07 November 2018 - 02:52 PM

:
Lazy<IEnumerable<string>> _folderNames;
public IEnumberable<string> FolderNames => _folderNames.Value;
:
public HomeController(IFileProvider provider)
{
    _folderNames = new Lazy<IEnumerable<string>>(() => provider.GetDirectoryContents("Playlist")
                                                               .Where(f => f.IsDirectory)
                                                               .Select(x => x.Name)
                                                               .ToList());
}
:



Take advantage of the Lazy<T>. In the constructor, just capture the provider into the lambda. That will get executed once later when someone tries to get the Value. In your _Layouts where you would have accessed your old folderNames, you would now access FolderNames.
Was This Post Helpful? 1
  • +
  • -

#18 andrewsw   User is offline

  • awks lol ffs
  • member icon

Reputation: 6697
  • View blog
  • Posts: 27,502
  • Joined: 12-December 12

Re: get folder list in ASP.NET Core constructor

Posted 07 November 2018 - 03:54 PM

Cool to see an example of Lazy<T>, ta.

I may not implement it though ;). The folder list is always evaluated anyway for the nav buttons in the shared _Layout.
Was This Post Helpful? 0
  • +
  • -

#19 andrewsw   User is offline

  • awks lol ffs
  • member icon

Reputation: 6697
  • View blog
  • Posts: 27,502
  • Joined: 12-December 12

Re: get folder list in ASP.NET Core constructor

Posted 08 November 2018 - 01:39 AM

Ignore the following question ;). The RouteData does contain the parameter I need, but only when I navigate to a page that has a parameter, doy!



A related question, I can use the following to check the current Action from the route:

    <ul class="nav navbar-nav navbar-right">

        @{ 
            var routeValues = ViewContext.RouteData.Values;
            var action = routeValues["action"].ToString().ToLower();

        }
        @foreach (var folder in (IEnumerable<string>)ViewData["FolderNames"])
        {
            <li class="@(action == folder.ToLower() ? "active-link" : "")">
                <a asp-controller="Home" asp-action="Playlist" asp-route-title="@folder">
                    <span class='glyphicon glyphicon-th-list'></span> @folder
                </a>
            </li>
        }
    </ul>

but it is not the action I need, it is the parameter value. RouteData only gives controller and action.

Is there a way to get this value in C# (without resorting to JS and parsing the url)?
Was This Post Helpful? 0
  • +
  • -

#20 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7380
  • View blog
  • Posts: 15,311
  • Joined: 16-October 07

Re: get folder list in ASP.NET Core constructor

Posted 08 November 2018 - 05:37 AM

View PostSkydiver, on 07 November 2018 - 04:52 PM, said:

Take advantage of the Lazy<T>.


Only, you took an IEnumerable and transformed it into a list: pick one. :P

The IEnumerable is lazy loaded by default. Which got me to thinking about how I might write some code to demonstrate that...
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace ServiceDemo {
    static class Ex {
        public static IEnumerable<string> FolderNames(this IFileProvider fp, string dirname) =>
            fp.GetDirectoryContents(dirname)
                .Where(x => x.IsDirectory)
                // be noisy .Select(x => x.Name);
                .Select((x, i) => { if (i == 0) { Debug.WriteLine("FolderNames hit"); } return x.Name; });
    }
    abstract class FolderTester {
        protected abstract IEnumerable<string> FolderNames { get; }
        public string Name { get; }
        public FolderTester(string loadType) {
            Name = loadType;
            Debug.WriteLine(loadType + " Loaded");
        }
        public int Test() =>FolderNames.Count();
    }

    class File1Controller : FolderTester {
        private readonly IFileProvider fp;
        protected override IEnumerable<string> FolderNames => fp.FolderNames(".");
        public File1Controller(IFileProvider fp) : base("IFileProvider Direct") {
            this.fp = fp;
        }
    }
    class File2Controller : FolderTester {
        private readonly IEnumerable<string> folderNames;
        protected override IEnumerable<string> FolderNames => folderNames;
        public File2Controller(IFileProvider fp) : base("IEnumerable assign") {
            folderNames = fp.FolderNames(".");
        }
    }
    class File3Controller : FolderTester {
        private readonly List<string> folderNames;
        protected override IEnumerable<string> FolderNames => folderNames;
        public File3Controller(IFileProvider fp) : base("IEnumerable assign List") {
            folderNames = fp.FolderNames(".").ToList();
        }
    }
    class File4Controller : FolderTester {
        private readonly Lazy<List<string>> folderNamesLazy;
        private List<string> folderNames => folderNamesLazy.Value;
        protected override IEnumerable<string> FolderNames => folderNames;
        public File4Controller(IFileProvider fp) : base("Lazy List") {
            folderNamesLazy = new Lazy<List<string>>(() => fp.FolderNames(".").ToList());
        }
    }
    class File5Controller : FolderTester {
        private readonly Lazy<IEnumerable<string>> folderNamesLazy;
        private IEnumerable<string> folderNames => folderNamesLazy.Value;
        protected override IEnumerable<string> FolderNames => folderNames;
        public File5Controller(IFileProvider fp) : base("Lazy IEnumerable") {
            folderNamesLazy = new Lazy<IEnumerable<string>>(() => fp.FolderNames("."));
        }
    }

    class Runner {
        private readonly IServiceProvider servicesProvider;
        public Runner(IServiceProvider servicesProvider) {
            this.servicesProvider = servicesProvider;
        }
        public void Run() {
            RunTest<File1Controller>();
            RunTest<File2Controller>();
            RunTest<File3Controller>();
            RunTest<File4Controller>();
            RunTest<File5Controller>();
            void RunTest<T>() where T : FolderTester {
                var ft = servicesProvider.GetRequiredService<T>();
                Debug.WriteLine(ft.Name + " Run");
                for(int i=0; i<2; i++) {
                    var result = ft.Test();
                    Debug.WriteLine("Result {0}: {1}", i + 1, result);
                }
                Debug.WriteLine("---------");
            }

        }
    }

    class Program {
        static void Main(string[] args) { Run(); }
        public static void Run() => Run(InitServiceProvider());
        static void Run(IServiceProvider servicesProvider) {
            servicesProvider.GetRequiredService<Runner>().Run();
        }

        private static IServiceProvider InitServiceProvider() {
            var services = new ServiceCollection();
            services.AddSingleton<IFileProvider>(new PhysicalFileProvider(@"C:\"));
            services.AddTransient<File1Controller>();
            services.AddTransient<File2Controller>();
            services.AddTransient<File3Controller>();
            services.AddTransient<File4Controller>();
            services.AddTransient<File5Controller>();
            services.AddTransient<Runner>();
            return services.BuildServiceProvider();
        }
    }
}



Result:
IFileProvider Direct Loaded
IFileProvider Direct Run
FolderNames hit
Result 1: 15
FolderNames hit
Result 2: 15
---------
IEnumerable assign Loaded
IEnumerable assign Run
FolderNames hit
Result 1: 15
FolderNames hit
Result 2: 15
---------
IEnumerable assign List Loaded
FolderNames hit
IEnumerable assign List Run
Result 1: 15
Result 2: 15
---------
Lazy List Loaded
Lazy List Run
FolderNames hit
Result 1: 15
Result 2: 15
---------
Lazy IEnumerable Loaded
Lazy IEnumerable Run
FolderNames hit
Result 1: 15
FolderNames hit
Result 2: 15
---------



The choice is yours.

Now, for the ViewContext.RouteData.Values: do the work in the controller. Writing C# in Razor is amusing, but if enough of it builds up, consider moving the code into the C# controller class where it's more easily managed. And, importantly, more consistently intellisenced.

This post has been edited by baavgai: 08 November 2018 - 05:38 AM

Was This Post Helpful? 1
  • +
  • -

#21 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6719
  • View blog
  • Posts: 22,939
  • Joined: 05-May 12

Re: get folder list in ASP.NET Core constructor

Posted 08 November 2018 - 08:54 AM

View Postbaavgai, on 08 November 2018 - 08:37 AM, said:

View PostSkydiver, on 07 November 2018 - 04:52 PM, said:

Take advantage of the Lazy<T>.


Only, you took an IEnumerable and transformed it into a list: pick one. :P/>

:) True, with the ToList(), I could have dropped the ToList(). On the other hand, without the Lazy<T>, calling ToList() would end up enumerating right there and then within the constructor. Since I was recommending that the work to get the folder list be actually delayed when it was actually needed, doing the just the ToList() with Lazy<T> would have been counter productive.

View Postbaavgai, on 08 November 2018 - 08:37 AM, said:

Now, for the ViewContext.RouteData.Values: do the work in the controller.

+100. It's the job of the controller to coordinate the work of the model, and feed that into the view. Let the controller figure out what stuff is needed by the view. Push rather than pull model.
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2