CSharp - Other

Real-Time Progress Tracking with AJAX

Back-End

using System.Threading;
using System.Web.Http;
using System.Web.Mvc; // For JsonResult


public class ProgressController : ApiController
{
    [HttpPost]
    [Route("api/progress/start-task")]
    public JsonResult StartTask()
    {
        int totalSteps = 100;


        for (int i = 1; i <= totalSteps; i++)
        {
            // Simulate some work (e.g., 100ms per step)
            Thread.Sleep(100);


            // Return progress to the client
            HttpContext.Current.Response.Headers["X-Progress"] = $"{i * 100 / totalSteps}%";
            var progress = new { Progress = i * 100 / totalSteps };
            HttpContext.Current.Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(progress));
            HttpContext.Current.Response.Flush();
        }


        return new JsonResult
        {
            Data = new { Message = "Task Completed", Progress = 100 },
            JsonRequestBehavior = JsonRequestBehavior.AllowGet
        };
    }
}


Front-End

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AJAX Progress Bar in .NET Framework</title>
    <style>
        #progress-bar {
            width: 100%;
            background-color: #f3f3f3;
        }
        #progress-bar-fill {
            width: 0%;
            height: 30px;
            background-color: #4caf50;
            text-align: center;
            line-height: 30px;
            color: white;
        }
    </style>
</head>
<body>
    <h1>AJAX with Progress Bar in .NET Framework</h1>
    <button id="start-btn">Start Task</button>
    <div id="progress-bar">
        <div id="progress-bar-fill">0%</div>
    </div>


    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
        $(document).ready(function () {
            $('#start-btn').click(function () {
                $('#progress-bar-fill').css('width', '0%').text('0%');


                $.ajax({
                    url: '/api/progress/start-task',
                    type: 'POST',
                    xhr: function () {
                        var xhr = new window.XMLHttpRequest();


                        // Event to capture progress
                        xhr.onprogress = function (e) {
                            var progressText = e.target.responseText.trim().split('\n').pop();
                            try {
                                var progressData = JSON.parse(progressText);
                                $('#progress-bar-fill').css('width', progressData.Progress + '%').text(progressData.Progress + '%');
                            } catch (error) {
                                console.log('Progress parsing error', error);
                            }
                        };


                        return xhr;
                    },
                    success: function (data) {
                        $('#progress-bar-fill').css('width', '100%').text('100%');
                        alert(data.Message); // Notify the user that the task is complete
                    },
                    error: function (jqXHR, textStatus, errorThrown) {
                        alert('Error: ' + textStatus);
                    }
                });
            });
        });
    </script>
</body>
</html>

Remote Attribute In MVC

Model

[Remote("Action", "Controller", "Area", ErrorMessage = "Message")]
public string ColumnName{ get; set; }


Controller

public JsonResult IsExist(Model ModelName)
{
  Context db = new Context();
  return Json(!db.TableName.Any(x => x.ColumnName == ModelName.ColumnName), JsonRequestBehavior.AllowGet);
}

Replace Nested Loops with SelectMany()

Instead of using nested foreach loops to flatten collections, SelectMany() provides a more readable and efficient way to achieve the same result. It flattens nested collections into a single sequence.


var categories = new List < List < string >> {
  new List < string > {
    "Apple",
    "Banana"
  },
  new List < string > {
    "Orange",
    "Grape"
  },
  new List < string > {
    "Mango"
  }
};

// Flatten nested lists using SelectMany()
var flattened = categories.SelectMany(category => category).ToList();

Console.WriteLine(string.Join(", ", flattened));
//Apple, Banana, Orange, Grape, Mango

Reverse a String

Array.Reverse()

public string ArrayReverseString(string stringToReverse)
{
    var charArray = stringToReverse.ToCharArray();
    Array.Reverse(charArray);

    return new string(charArray);
}


Enumerable Reverse() Extension

public string EnumerableReverseMethod(string stringToReverse)
{
    return string.Concat(Enumerable.Reverse(stringToReverse));
}


Recursion

