Horseshoe.NET.Odbc

ADO.NET-based ODBC data access wrappers


Keywords
Data, Database, ODBC, Query, SQL
Install
Install-Package Horseshoe.NET.Odbc -Version 3.1.2

Documentation

Horseshoe.NET icon

Horseshoe.NET

A suite of .NET utilities with a dual purpose: simplify coding tasks and offer a variety of unique capabilities for developers. What this represents is a career's worth of collecting useful code snippets packaged as a NuGet library that any .NET developer can utilize.

A large portion of this code base is dedicated to replacing verbose, repetitive boilerplate code for tasks such as configuration, ADO.NET / ODP.NET database queries and web API calls with highly customizable single line code replacements.

Packages and Namespaces

  • (NuGet package)
    • (more namespaces)
  • Horseshoe.NET
    • Horseshoe.NET.Bootstrap
    • Horseshoe.NET.Collections
    • Horseshoe.NET.Comparison (introducing the 'Criterinator' search tool)
    • Horseshoe.NET.ConsoleX
      • Horseshoe.NET.ConsoleX.Plugins
    • Horseshoe.NET.Crypto
    • Horseshoe.NET.Data
    • Horseshoe.NET.DataImport
    • Horseshoe.NET.DateAndTime
    • Horseshoe.NET.Db
    • Horseshoe.NET.Dotnet
    • Horseshoe.NET.Email
      • Horseshoe.NET.Email.EmailToSms
    • Horseshoe.NET.Format
    • Horseshoe.NET.IO
      • Horseshoe.NET.IO.FileFilter
      • Horseshoe.NET.IO.FileTraversal
      • Horseshoe.NET.Ftp
    • Horseshoe.NET.ObjectsTypesAndValues
    • Horseshoe.NET.OleDb (.NET Framework only)
    • Horseshoe.NET.Primitives
    • Horseshoe.NET.RelayMessages
    • Horseshoe.NET.Text
      • Horseshoe.NET.Text.TextGrid
    • Horseshoe.NET.Xml
      • Horseshoe.NET.Xml.Doc
  • Horseshoe.NET.ActiveDirectory
  • Horseshoe.NET.Caching
  • Horseshoe.NET.Caching.Abstractions (namespace Horseshoe.NET.Caching)
  • Horseshoe.NET.Configuration
  • Horseshoe.NET.Excel
  • Horseshoe.NET.Http
    • Horseshoe.NET.Http.Mvc
    • Horseshoe.NET.Http.ReportingServices
    • Horseshoe.NET.Http.WebForms (.NET Framework only)
  • Horseshoe.NET.Jwt
  • Horseshoe.NET.Jwt.Abstractions (namespace Horseshoe.NET.Jwt)
  • Horseshoe.NET.Mathematics (new)
    • Horseshoe.NET.Mathematics.Finance
    • Horseshoe.NET.Mathematics.Geometry
      • Horseshoe.NET.Mathematics.Geometry.Trigonometry
  • Horseshoe.NET.Odbc
  • Horseshoe.NET.OracleDb
  • Horseshoe.NET.SecureIO
  • Horseshoe.NET.SqlDb

Code Examples

Horseshoe.NET.ActiveDirectory

var userIdNameOrEmail = "djones1" -or- "david.jones@mybiz.com" -or- "Jones, David E. [Contractor]";
var ldapProperties = "name|cn|samaccountname|memberof";   // (optional)

var user = ADUtil.GetUser(userIdNameOrEmail, propertiesToLoad: ldapProperties);
-or-
var user = ADUtil.Authenticate(userIdNameOrEmail, "P@$$W0rd123", propertiesToLoad: ldapProperties);

user.GetGroups(orderByAdsPath: true);        // "All Contractors", "DB Admins", "Hiring Team"...
user.OU;                                     // "Contractors"
user.RawOU;                                  // LDAP://OU=Contractors,DC=mybiz,DC=com
ADUtil.ListOUs();                            // (lists all OUs in Active Directory)
ADEngine.GetDomainContext().ConnectedServer; // (lists name of connected domain controller)

