UssdBuilder 1.0.3

dotnet add package UssdBuilder --version 1.0.3
NuGet\Install-Package UssdBuilder -Version 1.0.3
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="UssdBuilder" Version="1.0.3" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add UssdBuilder --version 1.0.3
#r "nuget: UssdBuilder, 1.0.3"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install UssdBuilder as a Cake Addin
#addin nuget:?package=UssdBuilder&version=1.0.3

// Install UssdBuilder as a Cake Tool
#tool nuget:?package=UssdBuilder&version=1.0.3

UssdBuilder

A lightweight and lightning-fast ussd library for advocates of clean and scalable code.

INTRODUCTION

A ussd application is one of hardest api to build. Although the implementation starts fairly simple, it could quickly degenerate into a messy and complicated code of if-else webs.

This library intends to solve the issue above, enabling you build lightning-fast ussd apps quicker, while keeping it clean, readable, and scalable.

SETUP

  1. Install the Nuget library
  2. Go to your project's Startup.cs or Program.cs and add the code below
builder.Services.AddDistributedMemoryCache(); //any implementation of IDistributedCache works, visit https://learn.microsoft.com/en-us/aspnet/core/performance/caching/distributed?view=aspnetcore-6.0

builder.Services.AddUssdServer();

USAGE

  1. Resolve the injected IUssdServer instance
  2. Declare your ussd routes
this.server.AddRoute(new UssdRoute
{
    Code = "000",
    Prev = null, //no previous screen means this is a new ussd session
    Regx = (_, _) => true, //use this if you want your request to proceed regardless of user input
    Goto = "welcome"
});

//Go to "sayhello" if (ussdCode == "000" && prevScreen == "welcome" && userInput == 1)
this.server.AddRoute(new UssdRoute
{
    Code = "000",
    Prev = "welcome",
    Regx = (_, req) => req.Text == "1",
    Goto = "sayhello"
});

//Go to "goodbye" if (ussdCode == "000" && prevScreen == "welcome" && userInput == 2)
this.server.AddRoute(new UssdRoute
{
    Code = "000",
    Prev = "welcome",
    Regx = (_, req) => req.Text == "2",
    Goto = "goodbye"
});

// //Go to "goodbye" if (ussdCode == "000" && prevScreen == "welcome", regardless of user input)
// this.server.AddRoute(new UssdRoute
// {
//     Code = "000",
//     Prev = "welcome",
//     Regx = (_, _) => true, //use this if you want your request to proceed regardless of user input
//     Goto = "goodbye"
// });

//Go to "welcome" if (ussdCode == "000" && prevScreen == "welcome" && userInput != 1 && userInput != 2)
this.server.AddRoute(new UssdRoute
{
    Code = "000",
    Prev = "welcome",
    Regx = (_, req) => req.Text != "1" && req.Text != "2",  //Regx could also be used for input validation like input length check, etc.
    Goto = "welcome"
});
  1. Add your route handlers
this.server.AddHandlers("000", new()
{
     {"welcome", async (UssdScreen current, UssdRequest request) => {
         // do some async work
         return new UssdResponse
         {
            Status = true,
            Message = "CON Welcome.\nEnter \n1. To say hello \n2. To say goodbye \n3. To repeat"
         };
     }},

     {"sayhello", async (UssdScreen current, UssdRequest request) => {
         // do some async work
         return new UssdResponse
         {
            Status = true,
            Message = $"END Hello world. User input was {request.Text}"
         };
     }},
     
     {"goodbye", async (UssdScreen current, UssdRequest request) => {
         // do some async work
         return new UssdResponse
         {
            Status = true,
            Message = $"END Goodbye. User input was {request.Text}"
         };
     }},
});
  1. Handle incoming request in your controller action
[HttpPost("Handle")]
public async Task<IActionResult> Handle([FromBody] UssdRequest model)
{
    try
    {
        var result = await server.HandleAsync(model);
        return Ok(result);
    }
    catch (Exception ex)
    {
        await server.DeleteAsync(model.SessionId);
        return Ok($"END An error occurred: {ex.Message}");
    }
}

Important note

  1. Complex input (e.g *0*0*2#) is handled by default using string.Split(...) and iteration over splitted inputs. To disable this behaviour, use
builder.Services.AddUssdServer(opt =>
{
    opt.EnableInputSplit = false;
});

  1. The default sliding expiration of a ussd session 40 seconds. To override this session behaviour, use
builder.Services.AddUssdServer(opt =>
{
    opt.CacheEntryOptions = new DistributedCacheEntryOptions
    {
        //...add your cache session options here
    };
});

  1. A single ussd server or endpoint can serve multiple ussd codes, you just have to add routes and handlers for the different codes you want the server to process.

  2. For the sake of clean code, Route.Regx is not meant to do more than input validation, do your complex work in your handler.

  3. For more details, see sample projects

  4. PRs are welcome.

  5. Having a problem? Verify that you are implementing rightly, check sample projects, and if the problem persists, create an issue.

  6. Want to hire competent engineer(s) for a ussd application? Shoot me an email

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.3 137 9/29/2023
1.0.2 119 9/29/2023

New + Improved

- Removed the need to inject DistributedCacheEntryOptions