public string RecursiveStringReverseMethod(string stringToReverse)
{
    if (stringToReverse.Length <= 1)
        return stringToReverse;

    return stringToReverse[^1] + 
           RecursiveStringReverseMethod(stringToReverse[1..^1]) + stringToReverse[0];
}


Loop and XOR Operator

public string ReverseXorMethod(string stringToReverse)
{
    var charArray = stringToReverse.ToCharArray();
    var len = stringToReverse.Length - 1;

    for (int i = 0; i < len; i++, len--)
    {
        charArray[i] ^= charArray[len];
        charArray[len] ^= charArray[i];
        charArray[i] ^= charArray[len];
    }

    return new string(charArray);
}


Stack

public string StackReverseMethod(string stringToReverse)
{
    var resultStack = new Stack<char>();
    foreach (char c in stringToReverse)
    {
        resultStack.Push(c);
    }

    var sb = new StringBuilder();
    while (resultStack.Count > 0)
    {
        sb.Append(resultStack.Pop());
    }

    return sb.ToString();
}


StringBuilder

public string StringBuilderReverseMethod(string stringToReverse)
{
    var sb = new StringBuilder(stringToReverse.Length);
    for (int i = stringToReverse.Length - 1; i >= 0; i--)
    {
        sb.Append(stringToReverse[i]);
    }

    return sb.ToString();
}


Create()

public string StringCreateMethod(string stringToReverse)
{
    return string.Create(stringToReverse.Length, stringToReverse, (chars, state) =>
    {
        state.AsSpan().CopyTo(chars);
        chars.Reverse();
    });
}


LINQ Reverse()

public string StringExtensionReverseMethod(string stringToReverse)
{
    return new string(stringToReverse.Reverse().ToArray());
}


Special Characters Reversion With TextElementEnumerator

public string TextElementEnumeratorMethod(string stringToReverse)
{
    return string.Create(stringToReverse.Length, stringToReverse, (chars, val) =>
    {
        var valSpan = val.AsSpan();
        var en = StringInfo.GetTextElementEnumerator(val);
        en.MoveNext();
        var start = en.ElementIndex;
        var pos = chars.Length;
        while (en.MoveNext())
        {
            var next = en.ElementIndex;
            var len = next - start;
            valSpan[start..next].CopyTo(chars[(pos - len)..pos]);
            pos -= len;
            start = next;
        }

        if (start != 0)
            valSpan[start..].CopyTo(chars[0..pos]);
    });
}

Role-based Authorization in ASP.NET Core

Configuring role-based authorization in program.cs or startup.cs

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>();


Register useAuthorization() between UseRouting and UseEndpoints otherwise, we might run into the following issue.

Configure your application startup by adding app.UseAuthorization() in the application startup code. If there are calls to app.UseRouting() and app.UseEndpoints(…), the call to app.UseAuthorization() must go between them


How we set the role-based authorization

controller class

[Authorize(Roles = "Admin")]
public class HomeController : Controller
{
  [Route("index")]
  public IActionResult Index()
  {
      return View();
  }
}


action methods

[Authorize(Roles = "SuperUser")]
[Route("time")]
public IActionResult Time() => Content(new TimeOnly().ToLongTimeString());


How to apply multiple roles

[Authorize(Roles = "SuperUser, Admin")]
public IActionResult Time() => Content(new TimeOnly().ToLongTimeString());

or

[Authorize(Roles = "SuperUser")]
[Authorize(Roles = "Admin")]
public IActionResult Time() => Content(new TimeOnly().ToLongTimeString());


Using policy-based roles

Program.cs or Startup.cs

builder.Services.AddAuthorization(options => { 
  options.AddPolicy("SuperUserRights", policy => policy.RequireRole("Admin", "SuperUser", "BackupAdmin")); 
});


Controller class or Action methods

[Authorize(Policy = "SuperUserRights")]
public IActionResult Time() => Content(new TimeOnly().ToLongTimeString());

SAP Crystal Reports - CrystalImageHandler.aspx not found

App_Start > RouteConfig.cs

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");
    routes.IgnoreRoute("Report/{resource}.aspx/{*pathInfo}");
}


