如何:开发实例控制提供程序

以下过程提供了创建自定义实例控制提供程序的步骤。

  1. 创建一个自定义库项目。

  2. 添加一个对 Microsoft.ApplicationServer.StoreManagement 的引用。此外,还要添加一个对 System.Configuration 程序集的引用以编译本主题中的示例代码。

  3. 在源文件开头添加以下语句。

    using Microsoft.ApplicationServer.StoreManagement.Control;
    using Microsoft.ApplicationServer.StoreManagement.Control;
    using System.Data.SqlClient;
    using System.Collections.Specialized;
    using System.Threading;
    using System.Data;
    
  4. 为从 InstanceControlProvider 类派生的实例控制提供程序创建一个类。

        public class MySqlInstanceControlProvider : InstanceControlProvider
        {
        }
    
  5. 实现 Initialize 方法。此方法将接受一个与配置文件中指定的配置信息对应的属性包。属性包中的数据用于构造提供程序。先调用 Initialize 方法,然后再调用 CreateInstanceControlUniqueProviderIdentifier 方法。

    备注

    在远程方案中,名称值集合中应包含一个名称为“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);
            }
    
  6. 实现 InstanceControlProvider 类的 CreateInstanceControl 方法以返回一个自定义的 InstanceControl 对象,客户端将使用该对象来访问 CommandSend 对象或 CommandReceive 对象。

            public override InstanceControl CreateInstanceControl()
            {
                SqlConnectionStringBuilder connectionStringBuilder = new SqlConnectionStringBuilder(this.ConnectionString);
                connectionStringBuilder.AsynchronousProcessing = true;
                return new MySqlInstanceControl(connectionStringBuilder.ConnectionString);
            }
    

    备注

    请参阅下一节了解 MySqlInstanceControl 类型的实现。

  7. 实现 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 类型的步骤。

  1. 创建一个从 InstanceControl 类派生的类。

        public class MySqlInstanceControl : InstanceControl
        {
            readonly string connectionString;
             public MySqlInstanceControl(string connectionString)
             {
                 this.connectionString = connectionString;
             }
        }
    
  2. 实现 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;
                }
            }
    
  3. 实现 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 时,存储自身将会处理该命令以从实例存储中删除该实例。

    备注

    请参阅以下关于实现 MySqlCommandSendMySqlCommandReceive 类型的部分内容。

实现 CommandSend

创建一个自定义 CommandSend 类型:

  • 创建一个从 CommandSend 类派生的类并实现 BeginTrySendEndTrySend 方法。

        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 类派生的类并实现 BeginTryReceiveEndTryReceive 方法。

        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 类派生的类并实现 BeginCompleteEndCompleteBeginAbandonEndAbandon 方法。

    客户端将调用 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