Introduction
When writing applications, you always find yourself doing the same mundane tasks, like converting between data types or accessing data in a database, just to mention a few things.
I have decided to prep some of my utility classes with comments and publish them here at The Code Project. Most isn't rocket science and nothing you can't do with a few lines of code when needed - but when you write the same few lines of code several times, it starts to become annoying, and the utility assembly emerges.
Name |
Function |
RPC Convert |
Alternative to the Convert class provided by Microsoft, but with additional tool methods. |
RPC Database |
Classes that can be used to manage databases, tables, and records. |
RPC Directory |
Classes that make it easy to work with containers, groups, users, and computers in Active Directory. |
RPC SCA |
Class to handle keys and encrypt/decrypt text using a Symmetric Cryptographic Algorithm. |
RPC Triple |
This can best be described as a tree state boolean. |
You can find the release history at the bottom of this article.
RPC Convert
I like the Microsoft Convert
class, but I find it inadequate and would have liked to create my own RpcConvert
inheriting from Convert
, but Microsoft sealed their Convert
class. Instead, I decided to rewrite my RpcConvert
class with Extension Methods, which is available with version 3.5 of the .NET framework.
I wanted one class for my convert-methods, so I decided to include most of the conversions you'll find in Microsoft's Convert
class; some might call me crazy - but that's how I want it. Over time, my RpcConvert
class has evolved to a Swiss army knife, with non-converting methods.
Often when I convert from one data type to another, I don't want an exception to be thrown if the conversion fails; instead, I want a default value returned on exceptions.
Here is the example code converting from String
to Int32
, both as a normal call or as an Extension Method:
String str = "1717";
Int32 i = 0;
i = RpcConvert.ToInt32(str);
i = RpcConvert.ToInt32(str, -1);
i = str.ToInt32();
i = str.ToInt32(0);
These are some of the conversions my RpcConvert
class performs:
- Convert between basic types (
SByte
, Int16
, Int32
, Int64
, Byte
, UInt16
, UInt32
, UInt64
, Single
, Double
, Decimal
)
- Convert between most basic types and
DateTime
, Guid
, String
, and Object
- Split and merge conversions on
String
lists (List<String>
, String[]
, StringCollection
)
- String to and from file
- String from URL (download)
- String to and from Base64
- String to and from Rijndael
- String to and from RTF
- Generate random 'password' string
IsMatch
testing for wildcard (* and ?) match in a list of strings
RPC Database
This is some of my old code that goes back to the days of Borland Delphi. I started programming in C# right from the beginning, and one of my first projects was to port my Pascal database code to C#. A lot has happened since, because C# and .NET offer some nice features not available in Pascal at the time - one of these things is generics.
I haven't studied the new LINQ functionality that comes with .NET 3.5, so perhaps Microsoft has made my code redundant.
How it Works
The basic idea is that I want each record I work with in an object, and I want to be able to change the object properties and commit the change to the database by invoking a Save method. The same way, I want to be able to delete the record by invoking a Delete method.
And so, to use an RPC database, you write a class for each table you want to work with. This class is decorated with an attribute. Each field in the table is created as a property in the class, and each property that maps to a field in the database is decorated with an attribute.
Consider that I want to work with a table named "CountryInfo" with an auto-numeric key "Code", a "CountryName", and finally a "Population" field. The class will look something like this:
[RpcDataTable("CountryInfo")]
public class Countries : RpcDataRecord {
[RpcDataColumn("Code", RpcDataField.Serial, RpcDataAttribute.Id |
RpcDataAttribute.Required | RpcDataAttribute.Unique)]
public Int32 CountryCode
{
get
{
return RpcConvert.ToInt32(this["Code"]);
}
set
{
this["Code"] = value;
}
}
[RpcDataColumn(RpcDataField.String, RpcDataAttribute.Required)]
public String CountryName
{
get
{
return RpcConvert.ToString(this["CountryName"]);
}
set
{
this["CountryName"] = value;
}
}
[RpcDataColumn("Population", RpcDataField.Int32, RpcDataAttribute.Required)]
public Int32 CountryPopulation
{
get
{
return RpcConvert.ToInt32(this["Population"]);
}
set
{
this["Population"] = value;
}
}
public static Countries New(RpcDatabase db, String name,
Int32 population, Boolean saveTheRecord)
{
Countries record = new Countries();
record.Database = db;
record.CountryName = name;
record.CountryPopulation = population;
if (saveTheRecord == true)
{
record.Save();
}
return record; }
}
Often, I override the "BeforeSave
" method, and validate the data here. If the data isn't valid, the method can return false
or throw an exception. There are many similar methods to override.
Here is some example code that shows how to use the RpcDatabase
class and the Countries
class shown above.
RpcDatabase db = new RpcDatabase( RpcDataEngine.MicrosoftAccessFile,
Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),
"Country Database", null, null, 15);
db.DatabaseCreate();
db.Connect();
db.TableCreate(typeof(Countries));
Console.WriteLine(String.Format("{0} tables in the database", db.TableCount()));
Countries.New(db, "Norge", 4525116, true);
Countries.New(db, "Denmark", 5368854, true);
Countries.New(db, "Faroe Islands", 46011, true);
Countries.New(db, "Greenland", 56376, true);
Countries.New(db, "Sweden", 8876744, true);
Countries.New(db, "Iceland", 279384, true);
Countries.New(db, "Finland", 5183545, true);
RpcDataList<Countries> countries = db.QueryFilter<Countries>("[CountryName] = 'Norge'");
Countries country = countries[0];
country.CountryName = "Norway";
country.Save();
countries = db.QueryAll<Countries>();
countries.ApplySort("CountryPopulation",
System.ComponentModel.ListSortDirection.Descending);
foreach (Countries countryRecord in countries)
{
Console.WriteLine(String.Format("{0} has a population of {1:n0}",
countryRecord.CountryName, countryRecord.CountryPopulation));
}
db.TableDelete(typeof(Countries));
Console.WriteLine(String.Format("{0} tables in the database", db.TableCount()));
db.DatabaseDelete();
I am still using the code, and sometimes implement new features. At this time, I still need to support threading, transactions, and indexes.
RPC Directory
RPC Directory consists of a main class and a few classes encapsulating some of the basic data classes in the Active Directory:
RpcDirectoryContainer
RpcDirectoryGroup
RpcDirectoryUser
RpcDirectoryComputer
The 'DomainDNS
', 'Container
', and 'OrganizationalUnit
' are all treated as a container in my code. When a new container is created, it is created as an OU.
RpcDirectory ad = new RpcDirectory("admin@domain", "adminPassword");
RpcDirectoryContainer container = ad.CreateContainer("Test OU");
RpcDirectoryUser user = ad.CreateUser("myUserId", container);
user.FirstName = "Håkon";
user.LastName = "Hansen";
user.Description = "New user created by my application.";
user.Phone = "012 3456 7890";
user.Password = "Password1234";
user.PasswordChangeForced = true;
user.Enabled = true;
user.LogonScript = "sampleUsers.cmd";
user.ProfileDirectory = "\\\\Server\\Profiles\\myUserId";
user.MailboxEnable(true);
user.SmtpAddresses = RpcConvert.ToStringList(new String[] {"myUserId@domain",
"Haakon-Hansen@domain"});
There is one thing I still need to implement in RPC Directory:
- Encode special characters in the ID with backslash, when creating a new container, group, and user.
RPC SCA (Symmetric Cryptographic Algorithm)
Once again, Microsoft .NET makes it easy to use Cryptography, but again, I like to have that one class offering the basics.
String str = "My readable text";
RpcSCA sca = RpcSCA.TrippleDES();
sca.PrivateKey = "Password";
str = sca.Encrypt(str);
RPC Triple
Ever wanted a tree state boolean? Well, the Triple
class is just that. I considered using the CheckState
class, but ended up writing my own class with a lot of operator methods.
Triple t1 = true;
Triple t2 = Triple.Unknown;
if (t1 == false) { ... }
if (t2.IsUnknown == true) { ... }
Believe it or not, it is actually useful sometimes.
History
Date |
Comments |
11-08-2009 |
RPC Database: code added to the article. RPC Directory: Added code that finds the mailbox store, when mailbox enabling users or groups. This article by LiQuick showed me how to implement it. |
09-08-2009 |
First public release of some of my RPC Plumming code. |