Setting up Viewers Virtual Directory

  1. Check the virtual directory is set up correctly on the development as well as production web servers.
  2. If the directory are not found, then create the folder manually.
  3. Go to C:\Program files (X86) > Sap Business Objects > Crystal Reports for Net Framework 4.0 > Common > Crystal reports 2011 > crystalreportviewers.
  4. Copy all the items inside crystalreportviewers folder and paste it to the crystalreportviewers13 folder.


Development Server Virtual Directory - \Windows\Microsoft.NET\Framework\v4.0.30319\ASP.NETClientFiles\crystalreportviewers13
Production Virtual Directory (IIS) - \inetpub\wwwroot\aspnet_client\system_web\4_0_30319\crystalreportviewers13 | SITE_ROOT\aspnet_client\system_web\4_0_30319\crystalreportviewers13


Web.config

<system.web>
    <httpHandlers>
      	<add verb="GET" path="CrystalImageHandler.aspx" type="CrystalDecisions.Web.CrystalImageHandler, CrystalDecisions.Web, Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" />
        <add verb="GET" path="Report/CrystalImageHandler.aspx" type="CrystalDecisions.Web.CrystalImageHandler, CrystalDecisions.Web, Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" />
    </httpHandlers>
</system.web>

<system.webServer>
    <handlers>
        <add name="CrystalImageHandler.aspx_GET" verb="GET" path="CrystalImageHandler.aspx" type="CrystalDecisions.Web.CrystalImageHandler, CrystalDecisions.Web, Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" preCondition="integratedMode" />
        <add name="CrystalImageHandler.aspx_GETR" verb="GET" path="Report/CrystalImageHandler.aspx" type="CrystalDecisions.Web.CrystalImageHandler, CrystalDecisions.Web, Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" preCondition="integratedMode" />
    </handlers>
</system.webServer>


Search clause between strings in LINQ or lambda expression

x.Name.CompareTo(Start) >= 0 && x.Name.CompareTo(End) <= 0

SearchValues to search for data in a list

string[] productTitles = ProductList.Products.Select(x => x.Title).ToArray();

SearchValues<string> svProducts = SearchValues.Create(productTitles, StringComparison.OrdinalIgnoreCase);

IEnumerable<Product> found = ProductList.Products
    .Where(x => svProducts.Contains(x.Title));

Send Automated WhatsApp Messages (Wassenger API)

Send image message

// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with the POST method
var request = new RestRequest(Method.POST);

// Add headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body for sending a text message
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    message = "Hello world, this is a sample message" // Message content
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response content (optional for debugging)
Console.WriteLine(response.Content);


Send video messages

// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with the POST method
var request = new RestRequest(Method.POST);

// Add headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body for sending a video message
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    message = "This is a caption for a video message", // Add a caption for the video
    media = new
    {
        url = "https://download.samplelib.com/mp4/sample-5s.mp4", // URL of the video file
        expiration = "7d" // Set expiration time (e.g., 7 days)
    }
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response content (optional for debugging)
Console.WriteLine(response.Content);


Send document messages

// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with the POST method
var request = new RestRequest(Method.POST);

// Add headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body for sending a PDF with expiration
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    media = new
    {
        url = "https://www.africau.edu/images/default/sample.pdf", // URL of the PDF file
        expiration = "30d" // Set expiration time (e.g., 30 days)
    }
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response content (optional for debugging)
Console.WriteLine(response.Content);


Send audio voice record

// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with the POST method
var request = new RestRequest(Method.POST);

// Add headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body for sending an audio message (PTT)
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    media = new
    {
        url = "https://download.samplelib.com/mp3/sample-9s.mp3", // URL of the audio file
        format = "ptt" // Format type for audio message (PTT - Push to Talk)
    }
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response content (optional for debugging)
Console.WriteLine(response.Content);


Send a media message with an uploaded file

  • {{UPLOADED FILE ID}} : Replace this expression with the specific value
  • You can upload the file here
  • The file ID will look something like this: 57443b8773c036f2bae0cd96
// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with the POST method
var request = new RestRequest(Method.POST);

