Skip to main content

Command Palette

Search for a command to run...

Console application to manage Onelake storage in Microsoft Fabric

Updated
12 min readView as Markdown
Console application to manage Onelake storage in Microsoft Fabric
S
From Synapse Analytics, Power BI, Spark, Microsoft Fabric,ASP.NET Core and recently Agentic AI on .NET I try to explore, learn and share all aspects of Microsoft Data Stack in this blog.

My previous article demonstrated the use of Azure Storage API to manage Onelake in Fabric. This made me thinking if its possible to create a custom application that can leverage those API's outside the Fabric environment.

So I ended up created this small .NET console application in C#. Nothing fancy just simple console based interface that can perform basic storage level operations over the lakehouses.

Here is the walkthrough of the application functionality.

The code I developed to create the application is in a mess. I need to modularize it. Once done I will upload it to Github and also share it here.

Update 1/19/2024 : I completed cleaning up the code and modularize it.

The updated code is uploaded here on GitHub.

Updates : Created three additional classes

Program.cs being the entry point into the application.

Authentication.cs returns the bearer token

Actions.cs performing various storage level actions

HttpMethods.cs containing the various Http methods

HttpMethods class inherits Authentication class and the Program class inherits the Actions class.

@ minute 6:20 in the above video https://youtu.be/9lw3H1fe2FI&t=380 I mentioned that its not possible to provide a confirmation dialog in a console based app. I made some changes and instead added a prompt based confirmation.

Code

In the application ensure that you have the following Nuget packages installed.

dotnet add package Spectre.Console --version 0.49.1
dotnet add package Newtonsoft.Json --version 13.0.3
dotnet add package Microsoft.Extensions.Configuration.Json --version 9.0.1
dotnet add package Microsoft.Extensions.Configuration --version 9.0.1
dotnet add package Microsoft.Identity.Client --version 4.67.2
dotnet add package Spectre.Console --version 0.49.2-preview.0.69
dotnet add package Azure.Storage.Files.DataLake --version 12.21.0

Appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ClientId": "Service Principal Client Id",
  "DownloadLocation": "Download location to download files from the Fabirc tenant"
}

Authentication.cs

using Microsoft.Identity.Client;

namespace Security
{
    internal class Authentication
    {
        public static bool istokencached = false;
        public static string clientId = "";
        private static string[] scopes = new string[] { "https://storage.azure.com/.default" };
        private static string Authority = "https://login.microsoftonline.com/organizations";
        private static string RedirectURI = "http://localhost";
        public static readonly HttpClient client = new HttpClient();
        protected HttpClient Client => client;
        public async static Task<AuthenticationResult> ReturnAuthenticationResult()
        {
            string AccessToken;
            PublicClientApplicationBuilder PublicClientAppBuilder =
                PublicClientApplicationBuilder.Create(clientId)
                .WithAuthority(Authority)
                .WithCacheOptions(CacheOptions.EnableSharedCacheOptions)
                .WithRedirectUri(RedirectURI);

            IPublicClientApplication PublicClientApplication = PublicClientAppBuilder.Build();
            var accounts = await PublicClientApplication.GetAccountsAsync();
            AuthenticationResult result;
            try
            {

                result = await PublicClientApplication.AcquireTokenSilent(scopes, accounts.First())
                                 .ExecuteAsync()
                                 .ConfigureAwait(false);

            }
            catch
            {
                result = await PublicClientApplication.AcquireTokenInteractive(scopes)
                                 .ExecuteAsync()
                                 .ConfigureAwait(false);

            }
            istokencached = true;
            return result;

        }
    }
}

HttpsMethods.cs

using System.Net.Http.Headers;
using Microsoft.Identity.Client;

namespace Http
{
    internal class HttpMethods : Security.Authentication
    {
        public async static Task<string> GetAsync(string url)
        {

            AuthenticationResult result = await ReturnAuthenticationResult();
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
            HttpResponseMessage response = await client.GetAsync(url);
            try
            {
                response.EnsureSuccessStatusCode();
                return await response.Content.ReadAsStringAsync();
            }
            catch
            {
                Console.WriteLine(response.Content.ReadAsStringAsync().Result);
                return null;
            }

        }

