如何:开发实例控制提供程序
以下过程提供了创建自定义实例控制提供程序的步骤。
创建一个自定义库项目。
添加一个对 Microsoft.ApplicationServer.StoreManagement 的引用。此外,还要添加一个对 System.Configuration 程序集的引用以编译本主题中的示例代码。
在源文件开头添加以下语句。
using Microsoft.ApplicationServer.StoreManagement.Control; using Microsoft.ApplicationServer.StoreManagement.Control; using System.Data.SqlClient; using System.Collections.Specialized; using System.Threading; using System.Data;
为从 InstanceControlProvider 类派生的实例控制提供程序创建一个类。
public class MySqlInstanceControlProvider : InstanceControlProvider { }
实现 Initialize 方法。此方法将接受一个与配置文件中指定的配置信息对应的属性包。属性包中的数据用于构造提供程序。先调用 Initialize 方法,然后再调用 CreateInstanceControl 或 UniqueProviderIdentifier 方法。
备注
在远程方案中,名称值集合中应包含一个名称为“EnableServiceModelMetadata”的项。提供程序可以选择在调用 base.Initialize 方法前忽略和删除此参数。此属性通常用于确定是否调用 Microsoft.Web.Administration.ServerManager 对象上的 SetMetadata(“ServiceModel”, true)。
string ConnectionString { get; set; } public override void Initialize(string name, NameValueCollection config) { this.ConnectionString = config["connectionString"]; // Initialize the base class base.Initialize(name, config); }
实现 InstanceControlProvider 类的 CreateInstanceControl 方法以返回一个自定义的 InstanceControl 对象,客户端将使用该对象来访问 CommandSend 对象或 CommandReceive 对象。
public override InstanceControl CreateInstanceControl() { SqlConnectionStringBuilder connectionStringBuilder = new SqlConnectionStringBuilder(this.ConnectionString); connectionStringBuilder.AsynchronousProcessing = true; return new MySqlInstanceControl(connectionStringBuilder.ConnectionString); }
备注
请参阅下一节了解 MySqlInstanceControl 类型的实现。
实现 UniqueProviderIdentifier 方法。此方法返回的唯一提供程序 ID 用于确定是否不同的提供程序对象解析到相同的基础存储。
string UniqueStoreIdentifier { get; set; } public override string UniqueProviderIdentifier() { this.UniqueStoreIdentifier = GetUniqueStoreIdentifier(this.ConnectionString); return this.UniqueStoreIdentifier; } private string GetUniqueStoreIdentifier(string connectionString) { using (SqlConnection connection = new SqlConnection(connectionString)) { using (SqlCommand command = new SqlCommand()) { command.CommandType = System.Data.CommandType.Text; command.CommandText = "SELECT TOP (1) [StoreIdentifier] FROM [Microsoft.ApplicationServer.DurableInstancing].[StoreVersion]"; command.Connection = connection; command.Connection.Open(); Guid identifier = (Guid)command.ExecuteScalar(); return identifier.ToString(); } } }
实现 InstanceControl
以下过程提供了创建自定义 InstanceControl 类型的步骤。
创建一个从 InstanceControl 类派生的类。
public class MySqlInstanceControl : InstanceControl { readonly string connectionString; public MySqlInstanceControl(string connectionString) { this.connectionString = connectionString; } }
实现 CommandReceive 属性。CommandReceive 属性的 Get 取值函数方法应该返回一个 CommandReceive 对象。客户端将调用此对象上的方法以异步接收来自命令队列的命令。
MySqlCommandReceive commandReceive; public override CommandReceive CommandReceive { get { if (this.commandReceive == null) { MySqlCommandReceive tmp = new MySqlCommandReceive(this.connectionString); Interlocked.CompareExchange(ref this.commandReceive, tmp, null); } return this.commandReceive; } }
实现 CommandSend 属性并从 Get 取值函数方法返回一个自定义的 CommandSend 对象。CommandSend 属性的 Get 方法应该返回一个 CommandSend 对象。客户端将调用此对象的方法以异步方式将命令发送到命令队列。
MySqlCommandSend commandSend; public override CommandSend CommandSend { get { if (this.commandSend == null) { MySqlCommandSend tmp = new MySqlCommandSend(this.connectionString); Interlocked.CompareExchange(ref this.commandSend, tmp, null); return this.commandSend; } return this.CommandSend; } }
客户端使用这两个对象将命令发送到命令队列(排队)并从命令队列接收命令(取消排队)。例如,一个实例控制 cmdlet 使用 CommandSend 对象将命令添加到命令队列中,而 Workflow Management Service (WMS) 使用 CommandReceive 对象将命令从命令队列中删除。在某些环境中,例如,当执行了 Remove-ASAppServiceInstance cmdlet 时,存储自身将会处理该命令以从实例存储中删除该实例。
备注
请参阅以下关于实现 MySqlCommandSend 和 MySqlCommandReceive 类型的部分内容。
实现 CommandSend
创建一个自定义 CommandSend 类型:
创建一个从 CommandSend 类派生的类并实现 BeginTrySend 和 EndTrySend 方法。
public class MySqlCommandSend : CommandSend { readonly string connectionString; public MySqlCommandSend(string connectionString) { this.connectionString = connectionString; } public override IAsyncResult BeginSend(InstanceCommand command, TimeSpan timeout, AsyncCallback callback, object state) { throw new NotImplementedException(); } public override void EndSend(IAsyncResult result) { throw new NotImplementedException(); } }
实现 CommandReceive
创建一个自定义 CommandReceive 类的步骤:
创建一个从 CommandReceive 类派生的类并实现 BeginTryReceive 和 EndTryReceive 方法。
public class MySqlCommandReceive : CommandReceive { readonly string connectionString; Queue<MySqlReceivedInstanceCommand> receivedInstanceCommands; public MySqlCommandReceive(string connectionString) { this.connectionString = connectionString; this.receivedInstanceCommands = new Queue<MySqlReceivedInstanceCommand>(); } public override IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state) { throw new NotImplementedException(); } public override bool EndTryReceive(IAsyncResult result, out ReceivedInstanceCommand command) { throw new NotImplementedException(); } }
备注
关于实现 MySqlReceivedInstanceCommand 类的信息,请参阅以下部分。
实现 ReceivedInstanceCommand
创建一个自定义 ReceivedInstanceCommand 类型的步骤:
创建一个从 ReceivedInstanceCommand 类派生的类并实现 InstanceCommandContext 属性。
class MySqlReceivedInstanceCommand : ReceivedInstanceCommand { long commandId; MySqlCommandReceive receiver; MySqlInstanceCommandContext context; internal MySqlReceivedInstanceCommand(long commandId, Guid instanceId, Microsoft.ApplicationServer.StoreManagement.Control.CommandType commandType, IDictionary<string, string> serviceIdentifier, TimeSpan timeout, MySqlCommandReceive receiver) : base() { this.commandId = commandId; base.CommandType = commandType; base.InstanceId = instanceId; base.ServiceIdentifier = serviceIdentifier; //this.CommandTimeout = new TimeoutHelper(timeout, true); this.receiver = receiver; this.context = new MySqlInstanceCommandContext(this); } public override InstanceCommandContext InstanceCommandContext { get { return this.context; } } }
备注
关于实现 MySqlInstanceCommandContext 类型的信息,请参阅以下部分。
实现 InstanceCommandContext
创建一个自定义 InstanceCommandContext 类型的步骤:
创建一个从 InstanceCommandContext 类派生的类并实现 BeginComplete、EndCompleteBeginAbandon 和 EndAbandon 方法。
客户端将调用 InstanceCommandContext 对象上的 BeginComplete 方法,以通知命令执行成功。然后,控制提供程序将从命令队列中删除该命令。如果命令执行成功,WMS 将调用此方法。
客户端将调用 InstanceCommandContext 对象上的 BeginAbandon 方法,以通知命令执行失败。如何处理该命令由实例控制提供程序来决定。例如,控制提供程序可能会在从命令队列中删除该命令前重试此命令几次。如果此命令执行失败,WMS 将调用此方法。
class MySqlInstanceCommandContext : InstanceCommandContext { MySqlReceivedInstanceCommand command; internal MySqlInstanceCommandContext(MySqlReceivedInstanceCommand command) { this.command = command; } public override IAsyncResult BeginAbandon(Exception exception, TimeSpan timeout, AsyncCallback callback, object state) { throw new NotImplementedException(); } public override IAsyncResult BeginComplete(TimeSpan timeout, AsyncCallback callback, object state) { throw new NotImplementedException(); } public override void EndAbandon(IAsyncResult result) { throw new NotImplementedException(); } public override void EndComplete(IAsyncResult result) { throw new NotImplementedException(); } }
另请参阅
概念
如何:开发实例存储提供程序
如何:部署实例查询提供程序
如何:配置实例存储、查询和控制提供程序
实例存储、查询和控制提供程序
2011-12-05