// Add headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body for sending an image message
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    message = "This is a caption for an image message", // Caption for the image
    media = new
    {
        file = "{{UPLOADED FILE ID}}" // Replace with the actual uploaded file ID
    }
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response content (optional for debugging)
Console.WriteLine(response.Content);


Send a GIF message

// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with the POST method
var request = new RestRequest(Method.POST);

// Add headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body for sending a GIF message
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    message = "This is a sample caption for a GIF message", // Caption for the GIF
    media = new
    {
        url = "https://i.giphy.com/vKHKDIdvxvN7vTAEOM.mp4", // URL of the GIF in MP4 format
        format = "gif" // Specify the media format
    }
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response content (optional for debugging)
Console.WriteLine(response.Content);


Send a poll message

// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with the POST method
var request = new RestRequest(Method.POST);

// Add necessary headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body for the poll
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    poll = new
    {
        name = "Vote for your favorite color", // Title of the poll
        options = new[] 
        { 
            "Red", "Green", "Blue", "Yellow", "Grey", "Black", "Orange", "Purple", "White" // Poll options
        }
    }
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response content (optional for debugging)
Console.WriteLine(response.Content);


Send a scheduled date and time message

// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with method type POST
var request = new RestRequest(Method.POST);

// Add headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    message = "This is a scheduled message to be sent to a phone number in 10 minutes",
    deliverAt = "2024-12-02T13:52:32.396Z" // Replace with your desired delivery time (ISO 8601 format)
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response (optional)
Console.WriteLine(response.Content);


Send dynamic native button messages

WhatsApp no longer accepts native button messages. Buttons messages will be automatically converted into raw text equivalent messages.

// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with the POST method
var request = new RestRequest(Method.POST);

// Add headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body for sending a message with dynamic reply buttons
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    message = "This is a message with dynamic reply buttons", // Message content
    header = "Optional message header", // Optional header
    footer = "Optional message footer", // Optional footer
    buttons = new[]
    {
        new { id = "id1", text = "Say hello" },
        new { id = "id2", text = "Say goodbye" },
        new { id = "id3", text = "Get help" }
    }
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response content (optional for debugging)
Console.WriteLine(response.Content);


Send a list of items to select from

WhatsApp no longer accepts list messages. List messages will be automatically converted into raw text equivalent messages.

// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with the POST method
var request = new RestRequest(Method.POST);

// Add headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body for sending a list message
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    list = new
    {
        button = "Select one option", // Button text
        description = "Select which type of vehicle you are interested in", // Description of the list
        title = "Motor Business", // Title of the list
        footer = "Since 1990", // Footer text
        sections = new[]
        {
            new
            {
                title = "Select a car type",
                rows = new[]
                {
                    new { title = "Coupe", id = "a1", description = "This a description for coupe cars" },
                    new { title = "Sports", id = "a2", description = "This a description for sports cars" },
                    new { title = "SUV", id = "a3", description = "This a description for SUV cars" },
                    new { title = "Minivan", id = "a4", description = "This a description for minivan cars" },
                    new { title = "Crossover", id = "a5", description = "This a description for crossover cars" },
                    new { title = "Wagon", id = "a6", description = "This a description for wagon cars" }
                }
            },
            new
            {
                title = "Select a motorbike type",
                rows = new[]
                {
                    new { title = "Touring", id = "b1", description = "Designed to excel at covering long distances" },
                    new { title = "Cruiser", id = "b2", description = "Harley-Davidsons largely define the cruiser category" },
                    new { title = "Standard", id = "b3", description = "Motorcycle intended for use on streets and commuting" }
                }
            }
        }
    }
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response content (optional for debugging)
Console.WriteLine(response.Content);


Send a message with text formatting

// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with the POST method
var request = new RestRequest(Method.POST);

// Add headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body for sending a formatted text message
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    message = "This message is formatted using _italic format_, *bold format*, ~strikethrough format~ and ```monospace format```"
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response content (optional for debugging)
Console.WriteLine(response.Content);


Send a message with location coordinates

// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with the POST method
var request = new RestRequest(Method.POST);