        public async static Task<byte[]> SendAsync(HttpRequestMessage httprequestMessage)
        {
            AuthenticationResult result = await ReturnAuthenticationResult();
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
            HttpResponseMessage response = await client.SendAsync(httprequestMessage);
            response.EnsureSuccessStatusCode();
            try
            {
                return await response.Content.ReadAsByteArrayAsync();
            }
            catch
            {
                Console.WriteLine(response.Content.ReadAsByteArrayAsync().Result);
                return null;
            }
        }

        public async static Task<string> DeleteAsync(string url)
        {
            AuthenticationResult result = await ReturnAuthenticationResult();
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
            HttpResponseMessage response = await client.DeleteAsync(url);
            try
            {
                response.EnsureSuccessStatusCode();
                return await response.Content.ReadAsStringAsync();
            }
            catch
            {
                Console.WriteLine(response.Content.ReadAsStringAsync().Result);
                return null;
            }

        }

        public async static Task<string> PutAsync(string url, HttpContent content)
        {
            AuthenticationResult result = await ReturnAuthenticationResult();
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
            HttpResponseMessage response = await client.PutAsync(url, content);
            try
            {
                response.EnsureSuccessStatusCode();
                return await response.Content.ReadAsStringAsync();
            }
            catch
            {
                Console.WriteLine(response.Content.ReadAsStringAsync().Result);
                return null;
            }

        }

        public async static Task<string> PostAsync(string url, HttpContent content)
        {

            AuthenticationResult result = await ReturnAuthenticationResult();
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
            HttpResponseMessage response = await client.PostAsync(url, content);
            try
            {
                response.EnsureSuccessStatusCode();
                return await response.Content.ReadAsStringAsync();
            }
            catch
            {
                Console.WriteLine(response.Content.ReadAsStringAsync().Result);
                return null;
            }

        }
    }
}

Actions.cs

using LakeHouseFileDirectoryOperations;
using Microsoft.Identity.Client;
using Newtonsoft.Json.Linq;
using Security;
using Spectre.Console;
using System.Net.Http.Headers;
using System.Text;

namespace Action
{
    public class Actions
    {
        public static async Task _DeleteDirectory(string directoryfullpath)
        {

            Program.dfsendpoint = $"https://onelake.dfs.fabric.microsoft.com/{Program.workSpace}/{Program.lakeHouse}.Lakehouse/{directoryfullpath}?restype=directory&recursive=true";
            try
            {
                await Http.HttpMethods.DeleteAsync(Program.dfsendpoint);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Directory deletion failed : " + ex.Message);
            }
        }

        public static async Task UploadFilesToLakeHouse(string uploadpath, string lakehousedirectory)
        {

            DirectoryInfo d = new DirectoryInfo(uploadpath);
            byte[] bytes;

            foreach (FileInfo file in d.GetFiles())
            {
                using (Stream stream = File.OpenRead(file.FullName))
                {
                    string RequestUri = $"https://onelake.dfs.fabric.microsoft.com/{Program.workSpace}/{Program.lakeHouse}.Lakehouse/{lakehousedirectory}/{file.Name}?resource=file";
                    string jsonString = System.String.Empty;
                    var content = new StringContent(jsonString, Encoding.UTF8, "application/json");
                    var response = await Http.HttpMethods.PutAsync(RequestUri, content);
                    await FileStreamSendAsync(stream, lakehousedirectory, file.Name);
                }

            }

        }

        public static async Task DownloadFilesFromLakeHouse(string lakehouse_directoryfullpath, string local_directoryfullpath)
        {
            string dfsendpoint = "";

            dfsendpoint = $"https://onelake.dfs.fabric.microsoft.com/{Program.workSpace}/{Program.lakeHouse}.Lakehouse/{lakehouse_directoryfullpath}";

            var downloadMessage = new HttpRequestMessage
            {
                Method = HttpMethod.Get,
                RequestUri = new Uri(dfsendpoint)
            };

            try
            {
                var response_d = await Http.HttpMethods.SendAsync(downloadMessage);
                string filename_n = await GetDirectoryName(lakehouse_directoryfullpath);
                File.WriteAllBytes($"{local_directoryfullpath}\\{filename_n}", response_d);
            }
            catch (Exception ex)
            {
                Console.WriteLine("File download failed : " + ex.Message);

            }

        }