Horseshoe.NET.Comparison (introducing the 'Criterinator' search tool)

var filteredEmployees = SearchEmployeesByLastName("Finkleman", ignoreCase: true);

IEnumerable<Employee> SearchEmployeesByLastName(ICriterinator<string> lastNameCriterinator)
{
    return allEmployees.Where(e => lastNameCriterinator.IsMatch(e.LastName))
}

IEnumerable<Employee> SearchEmployeesByLastNameContains(string lastNameOrPartial, bool ignoreCase = false)
{
    return ignoreCase 
        ? SearchEmployeesByLastName(Criterinator.ContainsIgnoreCase(lastNameOrPartial))
        : SearchEmployeesByLastName(Criterinator.Contains(lastNameOrPartial))
}

Horseshoe.NET.Configuration

<appSettings>
  <add key="myInt" value="90" />
  <add key="myHexInt" value="5a" />
  <add key="myHexInt_Annotation" value="5a[hex]" />
  <add key="myHexInt_Format" value="0x5a" />
</appSettings>
// Getting an int...
Config.Get<int>("myInt");                // value="90" -> 90

// Getting a hex formatted int...
Config.Get<int>("myHexInt",              // value="5a" -> 90
    numberStyle: NumberStyles.HexNumber);

// Getting a hex formatted int w/ key annotation...
Config.Get<int>("myHexInt[hex]");        // value="5a" -> 90

// Getting a hex formatted int w/ data annotation or data format...
Config.Get<int>("myHexInt_Annotation");  // value="5a[hex]" -> 90
Config.Get<int>("myHexInt_Format");      // value="0x5a" -> 90

// Before Horseshoe.NET... 
var stringValue = ConfigurationManager.AppSettings["myInt"];
if (stringValue != null)
    return int.Parse(stringValue);
- or -
var stringValue = ConfigurationManager.AppSettings["myHexInt"];
if (stringValue != null)
    return int.Parse(stringValue, NumberStyles.HexNumber);

Horseshoe.NET.ConsoleX

Console.WriteLine("Select your preferred day(s) for playing pickleball.");
var daysOfWeek = new [] { "Sunday", "Monday", ... , "Friday", "Saturday" };
result = PromptX.List(daysOfWeek, selectionMode: ListSelectionMode.ZeroOrMore);
result.selectedIndices   // [ 2, 3, 4 ]
result.selectedItems     // [ "Monday", "Tuesday", "Wednesday" ]

// console input/output        
[1] Sunday
[2] Monday
[3] Tuesday
[4] Wednesday
[5] Thursday
[6] Friday
[7] Saturday
> 0               // ** 0 is outside the allowed range: 1 to 7 **
                  // Press any key to try again…
> 2               // [ "Monday" ]
> 2-4,6           // [ "Monday", "Tuesday", "Wednesday", "Friday" ]
> all             // [ "Sunday", "Monday",      ...    , "Friday", "Saturday" ]
> all except 1,7  // [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" ]
> none (or blank) // [ ]

Horseshoe.NET.Crypto

var plaintext = "H1ghW@y2Hev3n";
var b64Options = new CryptoOptions { IsCiphertextBase64Encoded = true };
ciphertext = Encrypt.String(plaintext, b64Options);  // "2puPR6R9//bo/D3hK+bONQ=="
plaintext = Decrypt.String(ciphertext, b64Options);  // "H1ghW@y2Hev3n"

Horseshoe.NET.Excel