// Add headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body for sending a location message with coordinates
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    location = new
    {
        coordinates = new[] { 40.7583748, -73.9891184 } // Latitude and longitude
    },
    message = "This is a location message using coordinates" // Optional message
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response content (optional for debugging)
Console.WriteLine(response.Content);


Send location message with address

// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with the POST method
var request = new RestRequest(Method.POST);

// Add headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body for sending a location message with an address
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    location = new
    {
        address = "Santa Claus Main Post Office, Tähtikuja 1, 96930 Arctic Circle, Finland" // Address
    },
    message = "This is a location message using an address" // Optional message
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response content (optional for debugging)
Console.WriteLine(response.Content);


Send a message with variables

// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with the POST method
var request = new RestRequest(Method.POST);

// Add headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body for sending a personalized message template
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    message = @"Dear {{ contact.name | customer }},
Thanks for contacting us!
We will answer your query shortly.

Your message was received on {{ date.humanize.full }}" // Template with placeholders
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response content (optional for debugging)
Console.WriteLine(response.Content);


Send a message with a URL

// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with the POST method
var request = new RestRequest(Method.POST);

// Add headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body for sending a message with a link
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    message = "Check out this cool link: https://www.youtube.com" // Message with link
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response content (optional for debugging)
Console.WriteLine(response.Content);


Send contact card messages

// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with the POST method
var request = new RestRequest(Method.POST);

// Add headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body for sending contact information
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    contacts = new[]
    {
        new { phone = "+1234567890", name = "John Doe" } // Contact details
    }
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response content (optional for debugging)
Console.WriteLine(response.Content);


Reply to a message

  • {{MESSAGE ID}} : Replace with the actual WhatsApp message ID to forward (18, 20, 22 or 32 hexadecimal value)
// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

// Create a RestClient instance with the API endpoint
var client = new RestClient("https://api.wassenger.com/v1/messages");

// Set up the request with the POST method
var request = new RestRequest(Method.POST);

// Add headers for content type and authentication
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

// Define the request body for sending a reply message
var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    quote = "{{MESSAGE ID}}", // Replace with the actual message ID
    message = "This message is a reply to another message within the same chat" // Reply message content
};

// Add the request body as JSON
request.AddJsonBody(requestBody);

// Execute the request and store the response
IRestResponse response = client.Execute(request);

// Output the response content (optional for debugging)
Console.WriteLine(response.Content);


Forward a message

  • {{MESSAGE ID}} : Replace with the actual WhatsApp message ID to reply to (18, 20, 22 or 32 hexadecimal value)
// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

var client = new RestClient("https://api.wassenger.com/v1/messages");
var request = new RestRequest(Method.POST);

request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    forward = new
    {
        message = "{{MESSAGE ID}}", // Replace with the message ID to forward
        chat = "+1234567890" // Replace with the chat ID to forward to
    },
    message = "The given message by ID will be forwarded to another chat"
};

request.AddJsonBody(requestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);


Send a catalogue message

  • {{PRODUCT CATALOG ID TO SEND}} : Replace this expression with the specific value
using RestSharp;

var client = new RestClient("https://api.wassenger.com/v1/messages");
var request = new RestRequest(Method.POST);

request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    product = "{{PRODUCT CATALOG ID TO SEND}}" // Replace with the product catalog ID
};

request.AddJsonBody(requestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);


Send a message in real-time with no enqueueing

using RestSharp;

var client = new RestClient("https://api.wassenger.com/v1/messages");
var request = new RestRequest(Method.POST);

request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE");

var requestBody = new
{
    live = true,
    phone = "+1234567890",
    message = "This message will be delivered in real-time if the session is online, otherwise the API will return an error"
};

request.AddJsonBody(requestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);


Send a message with maximum retries

using RestSharp;


var client = new RestClient("https://api.wassenger.com/v1/messages");
var request = new RestRequest(Method.POST);


request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE");


var requestBody = new
{
    retries = 2,
    phone = "+1234567890",
    message = "This message will be retried only twice. If the delivery fails twice, it will be flagged as deleted and removed from the queue"
};


request.AddJsonBody(requestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);


Send a message with the expiration time