       public async static Task<string> FileStreamSendAsync(Stream stream, string directory, string filename)
        {
            AuthenticationResult result = await Authentication.ReturnAuthenticationResult();

            Security.Authentication.client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);

            var content = new StreamContent(stream);
            string url = $"https://onelake.dfs.fabric.microsoft.com/{Program.workSpace}/{Program.lakeHouse}.Lakehouse/{directory}/{filename}?action=append&position=0";
            var streamMessage = new HttpRequestMessage
            {
                Method = HttpMethod.Patch,
                RequestUri = new Uri(url),
                Content = content
            };
            HttpResponseMessage response = await Http.HttpMethods.client.SendAsync(streamMessage);

            try
            {
                response.EnsureSuccessStatusCode();
                await response.Content.ReadAsStringAsync();
            }
            catch
            {
                Console.WriteLine(response.Content.ReadAsStringAsync().Result);
                return null;
            }
            if (response.IsSuccessStatusCode)
            {
                url = $"https://onelake.dfs.fabric.microsoft.com/{Program.workSpace}/{Program.lakeHouse}.Lakehouse/{directory}/{filename}?action=flush&position={stream.Length}";
                Http.HttpMethods.client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
                var flushMessage = new HttpRequestMessage
                {
                    Method = HttpMethod.Patch,
                    RequestUri = new Uri(url)
                };
                response = await Http.HttpMethods.client.SendAsync(flushMessage);
                response.EnsureSuccessStatusCode();
            }
            return null;
        }

        public static async Task Create_Directory(string directoryfullpath)
        {
            string jsonString = System.String.Empty;
            Program.dfsendpoint = $"https://onelake.dfs.fabric.microsoft.com/{Program.workSpace}/{Program.lakeHouse}.Lakehouse/{directoryfullpath}?resource=directory";
            var content = new StringContent(jsonString, Encoding.UTF8, "application/json");
            try
            {
                await Http.HttpMethods.PutAsync(Program.dfsendpoint, content);
                AnsiConsole.MarkupLine("");
                AnsiConsole.MarkupLine($"[blue]Success[/] : Directory [Yellow]{await GetDirectoryName(directoryfullpath)}[/] successfully created in lakehouse : [Yellow]{Program.lakeHouse}[/]");
                Thread.Sleep(1000);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Directory creation failed : " + ex.Message);

            }
        }


        public static async Task Rename_Directory(string old_directoryfullpath, string new_directoryfullpath)
        {
            Program.dfsendpoint = $"https://onelake.dfs.fabric.microsoft.com/{Program.workSpace}/{Program.lakeHouse}.Lakehouse/{new_directoryfullpath}?restype=directory&comp=rename";
            var Metadata = new HttpRequestMessage
            {
                Method = HttpMethod.Put,
                RequestUri = new Uri(Program.dfsendpoint)
            };
            Metadata.Headers.Add("x-ms-rename-source", $"/{Program.workSpace}/{Program.lakeHouse}.Lakehouse/{old_directoryfullpath}");

            try
            {
                await Http.HttpMethods.SendAsync(Metadata);
                AnsiConsole.MarkupLine("");
                AnsiConsole.MarkupLine($"[blue]Success[/] : Directory [Yellow]{await GetDirectoryName(old_directoryfullpath)}[/] successfully renamed to [Yellow]{await GetDirectoryName(new_directoryfullpath)}[/] in lakehouse : [Yellow]{Program.lakeHouse}[/]");
                Thread.Sleep(1000);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Directory rename failed : " + ex.Message);

            }
        }

        public static async Task<string> GetDirectoryName(string value)
        {
            int lastSlashIndex_n = value.ToString().LastIndexOf('/');
            string dir_n = value.ToString().Substring(lastSlashIndex_n + 1);
            return dir_n;
        }


        public static async Task<JObject> TraverseAllLakeHousesInWorkspace(string workspace)
        {
            string dfsendpoint = $"https://onelake.dfs.fabric.microsoft.com/{workspace}" + $"?resource=filesystem&recursive=false";
            string response = await Http.HttpMethods.GetAsync(dfsendpoint);
            if (response == null)
            {
                return null;
            }
            else
            {
                JObject jsonObject_lakehouse = JObject.Parse(response);
                return jsonObject_lakehouse;
            }
        }

