Navigation

Saturday, 16 November 2024

Understanding Deep Copy in C# with Classes Point and Line


In object-oriented programming, a common task involves creating a copy of an object. However, it's essential to distinguish between a shallow copy and a deep copy. In this post, we'll explore deep copying through a practical example, diving into the code to see how deep copying works with a custom Point and Line class in C#.

Shallow vs. Deep Copy

  1. Shallow Copy: A shallow copy of an object is a new object instance but contains references to the same objects within it. Changes made to the referenced objects in the copy reflect in the original object.

  2. Deep Copy: A deep copy creates a new object instance and also duplicates the objects referenced by it. As a result, modifying the deep-copied object does not affect the original.

Implementing Deep Copy with Point and Line

In our code, we have two classes, Point and Line, which demonstrate deep copying. Let’s break down the code.


public class Point
{
    public int X, Y;

    public Point DeepCopy()
    {
        return new Point { X = this.X, Y = this.Y };
    }

    public override string ToString()
    {
        return $"({X}, {Y})";
    }
}


The Point class has two integer properties, X and Y. It also has a DeepCopy method, which returns a new Point object with the same values for X and Y.

Line Class

The Line class contains two Point properties, Start and End, representing the start and end points of the line. In the Line class, we define a DeepCopy method to create a new Line with separate Start and End Point objects.


public class Line
{
    public Point Start, End;

    public Line DeepCopy()
    {
        return new Line
        {
            Start = this.Start.DeepCopy(),
            End = this.End.DeepCopy()
        };
    }

    public override string ToString()
    {
        return $"Start: {Start}, End: {End}";
    }
}


The DeepCopy method in the Line class uses the DeepCopy method in the Point class. This way, Start and End get new Point instances, ensuring that the copied line is independent of the original.

Testing Deep Copy in Main

The Program class demonstrates how DeepCopy works in practice. Here, line1 is our original line with specific start and end points.

var line1 = new Line
{
    Start = new Point { X = 1, Y = 2 },
    End = new Point { X = 3, Y = 4 }
};

When we create a deep copy of line1 with line1.DeepCopy(), we get a new Line object, line2. Changing the coordinates in line2 does not affect line1, showing that both lines are independent objects.



    var line2 = line1.DeepCopy();
    line2.Start.X = 5;
    line2.Start.Y = 6;


Complete Code:


    using System;

    namespace Coding.Exercise
    {
        public class Point
        {
            public int X, Y;

            public Point DeepCopy()
            {
                return new Point { X = this.X, Y = this.Y };
            }

            public override string ToString()
            {
                return $"({X}, {Y})";
            }
        }

        public class Line
        {
            public Point Start, End;

            public Line DeepCopy()
            {
                return new Line
                {
                    Start = this.Start.DeepCopy(),
                    End = this.End.DeepCopy()
                };
            }

            public override string ToString()
            {
                return $"Start: {Start}, End: {End}";
            }
        }

        public class Program
        {
            public static void Main()
            {
                var line1 = new Line
                {
                    Start = new Point { X = 1, Y = 2 },
                    End = new Point { X = 3, Y = 4 }
                };

                var line2 = line1.DeepCopy();
                line2.Start.X = 5;
                line2.Start.Y = 6;

                Console.WriteLine("Original Line: " + line1);
                Console.WriteLine("Copied Line: " + line2);
            }
        }
    }



Output:


Original Line: Start: (1, 2), End: (3, 4)
Copied Line: Start: (5, 6), End: (3, 4)

The original line (line1) remains unchanged, while the copied line (line2) has the modified Start coordinates, confirming that a true deep copy was made.

Conclusion

The DeepCopy method is essential when working with objects that reference other objects, helping to create fully independent copies. This example highlights how to implement deep copying for a class that contains references to other objects, ensuring data integrity and independence.

I hope this blog helps you understand how to use DeepCopy effectively in C#. If you have any questions or feedback, feel free to leave a comment below!

