本主题介绍如何实现支持嵌套容器(多级数据存储)、移动项和相对路径的 Windows PowerShell 提供程序的方法。 导航提供程序必须派生自 System.Management.Automation.Provider.NavigationCmdletProvider 类。
本主题示例中的提供程序使用 Access 数据库作为其数据存储。 有几个帮助程序方法和类用于与数据库交互。 有关包含帮助程序方法的完整示例,请参阅 AccessDBProviderSample05。
有关 Windows PowerShell 提供程序的详细信息,请参阅 Windows PowerShell 提供程序概述。
实现导航方法
System.Management.Automation.Provider.NavigationCmdletProvider 类实现支持嵌套容器、相对路径和移动项的方法。 有关这些方法的完整列表,请参阅 NavigationCmdletProvider 方法。
注释
本主题基于 Windows PowerShell 提供程序快速入门中的信息。 本主题不介绍如何设置提供程序项目的基础知识,或者如何实现从创建和删除驱动器的 System.Management.Automation.Provider.DriveCmdletProvider 类继承的方法。 本主题也不介绍如何实现由 System.Management.Automation.Provider.ItemCmdletProvider 或 System.Management.Automation.Provider.ContainerCmdletProvider 类公开的方法。 有关如何实现项 cmdlet 的示例,请参阅 编写项提供程序。 有关如何实现容器 cmdlet 的示例,请参阅 编写容器提供程序。
声明提供程序类
声明提供程序以派生自 System.Management.Automation.Provider.NavigationCmdletProvider 类,并使用 System.Management.Automation.Provider.CmdletProviderAttribute对其进行修饰。
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : NavigationCmdletProvider
{
}
实现 IsItemContainer
System.Management.Automation.Provider.NavigationCmdletProvider.IsItemContainer* 方法检查指定路径中的项是否为容器。
protected override bool IsItemContainer(string path)
{
if (PathIsDrive(path))
{
return true;
}
string[] pathChunks = ChunkPath(path);
string tableName;
int rowNumber;
PathType type = GetNamesFromPath(path, out tableName, out rowNumber);
if (type == PathType.Table)
{
foreach (DatabaseTableInfo ti in GetTables())
{
if (string.Equals(ti.Name, tableName, StringComparison.OrdinalIgnoreCase))
{
return true;
}
} // foreach (DatabaseTableInfo...
} // if (pathChunks...
return false;
}
实现 GetChildName
System.Management.Automation.Provider.NavigationCmdletProvider.GetChildName* 方法获取指定路径上子项的名称属性。 如果指定路径上的项不是容器的子级,则此方法应返回路径。
protected override string GetChildName(string path)
{
if (PathIsDrive(path))
{
return path;
}
string tableName;
int rowNumber;
PathType type = GetNamesFromPath(path, out tableName, out rowNumber);
if (type == PathType.Table)
{
return tableName;
}
else if (type == PathType.Row)
{
return rowNumber.ToString(CultureInfo.CurrentCulture);
}
else
{
ThrowTerminatingInvalidPathException(path);
}
return null;
}
实现 GetParentPath
System.Management.Automation.Provider.NavigationCmdletProvider.GetParentPath* 方法获取指定路径处项的父级的路径。 如果指定路径中的项是数据存储的根目录(因此没有父项),则此方法应返回根路径。
protected override string GetParentPath(string path, string root)
{
// If root is specified then the path has to contain
// the root. If not nothing should be returned
if (!String.IsNullOrEmpty(root))
{
if (!path.Contains(root))
{
return null;
}
}
return path.Substring(0, path.LastIndexOf(pathSeparator, StringComparison.OrdinalIgnoreCase));
}
实现 MakePath
System.Management.Automation.Provider.NavigationCmdletProvider.MakePath* 方法联接指定的父路径和指定子路径来创建提供程序内部路径(有关提供程序可支持的路径类型的信息,请参阅 Windows PowerShell 提供程序概述。 当用户调用 Microsoft.PowerShell.Commands.JoinPathCommand cmdlet 时,PowerShell 引擎将调用此方法。
protected override string MakePath(string parent, string child)
{
string result;
string normalParent = NormalizePath(parent);
normalParent = RemoveDriveFromPath(normalParent);
string normalChild = NormalizePath(child);
normalChild = RemoveDriveFromPath(normalChild);
if (String.IsNullOrEmpty(normalParent) && String.IsNullOrEmpty(normalChild))
{
result = String.Empty;
}
else if (String.IsNullOrEmpty(normalParent) && !String.IsNullOrEmpty(normalChild))
{
result = normalChild;
}
else if (!String.IsNullOrEmpty(normalParent) && String.IsNullOrEmpty(normalChild))
{
if (normalParent.EndsWith(pathSeparator, StringComparison.OrdinalIgnoreCase))
{
result = normalParent;
}
else
{
result = normalParent + pathSeparator;
}
} // else if (!String...
else
{
if (!normalParent.Equals(String.Empty) &&
!normalParent.EndsWith(pathSeparator, StringComparison.OrdinalIgnoreCase))
{
result = normalParent + pathSeparator;
}
else
{
result = normalParent;
}
if (normalChild.StartsWith(pathSeparator, StringComparison.OrdinalIgnoreCase))
{
result += normalChild.Substring(1);
}
else
{
result += normalChild;
}
} // else
return result;
}
实现 NormalizeRelativePath
System.Management.Automation.Provider.NavigationCmdletProvider.NormalizeRelativePath* 方法采用 path 和 basepath 参数,并返回与 path 参数和相对于 basepath 参数等效的规范化路径。
protected override string NormalizeRelativePath(string path,
string basepath)
{
// Normalize the paths first
string normalPath = NormalizePath(path);
normalPath = RemoveDriveFromPath(normalPath);
string normalBasePath = NormalizePath(basepath);
normalBasePath = RemoveDriveFromPath(normalBasePath);
if (String.IsNullOrEmpty(normalBasePath))
{
return normalPath;
}
else
{
if (!normalPath.Contains(normalBasePath))
{
return null;
}
return normalPath.Substring(normalBasePath.Length + pathSeparator.Length);
}
}
实现 MoveItem
System.Management.Automation.Provider.NavigationCmdletProvider.MoveItem* 方法将项从指定路径移动到指定的目标路径。 当用户调用 Microsoft.PowerShell.Commands.MoveItemCommand cmdlet 时,PowerShell 引擎将调用此方法。
protected override void MoveItem(string path, string destination)
{
// Get type, table name and rowNumber from the path
string tableName, destTableName;
int rowNumber, destRowNumber;
PathType type = GetNamesFromPath(path, out tableName, out rowNumber);
PathType destType = GetNamesFromPath(destination, out destTableName,
out destRowNumber);
if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}
if (destType == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(destination);
}
if (type == PathType.Table)
{
ArgumentException e = new ArgumentException("Move not supported for tables");
WriteError(new ErrorRecord(e, "MoveNotSupported",
ErrorCategory.InvalidArgument, path));
throw e;
}
else
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}
DataSet ds = GetDataSetForTable(da, tableName);
DataTable table = GetDataTable(ds, tableName);
OdbcDataAdapter dda = GetAdapterForTable(destTableName);
if (dda == null)
{
return;
}
DataSet dds = GetDataSetForTable(dda, destTableName);
DataTable destTable = GetDataTable(dds, destTableName);
DataRow row = table.Rows[rowNumber];
if (destType == PathType.Table)
{
DataRow destRow = destTable.NewRow();
destRow.ItemArray = row.ItemArray;
}
else
{
DataRow destRow = destTable.Rows[destRowNumber];
destRow.ItemArray = row.ItemArray;
}
// Update the changes
if (ShouldProcess(path, "MoveItem"))
{
WriteItemObject(row, path, false);
dda.Update(dds, destTableName);
}
}
}