        public static async Task<SelectionPrompt<string>> TraverseAllDirectoriesInLakeHouse(string lakehouse)
        {
            int i = 1;
            string dfsendpoint = $"https://onelake.dfs.fabric.microsoft.com/{Program.workSpace}/{Program.lakeHouse}.Lakehouse/Files?resource=filesystem&recursive=true";
            string response = await Http.HttpMethods.GetAsync(dfsendpoint);
            JObject jsonObject_dir = JObject.Parse(response);
            JArray dirArray = (JArray)jsonObject_dir["paths"];
            var prompt = new SelectionPrompt<string>();
            prompt.AddChoice($"{i}.\tFiles");
            i = i + 1;
            foreach (JObject dir in dirArray)
            {
                if (dir["isDirectory"] != null)
                {
                    int lastSlashIndex_n = dir["name"].ToString().IndexOf('/');
                    string dir_n = dir["name"].ToString().Substring(lastSlashIndex_n + 1);
                    prompt.AddChoice($"{i}.\t{dir_n.ToString()}"); i++;
                }
            }

            return prompt;
        }

        public static async Task<MultiSelectionPrompt<string>> TraverseAllFilesInDirectories(string directorypath)
        {
            if (directorypath == "" && Program.Dir != "")
            {
                int tabIndex = Program.Dir.IndexOf('\t');
                directorypath = Program.Dir.Substring(tabIndex + 1);
            }
            string dfsendpoint = $"https://onelake.dfs.fabric.microsoft.com/{Program.workSpace}/{Program.lakeHouse}.Lakehouse/{directorypath}?resource=filesystem&recursive=false";
            string response = await Http.HttpMethods.GetAsync(dfsendpoint);
            JObject jsonObject_dir = JObject.Parse(response);
            JArray dirArray = (JArray)jsonObject_dir["paths"];
            var prompt = new MultiSelectionPrompt<string>();
            List<string> lst = new List<string>();

            foreach (JObject dir in dirArray)
            {
                if (dir["isDirectory"] == null)
                {
                    // prompt.AddChoices(await GetDirectoryName(dir["name"].ToString());
                    //   prompt.AddChoiceGroup("Files",await GetDirectoryName(dir["name"].ToString()));
                    lst.Add(await GetDirectoryName(dir["name"].ToString()));
                }
            }
            if (lst.Count > 0) { prompt.AddChoiceGroup("File List", lst); }
            prompt.AddChoice("[red]<< Back To Directory List >>[/]");
            return prompt;
        }

    }
}

Program.cs

using Microsoft.Extensions.Configuration;
using Newtonsoft.Json.Linq;
using Security;
using Spectre.Console;

namespace LakeHouseFileDirectoryOperations
{
    public class Program : Action.Actions
    {
        private static string DownloadLocation = "";
        public static string workSpace = "";
        public static string lakeHouse = "";
        public static string dfsendpoint = "";
        public static string operation = "";
        public static string Dir = "";
        public static string Filepath = "";
        public static string selectedOption = "";
        public static string currlakehouse = "";
        public static async Task Main(string[] args)
        {

            ReadConfig();
            await ConfirmWorkspace();
            while (Dir.Contains("Files") || Dir.Contains("Back To Lakehouse"))
            {
                AnsiConsole.Clear(); Header(); CurrentWorkspaceLakehouse();
                await MainMenu(selectedOption);
            }

        }

        public static void ReadConfig()
        {
            var builder = new ConfigurationBuilder()
            .AddJsonFile($"appsettings.json", true, true);
            var config = builder.Build();
            Security.Authentication.clientId = config["ClientId"];
            DownloadLocation = config["DownloadLocation"];
        }
        public static void Header()
        {
            Console.Title = "Microsoft Fabric Command Line";
            AnsiConsole.MarkupLine($".NET Version: [blue]{Environment.Version.ToString()}[/]");
            AnsiConsole.Write(
               new FigletText("Microsoft Fabric Command Line Tool")
            .Centered()
            .Color(Color.Red));
        }