// [data.xlsx]
// ╔═══╦═════════╦═════╦═══════════╦═══════════════════╗
// ║   ║    A    ║  B  ║     C     ║         D         ║
// ╠═══╬═════════╩═════╩═══════════╩═══════════════════╣
// ║ 1 ║ Name    │ Age │ Fav Color │ Fav Food          ║
// ╠═══╣─────────┼─────┼───────────┼───────────────────╢
// ║ 2 ║ Gerald  │  37 │ red       │ chewing gum       ║
// ╠═══╣─────────┼─────┼───────────┼───────────────────╢
// ║ 3 ║ Abigail │  22 │ blue      │ raspberry sorbet  ║
// ╠═══╣─────────┼─────┼───────────┼───────────────────╢
// ║ 4 ║ Fred    │ 101 │ yello     │ grapefruit        ║
// ╠═══╣─────────┼─────┼───────────┼───────────────────╢
// ║ 5 ║ Diane   │  56 │ green     │ broccoli + cheese ║
// ╚═══╩═════════╧═════╧═══════════╧═══════════════════╝

var dataImport = ImportExcelData.AsDataImport
(
    "data.xlsx",
    hasHeaderRow: true,
    autoTrunc: AutoTruncate.Zap
);
var results = dataImport.ExportToStringArrays();
// [ "Gerald" ,  "37", "red"   , "chewing gum"       ]
// [ "Abigail",  "22", "blue"  , "raspberry sorbet"  ]
// [ "Fred"   , "101", "yellow", "grapefruit"        ]
// [ "Diane"  ,  "56", "green" , "broccoli + cheese" ]

Horseshoe.NET.Http

// basic HTTP call
var apiResponse = Get.AsJson<WebServiceResponse<string>>
(
    "https://site.com/service/endpoint"
);
apiResponse.Data;    // { "requestedItems" : [ { "name": "Item ABC"}, { "name": "Item DEF"}... ] }

// HTTP call with JWT authorization
var token = "eyjg73ls0...";
var apiResponse = Get.AsJson<WebServiceResponse<string>>
(
    "https://site.com/service/endpoint", 
    alterHeaders: (hdrs) =>
        hdrs.Add(HttpRequestHeader.Authorization, "Bearer " + token)
);
apiResponse.Data;    // { "authorizedItems" : [ { "name": "Item ABC"}, { "name": "Item DEF"}... ] }

Horseshoe.NET.Jwt

// mint a token
// note: the same digital signature crypto key that creates the digital signature is also used to validate it
TokenService.CreateAccessToken 
(
    tokenKey,            // e.g. encoding.GetBytes("ah476&ewj^!09")
    roles,               // e.g. { "All Contractors", "Domain Admin" }
    keyId,               // e.g. "0001"
    lifespanInSeconds,   // default is 3600 (1 hour)
    securityAlgorithm    // default is "HS256"
);                                            // "eyjg73ls0..." (encoded JWT)

// parse a token
// note: If ADFS '/token' provided the JWT roles will include Active Directory group memberships
TokenService.ParseToken("eyjg73ls0...");      // -> token as instance of AccessToken

Horseshoe.NET.Mathematics.Finance

FinanceEngine
    .GenerateCreditPayoffProjection(accounts, snowballing: true, extraSnowballAmount: 100m)
    .RenderToTextGrid();

