Navigation

Saturday 2 November 2024

Liskov Substitution Principle (LSP) in C#

 

Introduction

The Liskov Substitution Principle (LSP) is one of the five SOLID principles of object-oriented design, which aims to create flexible, extensible, and maintainable software. LSP is named after Barbara Liskov, a computer scientist who introduced this principle in the 1980s. This blog will walk you through the LSP concept in C# with code examples using a console application.


What is the Liskov Substitution Principle?

The Liskov Substitution Principle states that: "Objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program."

In simpler terms, if you have a base class, you should be able to replace it with any of its derived classes without the code misbehaving. This keeps your software flexible and ensures that substituting derived classes doesn't introduce unexpected bugs or inconsistencies.

Why LSP Matters

Adhering to LSP provides multiple benefits:

  • Predictable Code Behavior: Your code behaves consistently regardless of which subclass is being used.
  • Scalability: It’s easier to extend functionality with new classes without breaking existing code.
  • Reduced Bugs: Violating LSP can lead to unexpected behavior or errors, so following it helps make code reliable and maintainable.

Friday 1 November 2024

The Single Responsibility Principle (SRP) of SOLID in C#

 

What is the Single Responsibility Principle (SRP)?

  • Definition of SRP: “A class should have only one reason to change.”
  • Purpose of SRP: Explain how SRP aims to limit each class to a single responsibility to avoid coupling multiple roles into a single class.
  • Benefits of SRP: Mention maintainability, flexibility, scalability, and testability.

Example Scenario for SRP in a Console Application

  • Context: Describe a scenario where SRP might be applied, such as a simple console application to manage employee data.

  • Initial Code Without SRP: Show an example of a single class handling multiple responsibilities, like creating an employee, logging data, and sending a notification.


namespace ConsoleAppForPattern
{
    internal class EmpManager
    {
        public void AddEmployee(string name)
        {
            Console.WriteLine($"Employee {name} added.");
            LogEmployeeAddition(name);
            SendWelcomeEmail(name);
        }

        private void LogEmployeeAddition(string name)
        {
            Console.WriteLine($"Log: Employee {name} was added to the system.");
        }

        private void SendWelcomeEmail(string name)
        {
            Console.WriteLine($"Email: Welcome {name} to the company!");
        }
    }
}

  • Issues with this Code: Explain how the EmployeeManager class violates SRP by handling employee creation, logging, and email notifications in one place. Each of these tasks could change for different reasons, so they should be separated.

Tuesday 29 October 2024

Understanding the Open-Closed Principle in C# with a Example

 In this post, we’ll explore one of the SOLID principles of object-oriented programming: the Open-Closed Principle (OCP). In C#, applying OCP can help make your code more flexible, maintainable, and easier to extend. We'll illustrate OCP with a reporting system example, where we’ll create reports in different formats, like PDF, Excel, CSV and etc.

What is the Open-Closed Principle?

The Open-Closed Principle (OCP) states that:

Software entities (like classes, modules, and functions) should be open for extension but closed for modification.


This means that you should be able to add new functionality to your classes without changing their existing code. In C#, we can achieve this by using inheritance and polymorphism, allowing new functionality to be added without altering tested, stable code.

Example Scenario: A Reporting System

Let's say we’re building a reporting system that generates different types of reports. In our example, we’ll have a Report base class and several subclasses for each report type. This setup will allow us to follow the Open-Closed Principle.

Here’s how our code could look:

namespace ConsoleAppForPattern
{
    public class OPenClose
    {
        public abstract class Report
        {
            public abstract void GenerateReport();
        }

        public class PDFReport : Report
        {
            public override void GenerateReport()
            {
                // Logic to generate PDF report
                Console.WriteLine("Generating PDF report...");
            }
        }

        public class ExcelReport : Report
        {
            public override void GenerateReport()
            {
                // Logic to generate Excel report
                Console.WriteLine("Generating Excel report...");
            }
        }
        public class CSVReport : Report
        {
            public override void GenerateReport()
            {
                // Logic to generate CSV report
                Console.WriteLine("Generating CSV report...");
            }
        }
    }
}


// Main class with entry point
using static ConsoleAppForPattern.OPenClose;