        public async static Task ConfirmWorkspace()
        {
            Header();
            AnsiConsole.MarkupLine("");
            workSpace = AnsiConsole.Prompt(
            new TextPrompt<string>("Please Enter the Workspace : "));
            AnsiConsole.MarkupLine("");
            var confirmation_1 = AnsiConsole.Prompt(
            new TextPrompt<bool>($"Is the workspace [Yellow]{workSpace}[/] that you want to use ?")
           .AddChoice(true)
           .AddChoice(false)
           .DefaultValue(true)
           .WithConverter(choice => choice ? "yes" : "no"));
            string str = confirmation_1 ? "Confirmed" : "Declined";
            if (str == "Declined")
            { AnsiConsole.Clear(); await ConfirmWorkspace(); }
            else await MainMenu("");
        }

        public static void CurrentWorkspaceLakehouse()
        {

            AnsiConsole.MarkupLine($"Your current workspace is [Yellow]{workSpace}[/] and lakehouse is [Yellow]{lakeHouse}[/] ");
            AnsiConsole.MarkupLine("");
        }
        public async static Task DisplayLakehouses()
        {

            int i = 1;
            JObject jobject = await TraverseAllLakeHousesInWorkspace(workSpace);
            if (jobject == null)
            {
                AnsiConsole.MarkupLine($"Your current workspace [red]{workSpace}[/] is invalid ");
                Thread.Sleep(2500);
                AnsiConsole.Clear();
                await ConfirmWorkspace();

            };
            var lkhouse = new List<string>();
            AnsiConsole.Status()
                .Start($"Getting a list of lakehouses from the workspace [Yellow]{workSpace}[/]...", ctx =>
                {

                    ctx.Spinner(Spinner.Known.Star);
                    ctx.SpinnerStyle(Style.Parse("Yellow"));
                    JArray pathsArray = (JArray)jobject["paths"];

                    foreach (JObject path in pathsArray)
                    {
                        if (path["name"].ToString().Contains(".Lakehouse"))
                        {
                            lkhouse.Add(path["name"].ToString().Replace(".Lakehouse", ""));
                        }
                    }
                    Thread.Sleep(1500);
                    ctx.Status("Done ..");
                    Thread.Sleep(1000);

                });

            var prompt = new SelectionPrompt<string>();

            foreach (var obj in lkhouse)
            {
                prompt.AddChoice($"{i}.\t{obj.ToString()}"); i++;

            }
            prompt.AddChoice($"[red]{""} \t<< Main Menu >>[/]");
            AnsiConsole.Clear();
            Header();
            AnsiConsole.MarkupLine($"Your current workspace is [Yellow]{workSpace}[/]");
            AnsiConsole.MarkupLine("");
            prompt.Title("Which lakehouse would you like to interact with ?")
                    .PageSize(30)
                    .MoreChoicesText("[grey](Move up and down to reveal more)[/]");

            lakeHouse = AnsiConsole.Prompt(prompt);
            lakeHouse = lakeHouse.Replace(lakeHouse.Substring(0, lakeHouse.IndexOf("\t") + 1), "");

            if (lakeHouse.Contains("Main Menu"))
            { await MainMenu(""); }

        }
        public static async Task<SelectionPrompt<string>> MiscOperationsInPrompt(string operation)
        {
            var dirprompt = new SelectionPrompt<string>();
            if (Dir == "") { await DisplayLakehouses(); }
            AnsiConsole.Clear();
            Header();
            dirprompt = await TraverseAllDirectoriesInLakeHouse(lakeHouse);
            dirprompt.AddChoice("[red]<< Back To Lakehouse List >>[/]");
            dirprompt.Title("Which directory would you like to interact with ?")
                   .PageSize(30)
                   .MoreChoicesText("[grey](Move up and down to reveal more lakehouses)[/]");
            AnsiConsole.MarkupLine($"Your current workspace is [Yellow]{workSpace}[/] and lakehouse is [Yellow]{lakeHouse}[/] ");
            AnsiConsole.MarkupLine("");
            return dirprompt;
        }