// Date     │ Line of Credit                   │ Credit Card                       │ Totals                 
//          │ APR: 6.24% ($20.80)              │ Acct #: *7890                     │                        
//          │ Balance: $4,000.00               │ APR: 12.99% ($108.25)             │                        
//          │ Min Payment: $150.00             │ Balance: $10,000.00               │                        
//          │                                  │ Min Payment: $200.00              │                        
// ----     │ --------------------             │ ---------------------             │ ------                 
//          │ Pmt     Pri     Int    Bal       │ Pmt     Pri     Int     Bal       │ Pmt     Pri     Int    
// Feb 2025 │ $250.00 $229.20 $20.80 $3,770.80 │ $200.00 $ 91.75 $108.25 $9,908.25 │ $450.00 $320.95 $129.05
// Mar 2025 │ $250.00 $230.39 $19.61 $3,540.41 │ $200.00 $ 92.74 $107.26 $9,815.51 │ $450.00 $323.13 $126.87
// Apr 2025 │ $250.00 $231.59 $18.41 $3,308.82 │ $200.00 $ 93.75 $106.25 $9,721.76 │ $450.00 $325.34 $124.66
// May 2025 │ $250.00 $232.79 $17.21 $3,076.03 │ $200.00 $ 94.76 $105.24 $9,627.00 │ $450.00 $327.55 $122.45
// Jun 2025 │ $250.00 $234.00 $16.00 $2,842.03 │ $200.00 $ 95.79 $104.21 $9,531.21 │ $450.00 $329.79 $120.21
// Jul 2025 │ $250.00 $235.22 $14.78 $2,606.81 │ $200.00 $ 96.82 $103.18 $9,434.39 │ $450.00 $332.04 $117.96
// Aug 2025 │ $250.00 $236.44 $13.56 $2,370.37 │ $200.00 $ 97.87 $102.13 $9,336.52 │ $450.00 $334.31 $115.69
// Sep 2025 │ $250.00 $237.67 $12.33 $2,132.70 │ $200.00 $ 98.93 $101.07 $9,237.59 │ $450.00 $336.60 $113.40
// Oct 2025 │ $250.00 $238.91 $11.09 $1,893.79 │ $200.00 $100.00 $100.00 $9,137.59 │ $450.00 $338.91 $111.09
// Nov 2025 │ $250.00 $240.15 $ 9.85 $1,653.64 │ $200.00 $101.09 $ 98.91 $9,036.50 │ $450.00 $341.24 $108.76
// Dec 2025 │ $250.00 $241.40 $ 8.60 $1,412.24 │ $200.00 $102.18 $ 97.82 $8,934.32 │ $450.00 $343.58 $106.42
// Jan 2026 │ $250.00 $242.66 $ 7.34 $1,169.58 │ $200.00 $103.29 $ 96.71 $8,831.03 │ $450.00 $345.95 $104.05
// Feb 2026 │ $250.00 $243.92 $ 6.08 $  925.66 │ $200.00 $104.40 $ 95.60 $8,726.63 │ $450.00 $348.32 $101.68
// Mar 2026 │ $250.00 $245.19 $ 4.81 $  680.47 │ $200.00 $105.53 $ 94.47 $8,621.10 │ $450.00 $350.72 $ 99.28
// Apr 2026 │ $250.00 $246.46 $ 3.54 $  434.01 │ $200.00 $106.68 $ 93.32 $8,514.42 │ $450.00 $353.14 $ 96.86
// May 2026 │ $250.00 $247.74 $ 2.26 $  186.27 │ $200.00 $107.83 $ 92.17 $8,406.59 │ $450.00 $355.57 $ 94.43
// Jun 2026 │ $187.24 $186.27 $ 0.97 $    0.00 │ $262.76 $171.76 $ 91.00 $8,234.83 │ $450.00 $358.03 $ 91.97
// Jul 2026 │                                  │ $450.00 $360.86 $ 89.14 $7,873.97 │ $450.00 $360.86 $ 89.14
// Aug 2026 │                                  │ $450.00 $364.76 $ 85.24 $7,509.21 │ $450.00 $364.76 $ 85.24
// Sep 2026 │                                  │ $450.00 $368.71 $ 81.29 $7,140.50 │ $450.00 $368.71 $ 81.29
// Oct 2026 │                                  │ $450.00 $372.70 $ 77.30 $6,767.80 │ $450.00 $372.70 $ 77.30
// Nov 2026 │                                  │ $450.00 $376.74 $ 73.26 $6,391.06 │ $450.00 $376.74 $ 73.26
// Dec 2026 │                                  │ $450.00 $380.82 $ 69.18 $6,010.24 │ $450.00 $380.82 $ 69.18
// Jan 2027 │                                  │ $450.00 $384.94 $ 65.06 $5,625.30 │ $450.00 $384.94 $ 65.06
// Feb 2027 │                                  │ $450.00 $389.11 $ 60.89 $5,236.19 │ $450.00 $389.11 $ 60.89
// Mar 2027 │                                  │ $450.00 $393.32 $ 56.68 $4,842.87 │ $450.00 $393.32 $ 56.68
// Apr 2027 │                                  │ $450.00 $397.58 $ 52.42 $4,445.29 │ $450.00 $397.58 $ 52.42
// May 2027 │                                  │ $450.00 $401.88 $ 48.12 $4,043.41 │ $450.00 $401.88 $ 48.12
// Jun 2027 │                                  │ $450.00 $406.23 $ 43.77 $3,637.18 │ $450.00 $406.23 $ 43.77
// Jul 2027 │                                  │ $450.00 $410.63 $ 39.37 $3,226.55 │ $450.00 $410.63 $ 39.37
// Aug 2027 │                                  │ $450.00 $415.07 $ 34.93 $2,811.48 │ $450.00 $415.07 $ 34.93
// Sep 2027 │                                  │ $450.00 $419.57 $ 30.43 $2,391.91 │ $450.00 $419.57 $ 30.43
// Oct 2027 │                                  │ $450.00 $424.11 $ 25.89 $1,967.80 │ $450.00 $424.11 $ 25.89
// Nov 2027 │                                  │ $450.00 $428.70 $ 21.30 $1,539.10 │ $450.00 $428.70 $ 21.30
// Dec 2027 │                                  │ $450.00 $433.34 $ 16.66 $1,105.76 │ $450.00 $433.34 $ 16.66
// Jan 2028 │                                  │ $450.00 $438.03 $ 11.97 $  667.73 │ $450.00 $438.03 $ 11.97
// Feb 2028 │                                  │ $450.00 $442.77 $  7.23 $  224.96 │ $450.00 $442.77 $  7.23
// Mar 2028 │                                  │ $227.40 $224.96 $  2.44 $    0.00 │ $227.40 $224.96 $  2.44