using RestSharp;

var client = new RestClient("https://api.wassenger.com/v1/messages");
var request = new RestRequest(Method.POST);

request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE");

var requestBody = new
{
    expiration = new { seconds = 90 },
    phone = "+1234567890",
    message = "This message will be deleted if it cannot be delivered within 90 seconds after being queued. This is useful for time-sensitive messages."
};

request.AddJsonBody(requestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);


Send a message within a time and day range

using RestSharp;

var client = new RestClient("https://api.wassenger.com/v1/messages");
var request = new RestRequest(Method.POST);

request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE");

var requestBody = new
{
    phone = "+1234567890",
    message = "Restricted message example that will only be delivered between 9 am to 5 pm from Monday to Friday.",
    restrict = new
    {
        start = 9,
        end = 17,
        timezone = "CEST",
        weekdays = new[] { 1, 2, 3, 4, 5 }
    }
};

request.AddJsonBody(requestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);


Send a message reaction

  • {{WHATSAPP MESSAGE ID}} : Replace this expression with the specific value
using RestSharp;

var client = new RestClient("https://api.wassenger.com/v1/messages");
var request = new RestRequest(Method.POST);

request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE");

var requestBody = new
{
    phone = "+1234567890",
    reaction = "👍",
    reactionMessage = "{{WHATSAPP MESSAGE ID}}" // Replace with the message ID
};

request.AddJsonBody(requestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);


Remove message reaction:

  • {{WHATSAPP MESSAGE ID}} : Replace this expression with the particular value
using RestSharp;

var client = new RestClient("https://api.wassenger.com/v1/messages");
var request = new RestRequest(Method.POST);

request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE");

var requestBody = new
{
    phone = "+1234567890",
    reaction = "-", // Use "-" to remove a reaction
    reactionMessage = "{{MESSAGE WHATSAPP ID}}" // Replace with the message ID
};

request.AddJsonBody(requestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);


Send a message on behalf of an agent and assign a chat

  • {{USER ID}} : Replace with the actual user ID (24 hexadecimal value)
  • {{ASSIGNED USER ID}} : Replace with the actual user ID to assign the chat (24 hexadecimal value)
// Required: RestSharp package
// Documentation: https://restsharp.dev
// Installation: https://www.nuget.org/packages/RestSharp

using RestSharp;

var client = new RestClient("https://api.wassenger.com/v1/messages");
var request = new RestRequest(Method.POST);

request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    agent = "{{USER ID}}", // Replace with the agent's user ID
    message = "This message is sent via API on behalf of an agent."
};

request.AddJsonBody(requestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);


Send a message and resolve the chat

using RestSharp;

var client = new RestClient("https://api.wassenger.com/v1/messages");
var request = new RestRequest(Method.POST);

request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    message = "Once this message is delivered, the chat will be reported as resolved in the web chat interface.",
    actions = new[]
    {
        new { action = "chat:resolve" }
    }
};

request.AddJsonBody(requestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);


Send a message and add a chat label

using RestSharp;

var client = new RestClient("https://api.wassenger.com/v1/messages");
var request = new RestRequest(Method.POST);

request.AddHeader("Content-Type", "application/json");
request.AddHeader("Token", "ENTER API KEY HERE"); // Replace with your API key

var requestBody = new
{
    phone = "+1234567890", // Replace with the recipient's phone number
    message = "Once this message is delivered, the given labels will be added to the chat automatically.",
    actions = new[]
    {
        new
        {
            action = "labels:add",
            params = new
            {
                labels = new[] { "new", "sales" } // Labels to be added
            }
        }
    }
};

request.AddJsonBody(requestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);

Serialize Exceptions as JSON

Serialize Exceptions Using Newtonsoft.Json

public class CustomException : Exception
{
    public string Mitigation { get; }

    public CustomException(string message, string mitigation) 
        : this(message, mitigation, null)
    { }

    public CustomException(string message, string mitigation, Exception? innerException) 
        : base(message, innerException)
    {
        Mitigation = mitigation;
    }
}