        public static async Task<string> ListOperationsInPrompt(string operation)
        {
            var dirprompt_s = new SelectionPrompt<string>();
            var dirprompt_m = new MultiSelectionPrompt<string>();
            string title = "";
            if (!Dir.Contains("Files"))
            {

                if (operation == "1.\tLakeHouse directory structure")
                {

                    title = "Select the directory to view its structure";
                }

                if (operation == "2.\tCreate a lakehouse directory")
                {

                    title = "Which location would you like to create a directory ?";
                }

                if (operation == "3.\tRename a lakehouse directory")
                {

                    title = "Which directory would you like to rename ?";
                }

                if (operation == "4.\tDelete a lakehouse directory")
                {

                    title = "Which directory would you like to delete ?";
                }

                if (operation == "5.\tDownload files from a lakehouse directory")
                {

                    title = "Files from which directory would you like to download ?";

                }
                if (operation == "6.\tUpload files to a lakehouse directory")
                {

                    title = "Directory to which files to be uploaded";

                }
                if (Dir.Contains("Back To Lakehouse List"))
                { await DisplayLakehouses(); }
                dirprompt_s = await MiscOperationsInPrompt(operation);
                dirprompt_s.Title(title)
                       .PageSize(30)
                       .MoreChoicesText("[grey](Move up and down to reveal more directories)[/]");
                Dir = AnsiConsole.Prompt(dirprompt_s);

            }
            return Dir;
        }

        public static async Task<string> ReturnFileName()
        {
            int tabIndex = Dir.IndexOf('\t');
            return Dir.Substring(tabIndex + 1);
        }