var planningItems = new List<BudgetPlanningItem>
{
    new BudgetPlanningItem { Name = "Paycheck", Amount = 3000m, Recurrence = "w-2"},
    new BudgetPlanningItem { Name = "Retirement Pension", Amount = 900m, Recurrence = "last"},
    new BudgetPlanningItem { Name = "Grocery allowance ($400/mo)", Amount = -200m, Recurrence = "1,15"},
    ...
};
var budget = Budget.GenerateSimpleBudget(planningItems);
TextGrid.FromCollection(budget).Render();

//    Date Name                               Amount Running Total
//  ------ -----------------------------  ---------- -------------
//   Apr 1 Bill Payment #1                   $30.00     $1,970.00
//   Apr 1 Grocery allowance ($400/mo)      $200.00     $1,770.00
//   Apr 1 Eating out allowance ($150/mo)    $75.00     $1,695.00
//   Apr 1 Insurance                        $200.00     $1,495.00
//   Apr 1 Mortgage                       $1,000.00       $495.00
//   Apr 1 Gas allowance ($300/mo)          $150.00       $345.00
//   Apr 1 Bill Payment #5                   $30.00       $315.00
//   Apr 1 Amazon allowance ($60/mo)         $30.00       $285.00
//   Apr 2 Bill Payment #2                   $60.00       $225.00
//   Apr 2 Bill Payment #6                   $60.00       $165.00
//   Apr 3 Bill Payment #7                   $90.00        $75.00
//   Apr 3 Bill Payment #3                   $90.00        $15.00-
//   Apr 4 Paycheck                       $3,000.00+    $2,985.00
//   Apr 4 Tithing                          $300.00     $2,685.00
//   Apr 4 Bill Payment #8                  $120.00     $2,565.00
//   Apr 4 Bill Payment #4                  $120.00     $2,445.00
//  Apr 15 Grocery allowance ($400/mo)      $200.00     $2,245.00
//  Apr 15 Eating out allowance ($150/mo)    $75.00     $2,170.00
//  Apr 15 Amazon allowance ($60/mo)         $30.00     $2,140.00
//  Apr 15 Gas allowance ($300/mo)          $150.00     $1,990.00
//  Apr 18 Paycheck                       $3,000.00+    $4,990.00
//  Apr 18 Tithing                          $300.00     $4,690.00
//  Apr 30 Retirement Pension               $900.00+    $5,590.00