Monday, 11 November 2024

Creating a Dynamic Code Builder in C#: A Fluent API Approach

In software development, creating repetitive classes or structures can be tedious. Imagine if we could dynamically generate boilerplate code through an elegant and straightforward approach. In this blog, we will explore a simple implementation in C# using a class called CodeBuilder to generate class definitions on the fly. This approach uses the Builder Pattern to provide a fluent and intuitive API.


Why Use a Code Builder?

When working on large projects, developers often find themselves needing to create multiple classes with similar structures. A CodeBuilder helps reduce redundancy, saves time, and keeps the codebase clean and maintainable. This builder not only allows for easy creation of class definitions but also enhances code readability.

Code Walkthrough

Let's break down the CodeBuilder implementation step by step.


// Main class with entry point
using ConsoleAppForPattern;
using System.Text;

class Program
{


    public class CodeBuilder
    {
        private readonly string _className;
        private readonly List<Tuple<string, string>> _fields = new List<Tuple<string, string>>();

        public CodeBuilder(string className)
        {
            _className = className;
        }

        public CodeBuilder AddField(string fieldName, string fieldType)
        {
            _fields.Add(new Tuple<string, string>(fieldType, fieldName));
            return this;
        }

        public override string ToString()
        {
            var sb = new StringBuilder();
            sb.AppendLine($"public class {_className}");
            sb.AppendLine("{");

            foreach (var field in _fields)
            {
                sb.AppendLine($"  public {field.Item1} {field.Item2};");
            }

            sb.AppendLine("}");
            return sb.ToString();
        }

    }

    static void Main(string[] args)
    {
        var cb = new CodeBuilder("Person").AddField("Name", "string")
                                          .AddField("Age", "int");
        Console.WriteLine(cb);      
    }

}



Understanding the CodeBuilder Class

  1. Class Fields

    • _className stores the name of the class being built.

    • _fields is a list that holds tuples representing field types and names.

  2. Constructor

    • The constructor accepts the class name as a parameter, initializing _className.

  3. AddField Method

    • AddField(string fieldName, string fieldType) adds a new field to the class by adding a tuple to the _fields list.

    • The method returns this to enable fluent chaining of multiple calls.

  4. ToString Method

    • This method constructs the final class definition using StringBuilder. It iterates through the fields and generates their respective declarations.

Usage Example

In the Main method, we create an instance of CodeBuilder to generate a class named Person with fields Name (of type string) and Age (of type int).

 
static void Main(string[] args)
    {
        var cb = new CodeBuilder("Person").AddField("Name", "string").AddField("Age", "int");
        Console.WriteLine(cb);      
    }


The output will be:

public class Person
{
  public string Name;
  public int Age;
}


Benefits of Using CodeBuilder

  • Fluent Interface: The AddField method returns the instance of CodeBuilder, allowing us to chain calls and build the class definition in a natural, readable way.

  • Reduced Repetition: This approach eliminates repetitive boilerplate code and keeps the focus on defining what's unique about each class.

  • Easy Maintenance: If fields need to be added or changed, it is straightforward to update the CodeBuilder call without modifying the entire class structure manually.


Practical Applications

The CodeBuilder class can be particularly useful in scenarios where class definitions are dynamic or driven by external configurations (e.g., JSON schemas or database structures). It is a handy tool for prototyping or creating Domain-Specific Languages (DSLs) for code generation.

Conclusion

The CodeBuilder class is a simple yet powerful demonstration of the Builder Pattern, providing an easy way to dynamically generate class definitions in C#. By leveraging fluent interfaces, it makes the process intuitive and highly maintainable. Whether you're dealing with dynamic structures or simply want to reduce boilerplate, this approach can significantly enhance your productivity as a developer.

Feel free to expand upon this implementation by adding methods to generate properties instead of fields, or by introducing additional modifiers like private or readonly to make it more versatile.


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);
        //     }
        // }
    }
}