[Serializable]
public class CustomVerboseException : CustomException
{
    public CustomVerboseException(string message, string mitigation) 
        : base(message, mitigation) { }
}


try
{
    throw new CustomException("Custom error", "Try later");
}
catch (CustomException ex)
{
    var json = JsonConvert.SerializeObject(ex)!;

    Assert.Contains("Mitigation", json);
}


Serialize Exceptions By Custom JsonConverter

public class SimpleExceptionConverter : JsonConverter<Exception>
{
    public override Exception? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, Exception value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();

        writer.WriteString("Error", value.Message);
        writer.WriteString("Type", value.GetType().Name);

        if (value.InnerException is { } innerException)
        {
            writer.WritePropertyName("InnerException");
            Write(writer, innerException, options);
        }

        writer.WriteEndObject();
    }
}


public class DetailExceptionConverter : JsonConverter<Exception>
{
    public override void Write(Utf8JsonWriter writer, Exception value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();

        var exceptionType = value.GetType();

        writer.WriteString("ClassName", exceptionType.FullName);

        var properties = exceptionType.GetProperties()
            .Where(e => e.PropertyType != typeof(Type))
            .Where(e => e.PropertyType.Namespace != typeof(MemberInfo).Namespace)
            .ToList();

        foreach (var property in properties)
        {
            var propertyValue = property.GetValue(value, null);

            if (options.DefaultIgnoreCondition == JsonIgnoreCondition.WhenWritingNull && propertyValue == null)
                continue;

            writer.WritePropertyName(property.Name);

            JsonSerializer.Serialize(writer, propertyValue, property.PropertyType, options);
        }

        writer.WriteEndObject();
    }
}


try
{
    var innerException = new InvalidOperationException("Bad operation");

    throw new CustomException("Custom error", "Try later", innerException);
}
catch (Exception ex)
{
    JsonSerializerOptions options = new(JsonSerializerOptions.Default);
    options.Converters.Add(new SimpleExceptionConverter());

    var json = JsonSerializer.Serialize(ex, options);

    Assert.NotEmpty(json);
}


Serialize Exceptions By Object Transformation

public class ExceptionObject
{
    public string Message { get; set; }

    public string? StackTrace { get; set; }

    public ExceptionObject? InnerException { get; set; }

    public ExceptionObject(Exception exception)
    {
        Message = exception.Message;
        StackTrace = exception.StackTrace;

        if (exception.InnerException is { } innerException)
            InnerException = new ExceptionObject(innerException);
    }
}


try
{
    var innerException = new InvalidOperationException("Bad operation");

    throw new CustomException("Custom error", "Try later", innerException);
}
catch (Exception ex)
{
    var interimObject = new ExceptionObject(ex);

    var json = JsonSerializer.Serialize(interimObject);

    Assert.NotEmpty(json);
}

Short / long / int literal format

var d = 1.0d; // double
var d0 = 1.0;  // double
var d1 = 1e+3; // double
var d2 = 1e-3; // double
var f = 1.0f; // float
var m = 1.0m; // decimal
var i = 1;   // int
var ui = 1U;  // uint
var ul = 1UL;  // ulong
var l = 1L;  // long

Simplify Your Queries With "AutoInclude" In .Net Core

What is AutoInclude()?

In EF Core, navigation properties define relationships between entities. When loading entities, related data often needs to be included. Traditionally, this is done using Include() statements, which can become repetitive and clutter your code.


With AutoInclude(), you can configure navigation properties directly in your model, so they're always included by default:

protected override void OnModelCreating(ModelBuilder modelBuilder)  
{  
    modelBuilder.Entity<Order>()  
        .Navigation(o => o.Customer)  
        .AutoInclude();  
}


Now, whenever an Order entity is loaded, its Customer navigation property is automatically included.


Overriding AutoInclude() with IgnoreAutoIncludes()

There may be scenarios where you need to exclude navigation properties configured with AutoInclude() for specific queries. EF Core provides the IgnoreAutoIncludes() method for such cases:

var orders = context.Orders  
    .IgnoreAutoIncludes()  
    .ToList();


This query excludes all auto-included navigation properties, giving you precise control over what data is fetched.