RPC 管道(通用工具和实用程序)






4.25/5 (4投票s)
管道,工具,实用程序。
引言
在编写应用程序时,您会发现自己总是要执行一些相同的单调任务,例如数据类型之间的转换或访问数据库中的数据,仅举几例。
我决定在一些实用程序类中添加注释,并将它们发布到 The Code Project。其中大多数并非高深莫测,也不是您在需要时无法用几行代码完成的事情 - 但当您编写相同的几行代码数次时,它就会变得令人厌烦,这时实用程序程序集就应运而生了。
名称 | 函数 |
RPC 转换 | Microsoft 提供的 Convert 类的替代品,但具有额外的工具方法。 |
RPC 数据库 | 可用于管理数据库、表和记录的类。 |
RPC 目录 | 使处理 Active Directory 中的容器、组、用户和计算机变得容易的类。 |
RPC SCA | 用于处理密钥并使用对称加密算法加密/解密文本的类。 |
RPC Triple | 这最好描述为布尔的三种状态。 |
您可以在本文底部找到 发布历史记录。
RPC 转换
我喜欢 Microsoft 的 Convert
类,但我发现它不够用,并且希望创建我自己的 RpcConvert
类继承自 Convert
,但 Microsoft 封锁了他们的 Convert
类。因此,我决定使用扩展方法重写我的 RpcConvert
类,这在 .NET Framework 3.5 版本中可用。
我想要一个类来处理我的转换方法,所以我决定包含 Microsoft Convert
类中的大多数转换;有些人可能会认为我疯狂 - 但我就是这样想的。随着时间的推移,我的 RpcConvert
类已经发展成了一个瑞士军刀,并包含非转换方法。
通常,当我从一种数据类型转换为另一种数据类型时,我不希望在转换失败时抛出异常;相反,我希望在异常情况下返回一个默认值。
这是从 String
转换为 Int32
的示例代码,包括正常调用和扩展方法调用。
String str = "1717";
Int32 i = 0;
// Convert the String to Int32, returns 0 on exceptions.
i = RpcConvert.ToInt32(str);
// Convert the String to Int32, returns -1 on exceptions.
i = RpcConvert.ToInt32(str, -1);
// Convert the String to Int32 (Extension method), returns 0 on exceptions.
i = str.ToInt32();
// Convert the String to Int32 (Extension method), returns 0 on exceptions.
i = str.ToInt32(0);
以下是我的 RpcConvert
类执行的一些转换:
- 基本类型之间的转换(
SByte
、Int16
、Int32
、Int64
、Byte
、UInt16
、UInt32
、UInt64
、Single
、Double
、Decimal
) - 大多数基本类型与
DateTime
、Guid
、String
和Object
之间的转换 String
列表(List<String>
、String[]
、StringCollection
)的字符串拆分和合并转换- 字符串与文件之间的转换
- 从 URL 获取字符串(下载)
- 字符串与 Base64 之间的转换
- 字符串与 Rijndael 之间的转换
- 字符串与 RTF 之间的转换
- 生成随机“密码”字符串
IsMatch
测试通配符(* 和 ?)在字符串列表中的匹配
RPC 数据库
这是我的一些旧代码,可以追溯到 Borland Delphi 时代。我从一开始就学习 C#,我的第一个项目之一就是将我的 Pascal 数据库代码移植到 C#。此后发生了许多变化,因为 C# 和 .NET 提供了一些 Pascal 当时没有的优秀功能 - 其中之一就是泛型。
我没有研究 .NET 3.5 随附的新 LINQ 功能,所以也许 Microsoft 已经使我的代码变得多余。
工作原理
基本思想是,我希望我处理的每个记录都在一个对象中,并且我希望能够更改对象的属性并通过调用 Save 方法将更改提交到数据库。同样,我希望通过调用 Delete 方法来删除记录。
因此,要使用 RPC 数据库,您需要为要处理的每个表编写一个类。该类带有属性。表中的每个字段都作为类中的属性创建,并且每个映射到数据库字段的属性都带有属性。
考虑我想要处理一个名为“CountryInfo”的表,该表有一个自动编号键“Code”,一个“CountryName”,最后还有一个“Population”字段。该类看起来大致如下。
// The class is decorated with a RpcDataTable.
// It represents a table named 'CountryInfo' in the database.
// If the table name is omitted, the class name is used as the table name.
[RpcDataTable("CountryInfo")]
public class Countries : RpcDataRecord {
// The property is decorated with a RpcDataColumn.
// It represents a field named 'Code' in the table.
// This field is a INTEGER/SERIAL and a unique required key.
[RpcDataColumn("Code", RpcDataField.Serial, RpcDataAttribute.Id |
RpcDataAttribute.Required | RpcDataAttribute.Unique)]
public Int32 CountryCode
{
get
{
return RpcConvert.ToInt32(this["Code"]);
}
set
{
this["Code"] = value;
}
} // CountryCode
[RpcDataColumn(RpcDataField.String, RpcDataAttribute.Required)]
public String CountryName
{
get
{
return RpcConvert.ToString(this["CountryName"]);
}
set
{
this["CountryName"] = value;
}
} // CountryName
[RpcDataColumn("Population", RpcDataField.Int32, RpcDataAttribute.Required)]
public Int32 CountryPopulation
{
get
{
return RpcConvert.ToInt32(this["Population"]);
}
set
{
this["Population"] = value;
}
} // CountryPopulation
// Static factory method to create a new object.
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; } // New
}// Countries
通常,我会在“BeforeSave
”方法中覆盖,并在那里验证数据。如果数据无效,该方法可以返回 false
或抛出异常。有许多类似的方法可以覆盖。
以下是一些示例代码,展示了如何使用上面所示的 RpcDatabase
类和 Countries
类。
// Create a new Access database on the desktop, or open a existing one.
// Notice when working with Access databases, the host is actually the
// directory where the database file is, and the database is the name
// of the database file without the extension.
RpcDatabase db = new RpcDatabase( RpcDataEngine.MicrosoftAccessFile,
Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),
"Country Database", null, null, 15);
db.DatabaseCreate();
db.Connect();
// Create the table.
db.TableCreate(typeof(Countries));
Console.WriteLine(String.Format("{0} tables in the database", db.TableCount()));
// Create a few records in the database.
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);
// Get and update a record.
// I don't know the CountryCode because it is a serial, so in
// real life another key would have been better.
// The QueryFilter method accepts a filter which is the text you
// put after the WHERE word in a complete SQL query.
RpcDataList<Countries> countries = db.QueryFilter<Countries>("[CountryName] = 'Norge'");
Countries country = countries[0];
country.CountryName = "Norway";
country.Save();
// Get and show all records.
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));
}
// Delete the table.
db.TableDelete(typeof(Countries));
Console.WriteLine(String.Format("{0} tables in the database", db.TableCount()));
// Delete the database.
// This disconnects tha database first, but if the application don't
// quit, .NET keeps the MDB file open for a long time
// incase the database is opened again.
// I don't know how to force close the Access database.
db.DatabaseDelete();
我仍在继续使用这些代码,有时会实现新功能。目前,我仍然需要支持线程、事务和索引。
RPC 目录
RPC Directory 由一个主类和几个封装 Active Directory 中一些基本数据类的类组成。
RpcDirectoryContainer
RpcDirectoryGroup
RpcDirectoryUser
RpcDirectoryComputer
在我的代码中,“DomainDNS
”、“Container
”和“OrganizationalUnit
”都被视为容器。当创建一个新容器时,它会被创建为一个 OU。
// Create a new user in a new container in the AD.
RpcDirectory ad = new RpcDirectory("admin@domain", "adminPassword");
RpcDirectoryContainer container = ad.CreateContainer("Test OU");
RpcDirectoryUser user = ad.CreateUser("myUserId", container);
// Set some user properties.
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 must change password at next login.
user.Enabled = true; // Enable the user account.
user.LogonScript = "sampleUsers.cmd";
user.ProfileDirectory = "\\\\Server\\Profiles\\myUserId";
// Mailbox enable the user account (Microsoft Exchange).
// The mailbox is added to the first Store in the first Storage Group
// on the first Exchange server.
user.MailboxEnable(true);
// Create two SMTP e-mail addresses.
// The first e-mail address is the default address.
user.SmtpAddresses = RpcConvert.ToStringList(new String[] {"myUserId@domain",
"Haakon-Hansen@domain"});
RPC Directory 中还有一项我仍然需要实现的功能:
- 在创建新容器、组和用户时,使用反斜杠对 ID 中的特殊字符进行编码。
RPC SCA(对称加密算法)
再次,Microsoft .NET 使加密的使用变得容易,但同样,我希望有一个类提供基础功能。
// Encrypt a string.
String str = "My readable text";
RpcSCA sca = RpcSCA.TrippleDES();
sca.PrivateKey = "Password";
str = sca.Encrypt(str);
RPC Triple
曾经想要一个布尔的三种状态?那么,Triple
类就是这样。我考虑过使用 CheckState
类,但最终写了自己的类,并有很多运算符方法。
Triple t1 = true;
Triple t2 = Triple.Unknown;
if (t1 == false) { ... }
if (t2.IsUnknown == true) { ... }
信不信由你,它有时确实很有用。
历史
日期 | 注释 |
11-08-2009 | RPC 数据库:已向文章添加代码。RPC 目录:添加了查找邮箱存储的代码,用于为用户或组启用邮箱。LiQuick 的这篇 文章 向我展示了如何实现它。 |
09-08-2009 | 我的部分 RPC Plumming 代码首次公开发布。 |