        public static async Task MainMenu(string operation)
        {

            const string LakeHouseStructure = "1.\tLakeHouse directory structure";
            const string CreateDirectory = "2.\tCreate a lakehouse directory";
            const string RenameDirectory = "3.\tRename a lakehouse directory";
            const string DeleteDirectory = "4.\tDelete a lakehouse directory";
            const string DownloadFiles = "5.\tDownload files from a lakehouse directory";
            const string UploadFiles = "6.\tUpload files to a lakehouse directory";
            const string ChangeWorkspace = "7.\tChange Workspace";
            const string exit = "8.\tExit this Application";

            AnsiConsole.Clear();
            Header();
            AnsiConsole.MarkupLine($"Your current workspace is [Yellow]{workSpace}[/]");
            AnsiConsole.MarkupLine("");
            selectedOption = "";
            if (operation == "")
            {
                selectedOption = AnsiConsole.Prompt(
               new SelectionPrompt<string>()
                 .Title("Select an option to continue")
                 .PageSize(30)
                 .MoreChoicesText("[grey](Move up and down to reveal more options)[/]")
                 .AddChoices(new[] {
                           LakeHouseStructure,CreateDirectory,RenameDirectory,DeleteDirectory,DownloadFiles,UploadFiles,ChangeWorkspace,exit
                 }));
            }
            else
            {
                selectedOption = operation;
            }

            if (Authentication.istokencached == false)
            {
                AnsiConsole.Clear();
                Header();
                AnsiConsole.MarkupLine("[red]Note[/] : You will be prompted in a new browser window to enter the credentials of your fabric tenant!!!");
                Thread.Sleep(1500);

            }

            var fileprompt_m = new MultiSelectionPrompt<string>();
            var dirprompt_s = new SelectionPrompt<string>();
            switch (selectedOption)
            {

                case LakeHouseStructure:
                    operation = "1.\tLakehouse directory structure";
                    dirprompt_s = await MiscOperationsInPrompt(operation);
                    Dir = AnsiConsole.Prompt(dirprompt_s);
                    if (Dir == "Main Menu" || Dir.Contains("Back To Lakehouse")) { Dir = ""; await MainMenu(operation); }
                    else
                    {
                        Filepath = await ReturnFileName();
                        fileprompt_m = await TraverseAllFilesInDirectories(Filepath.ToString());
                        var filename_d = AnsiConsole.Prompt(fileprompt_m);
                    }
                    dirprompt_s = await MiscOperationsInPrompt(operation);
                    Dir = AnsiConsole.Prompt(dirprompt_s);
                    await ListOperationsInPrompt(operation);
                    break;

                case CreateDirectory:
                    operation = "2.\tCreate a lakehouse directory";
                    Dir = await ListOperationsInPrompt(operation);
                    if (Dir == "Main Menu" || Dir.Contains("Back To Lakehouse")) { Dir = ""; await MainMenu(operation); }
                    else

                    {
                        Filepath = await ReturnFileName();
                        var new_dir_n = AnsiConsole.Prompt(
                           new TextPrompt<string>(($"Enter the name for the new directory in [Yellow]{Filepath}[/] : ")));
                        await Create_Directory($"{Filepath}/{new_dir_n}");

                    };
                    dirprompt_s = await MiscOperationsInPrompt(operation);
                    Dir = AnsiConsole.Prompt(dirprompt_s);
                    await ListOperationsInPrompt(operation);

                    break;

                case RenameDirectory:
                    operation = "3.\tRename a lakehouse directory";
                    Dir = await ListOperationsInPrompt(operation);
                    if (Dir == "Main Menu") { await MainMenu("RenameDirectory"); }
                    if (Dir.Contains("Back To Lakehouse")) { Dir = ""; await TraverseAllLakeHousesInWorkspace(workSpace); }

                    else
                    {
                        int lastSlashIndex = Dir.ToString().LastIndexOf('\t');
                        string dir_n = Dir.ToString().Substring(lastSlashIndex + 1);

                        if (Dir == "1.    Files")
                        {
                            AnsiConsole.MarkupLine($"Cannot rename directory [Yellow]{dir_n}[/]");
                            Thread.Sleep(2000);
                        }
                        else
                        {
                            var new_dir_n = AnsiConsole.Prompt(
                             new TextPrompt<string>(($"Enter the new name for the directory [Yellow]{dir_n}[/] : ")));

                            int index = Dir.IndexOf(dir_n);
                            lastSlashIndex = Dir.ToString().LastIndexOf('/');
                            if (index != -1)
                            {

                                Filepath = await ReturnFileName();
                                int tabIndex = (Dir.Substring(0, lastSlashIndex + 1) + new_dir_n).IndexOf('\t');
                                string newFile = (Dir.Substring(0, lastSlashIndex + 1) + new_dir_n).Substring(tabIndex + 1);
                                await Rename_Directory(Filepath, newFile);
                            }
                        }
                    };
                    dirprompt_s = await MiscOperationsInPrompt(operation);
                    Dir = AnsiConsole.Prompt(dirprompt_s);
                    await ListOperationsInPrompt(operation);
                    break;

                case DeleteDirectory:

                    operation = "4.\tDelete a lakehouse directory";

                    Dir = await ListOperationsInPrompt(operation);

                    if (Dir == "Main Menu")
                    { await MainMenu("DeleteDirectory"); }

                    if (Dir.Contains("Back To Lakehouse") || Dir == "")
                    {
                        Dir = ""; await MainMenu("");
                        break;
                    }

                    else
                    {
                        Filepath = await ReturnFileName();

                        var confirmation = AnsiConsole.Prompt(
                         new TextPrompt<bool>($"Are you sure you want to delete this directory ?")
                        .AddChoice(true)
                        .AddChoice(false)
                        .DefaultValue(true)
                        .WithConverter(choice => choice ? "yes" : "no"));

                        if (confirmation == true)
                        {
                            await _DeleteDirectory(Filepath);
                            AnsiConsole.MarkupLine("");
                            AnsiConsole.MarkupLine($"Successfully deleted directory [Yellow]{await GetDirectoryName(Dir)}[/]");
                            Thread.Sleep(2000);
                            dirprompt_s = await MiscOperationsInPrompt(operation);
                            Dir = AnsiConsole.Prompt(dirprompt_s);
                            await ListOperationsInPrompt(operation);
                            break;
                        }

                        else
                        {
                            Dir = ""; await MainMenu(operation);
                            break;
                        }

                    }

                case DownloadFiles:

                    operation = "5.\tDownload files from a lakehouse directory";
                    if (Dir == "")
                    {
                        Dir = await ListOperationsInPrompt(operation);
                    }
                    if (Dir.Contains("Back To Lakehouse"))
                    {
                        Dir = await ListOperationsInPrompt(operation);
                    }

                    var filename = new List<string>();
                    Filepath = await ReturnFileName();
                    fileprompt_m = await TraverseAllFilesInDirectories(Filepath.ToString());

                    filename = AnsiConsole.Prompt(fileprompt_m);
                    int i = 0; int j = 0;
                    foreach (string flname in filename)
                    {
                        if (flname.ToString().Contains("Back To Directory"))
                        {
                            if (i > 0)
                            {
                                AnsiConsole.MarkupLine("");
                                AnsiConsole.MarkupLine($"[Yellow]All files downloaded succesfully[/]");
                                Thread.Sleep(2000);
                                AnsiConsole.Clear();
                                Header();
                                CurrentWorkspaceLakehouse();
                                j = 1;
                            }
                        }
                        else
                        {
                            i++;
                            int tabIndex = Dir.IndexOf('\t');
                            Filepath = Dir.Substring(tabIndex + 1);
                            await DownloadFilesFromLakeHouse(Filepath + "//" + flname, DownloadLocation);

                        }

                    }
                    if (i > 0 && j == 0)
                    {
                        AnsiConsole.MarkupLine("");
                        AnsiConsole.MarkupLine($"All files downloaded succesfully from [Yellow]{Filepath}[/] to [Yellow]{DownloadLocation}[/]");
                        Thread.Sleep(2000);
                        AnsiConsole.Clear();
                        Header();
                        CurrentWorkspaceLakehouse();
                    }
                    dirprompt_s = await MiscOperationsInPrompt(operation);
                    Dir = AnsiConsole.Prompt(dirprompt_s);
                    await ListOperationsInPrompt(operation);
                    break;

                case ChangeWorkspace:

                    AnsiConsole.Clear();
                    await ConfirmWorkspace();
                    break;

                case UploadFiles:

                    operation = "6.\tUpload files to a lakehouse directory";

                    Dir = await ListOperationsInPrompt(operation);

                    if (Dir == "Main Menu" || Dir.Contains("Back To Lakehouse"))
                    {
                        Dir = ""; await MainMenu(operation);
                    }
                    else
                    {
                        Filepath = await ReturnFileName();
                        var local_dir_n = AnsiConsole.Prompt(
                           new TextPrompt<string>(($"Enter the local path : ")));
                        await UploadFilesToLakeHouse(local_dir_n, Filepath);
                    };
                    AnsiConsole.MarkupLine("");
                    AnsiConsole.MarkupLine($"All files uploaded succesfully to [Yellow]{Filepath}[/]");
                    Thread.Sleep(2000);
                    AnsiConsole.Clear();
                    Header();
                    CurrentWorkspaceLakehouse();
                    AnsiConsole.MarkupLine($"Uploaded files in [Yellow]{Filepath}[/]");
                    AnsiConsole.MarkupLine("");
                    Filepath = await ReturnFileName();
                    fileprompt_m = await TraverseAllFilesInDirectories(Filepath.ToString());
                    filename = AnsiConsole.Prompt(fileprompt_m);
                    dirprompt_s = await MiscOperationsInPrompt(operation);
                    Dir = AnsiConsole.Prompt(dirprompt_s);
                    await ListOperationsInPrompt(operation);
                    break;

                case exit:
                    await ExitApplication();
                    return;
            }

        }

        public static async Task ExitApplication()
        {
            AnsiConsole.MarkupLine("");
            var confirmation_3 = AnsiConsole.Prompt(
              new TextPrompt<bool>($"Are you sure you want to exit the application ?")
             .AddChoice(true)
             .AddChoice(false)
             .DefaultValue(true)
             .WithConverter(choice => choice ? "yes" : "no"));
            if (confirmation_3 == true)
            { Environment.Exit(0); }

        }
    }
}

Conclusion :

The main idea behind this console app was to explore the possibility of managing Fabric components outside the Fabric environment. In the upcoming articles I will be demonstrating a few other aspects of fabric artifacts that can be managed outside the Fabric environment.

Thanks for reading !!!

More from this blog

My Ramblings On Microsoft Data Stack

102 posts

From Synapse Analytics, Power BI, Spark, Microsoft Fabric,ASP.NET Core and recently Agentic AI on .NET I try to explore, learn and share all aspects of Microsoft Data Stack in this blog.