Horseshoe.NET.Mathematics.Geometry[.Trigonometry]

A suite of methods representing geometric and trigonometric formulas and shape objects that can often self-populate angle and length values in the case of incomplete construction.

Code Examples

RightTriangle rightTriangle = new RightTriangle(a: 60.0, ac: 45.0, precision: 4);
Console.WriteLine(rightTriangle);

// Complete triangle: (1 iteration)
//               B:30°
//                /|
//  (hypotenuse) / |
//           AB /  | BC
//      len=90 /   | len=77.9423
//            /   _|
//           /)__|_|
//      A:60°  AC   C:90°
//             len=45

Horseshoe.NET.OleDb|Odbc|OracleDb|SqlDb

// DB connection not established and statement not executed yet
var query = Query.FromStatement
(
    "Server=MYSVR;Database=MYDB;UID=me;PWD=myPwd"                        // (ODBC)
    -or-
    "Data Source=me/myPwd@//MYSVR:1650//MYDB"                            // (Oracle)
    -or-
    "Data Source=MYSVR;Initial Catalog=MYDB;User ID=me;Password=myPwd",  // (SQL Server)
    "SELECT * FROM [MySchema].[MyTable]"
); 

// creating a row parser offers fine grained control over converting data rows to objects
var rowParser = new RowParser<MyModel>
(
    (IDataReader reader) => new MyModel
    {
        MyStringProperty = Zap.String(reader["varcharColumn"]),
        MyNonNullStringProperty = (string)reader["nonNullVarcharColumn"],
        MyNullableIntProperty = Zap.NInt(reader["intColumn"]),
        MyNonNullIntProperty = (int)reader["nonNullIntColumn"],
        MyCustomProperty = new MyCustomClass
        {
            ID = ((int)reader["nonNullIntColumn2"], 
            Description = (string)reader["nonNullVarcharColumn2"]
        }
    }
);

// the following causes the DB connection to open and the statement to execute
IEnumerable<MyModel> list = query.AsList(rowParser);
string str = Zap.String(query.AsScalar());
DataTable dataTable = query.AsDataTable("My DataTable");

Horseshoe.NET.SecureIO

pseudoConnectionString = "sftp://username@11.22.33.44//root/subdir?password=PA$$w0rd";

var dirContents = Sftp.ListDirectoryContents
(
    fileMask: FtpFileMasks.Txt,           // or "*.txt"
    connectionInfo: pseudoConnectionString
);
foreach (var fileName in dirContents)
    Console.WriteLine(fileName);

Sftp.CreateFile
(
    "hello.txt",                          // remote dest file name
    "Hello World!",                       // file contents
    connectionInfo: pseudoConnectionString
);

Sftp.UploadFile
(
    "C:\\hello.txt",                      // local src file path
    connectionInfo: pseudoConnectionString
);

var stream = Sftp.DownloadFile
(
    "hello.txt",                          // remote src file name
    connectionInfo: pseudoConnectionString
);
Console.WriteLine("File length: " + stream.Length);
Console.WriteLine("File contents: " + encoding.GetString(stream.ToArray()));

Sftp.DeleteFile
(
    "hello.txt",                          // remote src file name
    connectionInfo: pseudoConnectionString
);

Horseshoe.NET.Text

var phrase = "Å¢t Øñę\u0000”;
TextClean.ToAsciiPrintable(phrase);  // -> "Act One" (Unicode -> ASCII, [NUL] -> "")
TextUtil.Reveal(phrase, options: RevealOptions.All);
// "Å¢t Øñę" -> ['Å'-197]['¢'-162]['t'-116][space]['Ø'-216]['ñ'-241]['ę'-281][NUL]
// "Act One" -> [‘A’-65 ][‘c’-99 ][’t’-116][space]['O'-79 ][’n'-110]['e'-101]