class Program
{
    static void Main(string[] args)
    {
        // Create an instance of ReportGenerator
        ReportGenerator generator = new ReportGenerator();

        Console.WriteLine("Choose a report type to generate:");
        Console.WriteLine("1. PDF Report");
        Console.WriteLine("2. Excel Report");
        Console.WriteLine("3. CSV Report");

        // Read the user's choice
        string choice = Console.ReadLine();
        Report selectedReport = null;

        // Determine the type of report based on user input
        switch (choice)
        {
            case "1":
                selectedReport = new PDFReport();
                break;
            case "2":
                selectedReport = new ExcelReport();
                break;
            case "3":
                selectedReport = new CSVReport();
                break;
            default:
                Console.WriteLine("Invalid choice. Please select 1, 2, or 3.");
                return;
        }

        // Generate the selected report
        generator.Generate(selectedReport);

        Console.WriteLine("Report generated successfully!");
    }
    public class ReportGenerator
    {
        public void Generate(Report report)
        {
            report.GenerateReport();
        }
    }
}



Code Explanation

  1. Abstract Report Class: The Report class is defined as an abstract base class. It has an abstract GenerateReport method that will be overridden by its subclasses. Since it’s abstract, it can’t be instantiated directly, and each report type will provide its specific implementation.

  2. Concrete Report Classes: We create subclasses (PDFReport, ExcelReport, and CSVReport) that each provide their own implementation of GenerateReport. This follows the Open-Closed Principle by allowing us to add new report types (such as JSON, XML) by creating new subclasses without changing the Report or ReportGenerator classes.

  3. ReportGenerator Class: The ReportGenerator class takes a Report object and calls its GenerateReport method. This class doesn’t need to know which specific type of report it’s dealing with, thanks to polymorphism.

  4. Main Program: The Main function presents a menu to the user to select a report type, creates the corresponding report, and then generates it. This setup allows easy extension. To add a new report type, we can create a new class (e.g., JSONReport) without modifying any existing classes.

Benefits of the Open-Closed Principle in Our Example

  • Flexibility and Extensibility: We can easily add new types of reports without changing existing code.
  • Maintainability: Since existing code doesn’t change, there’s less risk of introducing bugs in stable code, making it easier to maintain.
  • Readability: Each report type is self-contained in its class, making the code clearer and more modular.

Extending the Code with a New Report Type

Let’s say we want to add a JSONReport. All we need to do is create a new class that inherits from

Report:

public class JSONReport : Report
        {
            public override void GenerateReport()
            {
                Console.WriteLine("Generating JSON report...");
            }
        }


In the Main method, we could add another case for JSON if we wanted, but the core classes don’t need any modification, thanks to the Open-Closed Principle!

Conclusion

By following the Open-Closed Principle, we designed a reporting system in C# that can be extended with new report types without altering the existing codebase. This approach reduces the risk of bugs, improves readability, and makes the system easier to maintain and expand. Try applying this principle in your projects to create more robust and adaptable code! 

Sunday 13 August 2023

Flutter : Simple Example of State Management with flutter_riverpod

In the world of Flutter app development, efficient state management is a key factor in building responsive and user-friendly applications. With various state management solutions available, developers often find themselves navigating through a maze of options. One solution that has gained significant attention and praise is flutter_riverpod

Project Structure 



Step 1: Install Package

             $ flutter pub add flutter_riverpod 

        Click here to get the latest version


Step 2: Add the following code to your main.dart file.   

The ProviderScope widget, provided by the Riverpod state management framework in Flutter, serves as a container for organizing and managing the state of your application. By wrapping your app's main widget with ProviderScope, you create a controlled environment where you can define and use various state providers seamlessly. This allows you to efficiently manage data across different parts of your app while promoting modularity and reusability.

 void main() {
runApp(const ProviderScope(child: MainApp()));
}

       Below, you'll find the entire code for this page. You can simply copy and paste it as-is:

import 'package:flutter/material.dart';
import 'package:flutter_application_riverpod/home_page.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
  runApp(
    const ProviderScope(child: MainApp()),
  );
}

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    /// Providers are declared globally and specify how to create a state
    final counterProvider = StateProvider((ref) => 0);
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: const Text("RiverPod"),
        ),
        body: const Center(
          child: HomePage(),
        ),
      ),
    );
  }
}


Step 3: home_page.dart 

Please copy and paste the entire code for the "home_page.dart" to ensure you have the complete implementation of the home page.

