# Hello Perigee!

## Resources

{% embed url="<https://www.youtube.com/watch?v=vCAROWxkKgM>" %}
Want to watch the intro to Perigee instead?
{% endembed %}

{% file src="/files/rKVj7W9clmAfXW1nHEim" %}
Completed Project Files
{% endfile %}

## Our first application

Go ahead and create a new .NET 5/6+ console application. Open up `Program.cs`, and head to the first step to get started!

{% hint style="warning" %}
If you haven't gone through the installation step, please do so first!
{% endhint %}

{% content-ref url="/pages/hdedFoHMHIxcQq94FsmK" %}
[Installation and Project Setup](/getting-started/installation-and-project-setup.md)
{% endcontent-ref %}

### Step 1) The application starting point

Let's start with the basics. First let's create a new application in `Program.cs`. Depending on the version of .NET you started with, you'll see two different things when you open `Program.cs`

### Net 6++

The <mark style="color:orange;">**.NET 6**</mark> ++ version looks like this:&#x20;

```csharp
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");

//YOUR CODE HERE
```

If this is the case, delete <mark style="color:blue;">**Line 2**</mark> - `Console.WriteLine("Hello, World!");` and start there.

### Net  5 and lower

The <mark style="color:orange;">**.NET 5**</mark> and below versions looks like this:

```csharp
class Program
{

    static void Main(string[] args)
    {
        //YOUR CODE HERE
    }
}
```

If this is the case, start coding on <mark style="color:blue;">**Line 6**</mark>.&#x20;

### The application code

Now that we know where to start, here's a simple <mark style="color:blue;">**Perigee**</mark> application.

{% code lineNumbers="true" %}

```csharp
//A fully managed perigee application! 
PerigeeApplication.ApplicationNoInit("FirstApp", 
(taskConfig) => { 

});
```

{% endcode %}

Let's look what what we have here in the constructor:

* <mark style="color:blue;">**Line 2**</mark> - `"FirstApp"` -  The name of the application, this can be whatever you like!
* <mark style="color:blue;">**Line 3**</mark> - `taskConfig block` - This block is where we add any and all thread managed tasks.&#x20;

{% hint style="info" %}
Make sure you have everything included in your `using` statements by clicking the :bulb: icon or press `ctrl+.` to find missing namespaces

```csharp
using Microsoft.Extensions.Logging;
using Perigee;
```

{% endhint %}

### Step 2) Adding thread managed code

This wouldn't be a hello tutorial without writing "Hello, World!", so let's add a [CRON](/perigee-and-beyond/all-about-cron.md#what-about-a-cron) method to [log](/getting-started/hello-logs.md#logging-introduction) <mark style="color:red;">`Hello Perigee`</mark> every 15 seconds!

The `.AddCron` method adds a new thread to the system. Each thread is managed by Perigee and is independent of every other thread. This is an important aspect of [Perigee Application Design](/getting-started/perigee-application-design.md#anatomy-of-a-perigee-application) as it allows for individual thread management. Threads do not affect each other, and Perigee's internal thread management system has mechanisms in place to automatically restart downed threads.

```csharp
//A fully managed perigee application! 
using Microsoft.Extensions.Logging;
using Perigee;

PerigeeApplication.ApplicationNoInit("FirstApp", (taskConfig) => {

    taskConfig.AddCRON("HelloWorld", "*/15 * * * * *", (ct, log) => {
        log.LogInformation("Hello Perigee from {appName}", taskConfig.AppName);
    });

});
```

* <mark style="color:blue;">**Line 4**</mark> - We use fluent syntax to `.AddCRON()` - This method takes a `name`, `CRON string`, and a `callback(cancelToken, ILogger)`.&#x20;
* <mark style="color:blue;">**Line 5**</mark> - We use the built in logger passed to us to log information in a templated format, passing in the name of the application to the logger.

Running the application produces a log new line every 15 seconds!

<figure><img src="/files/6QpIAw4E143Sa3Ft1jBQ" alt=""><figcaption></figcaption></figure>

To close this application using graceful shutdown, press <mark style="color:orange;">**CTRL-C**</mark>, it will start the safe shutdown procedure allowing the application to properly stop all running tasks before just exiting out.

<figure><img src="/files/YDxxU4AmeINX3iQVoRGr" alt=""><figcaption></figcaption></figure>

## Hello Perigee - Extended

My oh my, we logged something! :thumbsup:Exciting right? Let's take our first demo application a step further and watch for [CSV](/core-modules/file-formats/csv.md#read) files, read them in, and report the row and data counts.

Simply replace `.AddCron()` with the [directory watcher](/core-modules/event-sources/watchers/directory-watch.md#demo-application) instead, full code below:

```csharp
PerigeeApplication.ApplicationNoInit("FirstApp", (taskConfig) => {

    taskConfig.AddDirectoryWatch("CSV", "C:\\Watch", "*.csv", SearchOption.TopDirectoryOnly, (ct, l, path) => {

        //Read the CSV
        var CSVData = CSVReader.ToDataTable(path, out var rRes);

        //Reprt on it
        l.LogInformation("Read CSV {file}[{encoding}]. Columns/Rows: {col}/{row}; Delimiter: {delChar}; Jagged? {jagged}",
            Path.GetFileName(path), rRes.FileEncoding.EncodingName, rRes.ColumnCount,
            CSVData.Rows.Count, rRes.FinalDelimiter, rRes.RowShifts.Count > 0 ? "YES" : "NO");

        //Remove it - OR let the failed folder policy kick in
        //File.Delete(path);

    }, policy: ThreadRegistry.DirectoryWatchFailurePolicy.MoveToFailedFolder);

});
```

Here's a `sample.csv`:

```csv
Name, Age, Email, Phone
John Doe, 30, john.doe@example.com, 123-456-7890
Jane Smith, 25, jane.smith@example.com, 987-654-3210
Bob Johnson, 40, bob.johnson@example.com, 555-555-5555
Mary Lee, 28, mary.lee@example.com, 111-222-3333
Hash Brown, 35, hash.brown@example.com, 444-444-4444
```

{% hint style="success" %}
Make sure you have everything included in your **`using`** statements by clicking the :bulb: icon or press `ctrl+.` to find missing namespaces

```csharp
using Microsoft.Extensions.Logging;
using Perigee;
using Perigee.FileFormats.CSV;
using System.Data;
```

{% endhint %}

Voila! You're now watching for CSV files, reading them in, and reporting on the number of rows and columns.&#x20;

For an intro to Perigee we accomplished quite a lot.&#x20;

* We learned about [threads](/getting-started/perigee-application-design.md#managed-threads) - how they're added and independent of each other.
* We learned about [logging](/getting-started/hello-logs.md) information to the available sinks.
* [CRON](/perigee-and-beyond/all-about-cron.md#what-about-a-cron) strings and how to use a CRON thread.
* How to configure Perigee.
* What "Graceful Shutdown" looks like.
* We even got to see the [CSV](/core-modules/file-formats/csv.md#read) reader in action.

Let's hop over to the next section and continue!


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.perigee.software/getting-started/hello-perigee.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