The provided code exemplifies the use of `flutter_riverpod` for efficient state management in a Flutter app. It showcases a `HomePage` widget, equipped to consume state via Riverpod. Within the widget's state, the `ref.watch(counterProvider)` retrieves and displays the current count value managed by the `counterProvider` state provider. The widget also features an "Increment" button that, when pressed, triggers the `counterProvider`'s `increment` method to increase the count by 2. This concise yet powerful setup illustrates how Riverpod simplifies state management, enabling widgets to access and update app state with ease.



import 'package:flutter/material.dart';
import 'package:flutter_application_riverpod/providers/count_provider.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class HomePage extends ConsumerStatefulWidget {
  const HomePage({super.key});

  @override
  ConsumerState<HomePage> createState() => _HomePageState();
}

class _HomePageState extends ConsumerState<HomePage> {
  @override
  Widget build(BuildContext context) {
    final count = ref.watch(counterProvider);
    return Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text(count.toString()),
        ElevatedButton(
          onPressed: () {
            ref.read(counterProvider.notifier).increment(2);
          },
          child: const Text(" Count "),
        )
      ],
    );
  }
}


Step 4: Please copy and paste the code from the 'count_provider.dart' file that contains the provider implementation.

The provided code snippet highlights the core elements of `flutter_riverpod` state management. It introduces a `Counter` class that extends `StateNotifier<int>` to manage an integer state, initially set to 0. The class contains an `increment` method that adds a specified value to the state. The `counterProvider` is defined as a `StateNotifierProvider`, creating an instance of `Counter` to manage the state.


import 'package:flutter_riverpod/flutter_riverpod.dart';

class Counter extends StateNotifier<int> {
  Counter() : super(0);
  void increment(int val) => state += val;
}

final counterProvider = StateNotifierProvider((ref) {
  return Counter();
});



To sum it up, `flutter_riverpod` is like a powerful helper for managing how your Flutter app stores and uses information. It makes things easier by organizing data in a neat and organized way. Using `flutter_riverpod`, you can control different parts of your app better, keep your code cleaner, and even share data between different parts of your app more smoothly. Just like a helpful guide on a journey, `flutter_riverpod` takes the stress out of managing your app's data, making your app-building adventure smoother.

Result :


    



Saturday 21 January 2023

Dropbox API: How to download/upload file with Dropbox API

 Step 1: Start by Creating an app as shown in the below image.

Step 2: Give a name to an app like 'TestApp1205' and choose the scope of access as shown in the below image.

Step 3: After selecting an access scop, you have to generate an access token, through which you can get access to the app file and folder. 



Step 4: When the app has been created it looks like this.




Step 5: When file is uploaded with the help of code it looks like the below image.



Step 6: Following are the C# codes to download/upload files.


using Dropbox.Api;
using Dropbox.Api.Files;
using ExcelDataReader;
using System;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DropBoxApp
{
    class Program
    {
        public static StreamWriter log;
        //public static string localFilePath = "";

        static void Main(string[] args)
        {
            //localFilePath = Path.GetFullPath("../../../Test");
            Program program = new Program();
            var task = Task.Run((Func<Task>)program.Run);
            task.Wait();          
            Console.WriteLine("Hello World!");
        }
        public async Task Run()
        {

            using (var dbx = new DropboxClient("6exx-HrLsAxxxxTxmSHqbft_YR2Z6xxxxy5GKyHkR4KOM4_w2pGz"))
            {
                log = File.AppendText("logger");
                var full = await dbx.Users.GetCurrentAccountAsync();
                Console.WriteLine("D  {0}", full.Name.DisplayName + "-" + full.Email);
                ListRootFolder(dbx).Wait();
               
            }
        }
      public  async Task ListRootFolder(DropboxClient dbx)
        {
            var list = await dbx.Files.ListFolderAsync(string.Empty);

            // show folders then files
            foreach (var item in list.Entries.Where(i => i.IsFolder))
            {
                Console.WriteLine("D  {0}/", item.Name);
            }
            foreach (var item in list.Entries.Where(i => i.IsFile))
            {
                Console.WriteLine("F{0,8} {1}", item.AsFile.Size, item.Name);
                Download(dbx,"", item.Name).Wait();
            }
        }

     public  async Task Download(DropboxClient dbx, string folder, string file)
        {
            Console.WriteLine("Download file...");

            using (var response = await dbx.Files.DownloadAsync(folder + "/" + file))
            {
                Stream StreamFromDropbox = await response.GetContentAsStreamAsync();
                System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
                MemoryStream StreamFromDropboxCopyAsync = new MemoryStream();
                await StreamFromDropbox.CopyToAsync(StreamFromDropboxCopyAsync);
                StreamFromDropboxCopyAsync.Seek(offset: 0, loc: SeekOrigin.Begin);
                IExcelDataReader reader = ExcelDataReader.ExcelReaderFactory
.CreateOpenXmlReader(StreamFromDropboxCopyAsync,
new ExcelReaderConfiguration()
{ FallbackEncoding = System.Text.Encoding.GetEncoding(1252) });
               
                //Value store in dataset
                DataSet ds = reader.AsDataSet();

                Console.WriteLine("Downloaded {0} Rev {1}", response.Response.Name, response.Response.Rev);

                //Console.WriteLine("------------------------------");
                //Console.WriteLine(await response.GetContentAsStringAsync());
                //Console.WriteLine("------------------------------");
            }          
           
        }

       //public async Task Upload(DropboxClient dbx, string folder, string file, string content)
       // {
       //     using (var mem = new MemoryStream(Encoding.UTF8.GetBytes(content)))
       //     {
       //         var updated = await dbx.Files.UploadAsync(
       //             folder + "/" + file,
       //             WriteMode.Overwrite.Instance,
       //             body: mem);
       //         Console.WriteLine("Saved {0}/{1} rev {2}", folder, file, updated.Rev);
       //     }
       // }
    }
}


Some other methods to call Dropbox API 

using Dropbox.Api;
using Dropbox.Api.Common;
using Dropbox.Api.Files;
using System;
using System.Data;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace DropBoxApp
{
    class Program
    {
        public static StreamWriter log;
        //public static string localFilePath = "";

        static void Main(string[] args)
        {
            //localFilePath = Path.GetFullPath("../../../Test");
            Program program = new Program();
            var task = Task.Run((Func<Task>)program.Run);
            task.Wait();          
            Console.WriteLine("Hello World!");
        }
        private async Task<FolderMetadata> CreateFolder(DropboxClient client, string path)
        {
            Console.WriteLine("--- Creating Folder ---");
            var folderArg = new CreateFolderArg(path);
            try
            {
                var folder = await client.Files.CreateFolderV2Async(folderArg);

                Console.WriteLine("Folder: " + path + " created!");

                return folder.Metadata;
            }
            catch (ApiException<CreateFolderError> e)
            {
                if (e.Message.StartsWith("path/conflict/folder"))
                {
                    Console.WriteLine("Folder already exists... Skipping create");
                    return null;
                }
                else
                {
                    throw e;
                }
            }
        }

        public async Task Run()
        {

            using (var dbx = new DropboxClient("6exx-HrLsAxxxxTxmSHqbft_YR2Z6xxxxy5GKyHkR4KOM4_w2pGz"))
            {
                log = File.AppendText("logger");
                await  GetCurrentAccount(dbx);
                //var full = await dbx.Users.GetCurrentAccountAsync();
                //Console.WriteLine("D  {0}", full.Name.DisplayName + "-" + full.Email);
                //ListRootFolder(dbx).Wait();

                var path = "/EventId";
                var folder = await CreateFolder(dbx, path);
                var list = await ListFolder(dbx, path);

                var firstFile = list.Entries.FirstOrDefault(i => i.IsFile);
                if (firstFile != null)
                {
                    await Download(dbx, path, firstFile.AsFile);
                }
                //var pathInTeamSpace = "/Test";
                //await ListFolderInTeamSpace(dbx, pathInTeamSpace);                
                await Upload(dbx, path, firstFile.AsFile, "This is a text file");
                //await ChunkUpload(dbx, path, "Binary");

            }
        }
        private async Task GetCurrentAccount(DropboxClient client)
        {
            var full = await client.Users.GetCurrentAccountAsync();

            Console.WriteLine("Account id    : {0}", full.AccountId);
            Console.WriteLine("Country       : {0}", full.Country);
            Console.WriteLine("Email         : {0}", full.Email);
            Console.WriteLine("Is paired     : {0}", full.IsPaired ? "Yes" : "No");
            Console.WriteLine("Locale        : {0}", full.Locale);
            Console.WriteLine("Name");
            Console.WriteLine("  Display  : {0}", full.Name.DisplayName);
            Console.WriteLine("  Familiar : {0}", full.Name.FamiliarName);
            Console.WriteLine("  Given    : {0}", full.Name.GivenName);
            Console.WriteLine("  Surname  : {0}", full.Name.Surname);
            Console.WriteLine("Referral link : {0}", full.ReferralLink);

            if (full.Team != null)
            {
                Console.WriteLine("Team");
                Console.WriteLine("  Id   : {0}", full.Team.Id);
                Console.WriteLine("  Name : {0}", full.Team.Name);
            }
            else
            {
                Console.WriteLine("Team - None");
            }
        }
        //private async Task RunUserTests(DropboxClient client)
        //{
        //    await GetCurrentAccount(client);

        //    //var path = "/DotNetApi/Help";
        //    //var folder = await CreateFolder(client, path);
        //    //var list = await ListFolder(client, path);

        //    //var firstFile = list.Entries.FirstOrDefault(i => i.IsFile);
        //    //if (firstFile != null)
        //    //{
        //    //    await Download(client, path, firstFile.AsFile);
        //    //}

        //    //var pathInTeamSpace = "/Test";
        //    //await ListFolderInTeamSpace(client, pathInTeamSpace);

        //    //await Upload(client, path, "Test.txt", "This is a text file");

        //    //await ChunkUpload(client, path, "Binary");
        //}
        //public  async Task ListRootFolder(DropboxClient dbx)
        //{
        //    var list = await dbx.Files.ListFolderAsync(string.Empty);

        //    // show folders then files
        //    foreach (var item in list.Entries.Where(i => i.IsFolder))
        //    {
        //        Console.WriteLine("D  {0}/", item.Name);
        //    }
        //    foreach (var item in list.Entries.Where(i => i.IsFile))
        //    {
        //        Console.WriteLine("F{0,8} {1}", item.AsFile.Size, item.Name);
        //        //Download(dbx,"", item.Name).Wait();
        //    }
        //}
        private async Task<ListFolderResult> ListFolder(DropboxClient client, string path)
        {
            Console.WriteLine("--- Files ---");
            var list = await client.Files.ListFolderAsync(path);

            // show folders then files
            foreach (var item in list.Entries.Where(i => i.IsFolder))
            {
                Console.WriteLine("D  {0}/", item.Name);
            }

            foreach (var item in list.Entries.Where(i => i.IsFile))
            {
                var file = item.AsFile;

                Console.WriteLine("F{0,8} {1}",
                    file.Size,
                    item.Name);
            }

            if (list.HasMore)
            {
                Console.WriteLine("   ...");
            }
            return list;
        }
        private async Task Download(DropboxClient client, string folder, FileMetadata file)
        {
            Console.WriteLine("Download file...");

            using (var response = await client.Files.DownloadAsync(folder + "/" + file.Name))
            {
                Console.WriteLine("Downloaded {0} Rev {1}", response.Response.Name, response.Response.Rev);
                Console.WriteLine("------------------------------");
                Stream StreamFromDropbox = await response.GetContentAsStreamAsync();
                SaveFileStream(folder, StreamFromDropbox, response.Response.Name);
                Console.WriteLine("------------------------------");
            }
        }
        private void SaveFileStream(string path, Stream stream,string fileName)
        {
            string localFilePath = Path.GetFullPath("../../../"+path+"/"+fileName);
            var fileStream = new FileStream(localFilePath, FileMode.Create, FileAccess.Write);
            stream.CopyTo(fileStream);
            fileStream.Dispose();
        }
        private async Task Upload(DropboxClient client, string folder, FileMetadata file, string fileContent)
        {
            Console.WriteLine("Upload file...");
            string NewFileName = DateTime.Now.ToString("ddMMyyyymmss") + "_" + file.Name;
            string str = folder + "/" + NewFileName;
           
            string localFilePath = Path.GetFullPath("../../../EventId/" + file.Name);

            FileStream fs = new FileStream(localFilePath, FileMode.Open, FileAccess.Read);
            byte[] tmpBytes = new byte[fs.Length];
            fs.Read(tmpBytes, 0, Convert.ToInt32(fs.Length));
            //MemoryStream mystream = new MemoryStream(tmpBytes);

            using (var stream = new MemoryStream(tmpBytes))
            {
                var response = await client.Files.UploadAsync(folder + "/" + NewFileName, WriteMode.Overwrite.Instance, body: stream);

                Console.WriteLine("Uploaded Id {0} Rev {1}", response.Id, response.Rev);
            }
        }
        private async Task ChunkUpload(DropboxClient client, string folder, string fileName)
        {
            Console.WriteLine("Chunk upload file...");
            // Chunk size is 128KB.
            const int chunkSize = 128 * 1024;

            // Create a random file of 1MB in size.
            var fileContent = new byte[1024 * 1024];
            new Random().NextBytes(fileContent);

            using (var stream = new MemoryStream(fileContent))
            {
                int numChunks = (int)Math.Ceiling((double)stream.Length / chunkSize);

                byte[] buffer = new byte[chunkSize];
                string sessionId = null;

                for (var idx = 0; idx < numChunks; idx++)
                {
                    Console.WriteLine("Start uploading chunk {0}", idx);
                    var byteRead = stream.Read(buffer, 0, chunkSize);

                    using (MemoryStream memStream = new MemoryStream(buffer, 0, byteRead))
                    {
                        if (idx == 0)
                        {
                            var result = await client.Files.UploadSessionStartAsync(body: memStream);
                            sessionId = result.SessionId;
                        }

                        else
                        {
                            UploadSessionCursor cursor = new UploadSessionCursor(sessionId, (ulong)(chunkSize * idx));

                            if (idx == numChunks - 1)
                            {
                                await client.Files.UploadSessionFinishAsync(cursor, new CommitInfo(folder + "/" + fileName), memStream);
                            }

                            else
                            {
                                await client.Files.UploadSessionAppendV2Async(cursor, body: memStream);
                            }
                        }
                    }
                }
            }
        }
        private async Task ListFolderInTeamSpace(DropboxClient client, string path)
        {
            // Fetch root namespace info from user's account info.
            var account = await client.Users.GetCurrentAccountAsync();

            if (!account.RootInfo.IsTeam)
            {
                Console.WriteLine("This user doesn't belong to a team with shared space.");
            }
            else
            {
                try
                {
                    // Point path root to namespace id of team space.
                    client = client.WithPathRoot(new PathRoot.Root(account.RootInfo.RootNamespaceId));
                    await ListFolder(client, path);
                }
                catch (PathRootException ex)
                {
                    Console.WriteLine(
                        "The user's root namespace ID has changed to {0}",
                        ex.ErrorResponse.AsInvalidRoot.Value);
                }
            }
        }

        //public async Task Download(DropboxClient dbx, string folder, string file)
        //{
        //    Console.WriteLine("Download file...");

        //    using (var response = await dbx.Files.DownloadAsync(folder + "/" + file))
        //    {
        //        Stream StreamFromDropbox = await response.GetContentAsStreamAsync();
        //        System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
        //        MemoryStream StreamFromDropboxCopyAsync = new MemoryStream();
        //        await StreamFromDropbox.CopyToAsync(StreamFromDropboxCopyAsync);
        //        StreamFromDropboxCopyAsync.Seek(offset: 0, loc: SeekOrigin.Begin);
        //        IExcelDataReader reader = ExcelDataReader.ExcelReaderFactory.CreateOpenXmlReader(StreamFromDropboxCopyAsync, new ExcelReaderConfiguration() { FallbackEncoding = System.Text.Encoding.GetEncoding(1252) });

        //        //Value store in dataset
        //        DataSet ds = reader.AsDataSet();

        //        Console.WriteLine("Downloaded {0} Rev {1}", response.Response.Name, response.Response.Rev);

        //        //Console.WriteLine("------------------------------");
        //        //Console.WriteLine(await response.GetContentAsStringAsync());
        //        //Console.WriteLine("------------------------------");
        //    }

        //    //using (var response = await dbx.Files.DownloadAsync(folder + "/" + file))
        //    //{
        //    //     string _file = await response.GetContentAsStringAsync();

        //    //    //Console.WriteLine(await response.GetContentAsStringAsync());
        //    //}
        //}

        //public async Task Upload(DropboxClient dbx, string folder, string file, string content)
        // {
        //     using (var mem = new MemoryStream(Encoding.UTF8.GetBytes(content)))
        //     {
        //         var updated = await dbx.Files.UploadAsync(
        //             folder + "/" + file,
        //             WriteMode.Overwrite.Instance,
        //             body: mem);
        //         Console.WriteLine("Saved {0}/{1} rev {2}", folder, file, updated.Rev);
        //     }
        // }
    }
}