zoukankan      html  css  js  c++  java
  • 【SQL Server学习笔记】Service Broker创建异步的、数据驱动的消息应用程序

    Service Broker 可以创建异步的、数据驱动的消息应用程序,它允许一个数据库发送消息到其他数据库,而不需要等待响应,即使远程数据库不能立即处理这些消息,发送数据库也可以继续其他操作。通过使用T-SQL对象和命令,就可以完成管理Service Broker。

    Service Broker 为SQL Server提供消息队列,这样就可以从数据库中发送异步事务性消息到队列,在队列中这些消息将会被其他服务获取和处理,该服务可能运行在其他数据库、或服务器上。另外,对于异步程序,发送一条消息,并且应用程序不需要等待原始消息已被接收、或处理的确认信息,就可以处理其他相关的任务。一旦完成特定任务,两个Service Broker 服务之间的会话就可以显式的结束。

    Service Broker包含了一些开箱即用的特性,它处理当试图创建自己的异步消息系统时,可能经常遇到的复杂问题。

    比如:

    首先,Service Broker 消息要保证以适当的顺序,或者以他们发送的原始顺序进行接收,而且这些消息也只能被接收一次(调度程序保证不会重复的读取),并且可以作为同一个会话的一部分发送,与任务的同一个实例相关;

    其次,Service Broker 保证了消息的发送,当尝试发送第一个消息时,目标数据库(消息的接收者)不可用,消息将加入到发送方的数据库的队列中,当目标数据库变为可用时,发送者将会尝试发送这个消息;

    再次,由于Service Broker 是内建在SQL Server数据库中的,可以与数据库的其余部分仪器备份,所以这些消息在数据库发生故障的情况下也是可以恢复的;

    最后使用Service Broker 的事件通知功能,可以跟踪数据库和SQL Server实例的事件,这个与SQL Trace相似,但事件通知是异步的,并且对SQL Server实例整体的性能的影响最小,而SQL Trace对性能的影响较大。

    use master
    go
    
    if not exists(select 1 from sys.databases where name = 'BOOKSTORE')
    	CREATE DATABASE bookstore
    go
    
    
    if not exists(select 1 from sys.databases where name = 'bookDistribution')
    	CREATE DATABASE bookDistribution
    go
    
    
    --1.启动Service broker
    alter database bookstore set enable_broker   --disable_broker可以禁用
    
    alter database bookstore set trustworthy on  --指明SQL Server实例是否信任该数据库以及其中的内容
    
    alter database bookDistribution set enable_broker
    
    alter database bookDistribution set trustworthy on
    
    
    --2.创建数据库主密钥
    use bookstore
    go
    
    create master key
    encryption by password = '123abc'
    
    use bookDistribution
    go
    
    create master key
    encryption by password = 'abc123'
    
    
    
    --3.创建消息类型,定义了从Service Broker端点发送的消息中包含的数据类型
    use bookstore
    go
    
    create message type [//SackConsulting/SendBookOrder]
    validation = WELL_FORMED_XML
    go
    
    create message type [//SackConsulting/BookOrderReceived]
    validation = WELL_FORMED_XML
    
    
    
    use bookDistribution
    go
    
    
    create message type [//SackConsulting/SendBookOrder]
    validation = well_formed_xml
    go
    
    create message type [//SackConsulting/BookOrderReceived]
    validation = well_formed_xml
    go
    
    
    --4.创建约定,定义了在任务级别可以发送或者接收的消息类型
    use bookstore
    go
    
    create contract [//SackConsulting/BookOrderContract]
    (
    	[//SackConsulting/SendBookOrder] sent by initiator,  --可以由会话的发起方发送的消息类型
    	[//SackConsulting/BookOrderReceived] sent by target  --可以由会话的目标方发送的消息类型
    )
    
    
    use bookDistribution
    go
    
    create contract [//SackConsulting/BookOrderContract]
    (
    	[//SackConsulting/SendBookOrder] sent by initiator,
    	[//SackConsulting/BookOrderReceived] sent by target 
    )
    go
    
    
    --5.创建队列,队列用来保存数据
    --通过select语句来查询队列,或者用receive命令从队列检索一条、多条消息
    --检索程序可以是外部的.net程序,不过通过存储过程来实现更方便
    use bookstore
    go
    
    create queue bookStoreQueue
    with status = on 
    go
    
    
    --在创建queue时可以把自动处理消息的程序,绑定到队列的激活选项,
    --此处通过手动控制队列中的信息交换
    use bookDistribution
    go
    
    create queue bookStoreDistributionQueue
    with status = on 
    go
    
    
    
    --6.创建服务这样就可以把消息队列绑定到一个或者多个约定上
    --服务使用队列和约定来定义一个或一组任务
    --服务是消息的发起方和接收方强制约定的规则,并将消息路由到正确的队列
    use bookstore
    go
    
    create service [//SackConsulting/BookOrderService]
    on queue dbo.bookStoreQueue ([//SackConsulting/BookOrderContract])
    
    
    use bookDistribution
    go
    
    create service [//SackConsulting/BookStoreDistributionService]
    on queue dbo.bookStoreDistributionQueue ([//SackConsulting/BookOrderContract])
    
    
    
    
    --7.1开始会话,发送消息
    use bookstore
    go
    
    declare @conversation_handler uniqueidentifier;
    declare @order_msg xml;
    
    
    begin dialog conversation @conversation_handler
    from service [//SackConsulting/BookOrderService]
    to service '//SackConsulting/BookStoreDistributionService'
    on contract [//SackConsulting/BookOrderContract];
    
    
    set @order_msg = 
    	'<order id="1234" customer="22" orderdate="2012-10-01">
    	<LineItem ItemNumber="1" ISBN="1-12345-123-0" Quantity="1" />
    	</order>
    	';
    
    --send语句可以发送消息	
    send on conversation @conversation_handler
    message type [//SackConsulting/SendBookOrder]
    (@order_msg);
    
    
    --7.2.1检索消息
    use bookDistribution
    go
    
    select message_type_name,      --消息类型名
           CAST(message_body as xml) as message,  --消息
           queuing_order,                         --队列顺序,从0开始
           
           conversation_handle,                   --会话句柄
           conversation_group_id                  --会话组id
    from dbo.bookstoreDistributionQueue
    
    
    
    create table dbo.bookOrderReceived
    (
    	bookOrderReceivedID int identity(1,1) not null,
    	conversation_handle uniqueidentifier not null,
    	conversation_group_id uniqueidentifier not null,
    	message_body xml not null
    )
    
    
    --7.2.2receive语句会从队列中读取消息,并且把已经读取的消息删除
    declare @conversation_handler uniqueidentifier
    declare @conversation_group uniqueidentifier
    
    declare @order_msg xml
    
    declare @Text_response_msg varchar(max)
    declare @response_msg xml
    
    declare @orderID int;
    
    
    receive top(1)
    	@order_msg = message_body,
    	@conversation_handler = conversation_handle,
    	@conversation_group = conversation_group_id
    from dbo.bookStoreDistributionQueue;
    
    
    insert into dbo.bookOrderReceived
    (conversation_handle,conversation_group_id,message_body)
    values(@conversation_handler,
           @conversation_group,
           @order_msg)
    
    
    select @orderID = @order_msg.value('(/order/@id)[1]','int')
    
    select @Text_response_msg = 
    	'<orderreceived id="' + CAST(@orderID as varchar(10)) + '"/>'
    
    select @response_msg = CAST(@Text_response_msg as xml);
    
    --7.2.3发送回复消息
    send on conversation @conversation_handler
    message type [//SackConsulting/BookOrderReceived]
    (@response_msg);
    
    
    
    --7.3查看返回的消息,结束会话
    use bookstore
    go
    
    
    create table dbo.bookOrderConfirmation
    (
    	bookorderconfirmationID int identity(1,1) not null,
    	conversation_handle uniqueidentifier not null,
    	datereceived datetime not null default getdate(),
    	message_body xml not null
    )
    
    
    declare @conversation_handler uniqueidentifier
    declare @conversation_group uniqueidentifier
    
    declare @order_msg xml
    declare @text_response_msg varcahr(max);
    
    
    receive top(1)
    	@conversation_handler = conversation_handle,
    	@order_msg = message_body
    from dbo.bookstorequeue
    
    
    insert into dbo.bookOrderConfirmation
    (conversation_handle,message_body)
    values(@conversation_handler,@order_msg)
    
    
    end conversation @conversation_handler;  --结束会话
    
    
    
    --7.4取出消息,判断是否是结束会话消息类型,如果是,那么结束会话
    use bookDistribution
    go
    
    
    declare @conversation_handler uniqueidentifier
    declare @conversation_group uniqueidentifier
    
    declare @order_msg xml
    
    declare @message_type_name nvarchar(256);
    
    
    receive top(1)
    	@conversation_handler =  conversation_handle,
    	@order_msg = message_body,
    	@message_type_name = message_type_name
    from dbo.bookstoredistributionqueue
    
    /*======================================================
    结束会话会自动发送:
    http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog
    的消息类型到目标数据库,双方,包括发起方和目标,必须都结束会话
    
    ========================================================*/
    if @message_type_name = 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
    begin
    	end conversation @conversation_handler;
    end
    
    
    --7.5查看会话端点的状态
    select *
    from sys.conversation_endpoints
    
    
    
    
    --8.1设定Serivce Broker会话的优先级
    ALTER DATABASE BOOKSTORE
    set honor_broker_priority on
    
    alter database bookdistribution
    set honor_broker_priority on
    
    
    --8.2查看数据库的属性
    select name,
           is_honor_broker_priority_on
    from sys.databases
    where name in ('bookstore','bookdistribution')
    
    
    --8.3创建Service Broker优先级
    use bookstore
    go
    
    create broker priority conversation_priority_bookordercontract_bookorderservice
    for conversation
    set (
    		contract_name = [//SackConsulting/BookOrderContract],
    		local_service_name = [//SackConsulting/BookOrderService],
    		remote_service_name = any,
    		priority_level = 10
    	)
    
    select cp.name,
           cp.priority,             --优先级
           
           cp.service_contract_id,
           sc.name,                 --约定名称
           
           cp.local_service_id,
           s.name,                  --服务名称       cp.remote_service_name
           
    from sys.conversation_priorities cp
    
    inner join sys.service_contracts sc
            on cp.service_contract_id = sc.service_contract_id
            
    inner join sys.services s
            on s.service_id = cp.local_service_id
    
    
    use bookDistribution
    go
    
    create broker priority conversation_priority_bookordercontract_bookstoredistributionservice
    for conversation
    set
    	(
    		contract_name = [//SackConsulting/BookOrderContract],
    		local_service_name = [//SackConsulting/BookStoreDistributionService],
    		remote_service_name = any,
    		priority_level = 10
    	)
    
    select cp.name,
           cp.priority,             --优先级
           
           cp.service_contract_id,
           sc.name,                 --约定名称
           
           cp.local_service_id,
           s.name,                  --服务名称
           cp.remote_service_name       
    from sys.conversation_priorities cp
    inner join sys.service_contracts sc
            on cp.service_contract_id = sc.service_contract_id
            
    inner join sys.services s
            on s.service_id = cp.local_service_id
    	
    
    
    --8.4修改优先级
    use bookstore
    go
    
    alter broker priority conversation_priority_bookordercontract_bookorderservice
    for conversation
    set
    	(
    		remote_service_name = '//SackConsulting/BookStoreDistributionService'
    	)
    
    
    use bookDistribution
    go
    
    alter broker priority conversation_priority_bookordercontract_bookstoredistributionservice
    for conversation
    set
    	(
    		priority_level = 9
    	)
    	
    
    --8.5删除优先级
    drop broker priority conversation_priority_bookordercontract_bookstoredistributionservice


     创建处理消息的存储过程

    前面使用了临时的T-SQL来处理从队列传入的消息,也可以通过存储过程或外部应用程序创建服务程序,来自动的激活并处理队列中的消息的服务程序,同时还可以指定同时执行的服务程序的数量。

    use bookDistribution
    go
    
    create procedure dbo.usp_service_broker_ReceiveOrders
    as
    
    declare @conversation_handler uniqueidentifier
    declare @conversation_group uniqueidentifier
    declare @order_msg xml
    declare @text_response_msg varchar(8000)
    
    declare @response_msg xml
    declare @message_type_name nvarchar(156)
    declare @orderID int
    
    --当发生运行时错误时,会自动回滚事务
    set xact_abort on
    
    
    begin tran;
    	
    	--接收消息
    	receive top(1) 
    		@order_msg = message_body,
    	    @conversation_handler = conversation_handle,
    	    @conversation_group = conversation_group_id,
    	    @message_type_name = message_type_name
    	from dbo.bookStoreDistributionQueue
    	
    	--消息类型
    	if @message_type_name = '//SackConsulting/SendBookOrder'
    	begin
    		insert into dbo.bookOrderReceived
    		(conversation_handle,conversation_group_id,message_body)
    		values(@conversation_handler,
    		       @conversation_group,
    		       @order_msg)
    		       
    		select @orderID = @order_msg.value('(/order/@id)[1]','int')
    		
    		select @text_response_msg = '<orderreceived id="' + 
    		                             CAST(@orderID as varchar(10)) +
    		                             '"/>';
    		
    		select @response_msg = CAST(@text_response_msg as XML);
    		
    		send on conversation @conversation_handler
    		message type [//SackConsulting/BookOrderReceived]
    		(@response_msg);
    	end
    	
    	--如果收到结束会话的消息
    	if @message_type_name = 
    	       'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
        begin	
    		end conversation @conversation_handler;
    	end
    	
    commit tran
    
    go
    					
    
    --修改队列设置
    alter queue dbo.BookstoreDistributionQueue
    with activation 
    (
    	status = on,
    	procedure_name = dbo.usp_service_broker_receiveOrders,
    	max_queue_readers = 2,   --存储过程执行的最大数量
    	execute as self
    )	
    
    
    /*==========================================
    通过drop:删除与队列关联的所有激活信息
    
    alter queue dbo.BookstoreDistributionQueue
    with activation 
    (
    	drop
    )	
    ============================================*/   
    
    use bookstore
    go
    
    declare @conversation_handler uniqueidentifier
    
    declare @order_msg xml
    
    
    begin dialog conversation @conversation_handler
    from service [//SackConsulting/BookOrderService]
    to service '//SackConsulting/BookStoreDistributionService'
    on contract [//SackConsulting/BookOrderContract];
    
    
    set @order_msg = 
    	'<order id="1234" customer="22" orderdate="2012-10-01">
    	<LineItem ItemNumber="1" ISBN="1-12345-123-0" Quantity="1" />
    	</order>
    	';
    
    --send语句可以发送消息	
    send on conversation @conversation_handler
    message type [//SackConsulting/SendBookOrder]
    (@order_msg);
    
    
    --可以接收到一个消息,这个消息是对方在接受到下消息后,激活存储过程后,由存储过程回复的消息
    select conversation_handle,
           CAST(message_body as xml)
    from dbo.bookStoreQueue     
       


     实现远程服务器的Service Broker

    前面的例子是同一个SQL Server实例的两个数据库,但大部分情况会将Service Broker设置为,使用在两个或多个SQL Server实例上的数据库。为了实现跨越服务器通信,可以通过Windows身份验证或基于证书的身份验证,启用传输安全模式、启用对话安全模式、创建路由、创建远程绑定。

    --在实例1上
    use master
    go
    
    if exists(select 1 from sys.databases where name = 'bookstore')
    	drop database bookstore
    else
    	create database bookstore
    go
    
    
    alter database bookstore set enable_broker
    
    alter database bookstore set trustworthy on
    
    
    use bookstore
    go
    
    create message type [//BookConsulting/SendBookOrder]
    validation = well_formed_xml
    go
    
    create message type [//BookConsulting/BookOrderReceived]
    validation = well_formed_xml
    go
    
    
    create contract [//BookConsulting/BookOrderContract]
    (
    	[//BookConsulting/SendBookOrder] sent by initiator,
    	[//BookConsulting/BookOrderReceived] sent by target
    )
    go
    
    
    
    create queue BookStoreQueue
    with status = on
    
    
    create service [//BookConsulting/BookOrderService]
    on queue dbo.BookStoreQueue
    (
    	[//BookConsulting/BookOrderContract]
    )
    
    
    
    --在实例2上
    use master
    go
    
    if exists(select 1 from sys.databases where name = 'bookdistribution')
    	drop database bookdistribution
    else
    	create database bookdistribution
    go
    
    
    alter database bookdistribution set enable_broker
    
    alter database bookdistribution set trustworthy on
    
    
    use bookdistribution
    go
    
    create message type [//BookConsulting/SendBookOrder]
    validation = well_formed_xml
    go
    
    create message type [//BookConsulting/BookOrderReceived]
    validation = well_formed_xml
    go
    
    
    create contract [//BookConsulting/BookOrderContract]
    (
    	[//BookConsulting/SendBookOrder] sent by initiator,
    	[//BookConsulting/BookOrderReceived] sent by target
    )
    go
    
    
    
    create queue BookDistributionQueue
    with status = on
    
    
    create service [//BookConsulting/BookDistributionService]
    on queue dbo.BookDistributionQueue
    (
    	[//BookConsulting/BookOrderContract]
    )
    
    
    
    
    --启用传输安全模式,只是限制其他实例是否能访问本地服务器的端点
    
    --实例1
    
    use master 
    go
    
    
    --1.删除已经存在的数据库主密钥
    drop master key
    
    
    --2.创建数据库主密钥
    create master key encryption by password = '123456!@#'
    
    
    --3.创建证书
    create certificate bookMasterCert
    with subject = 'book Transport Security Service Broker',
    	 expiry_date = '2012-12-31' 
    
    
    --4.备份证书
    backup certificate bookMasterCert
    to file = 'c:\bookMasterCert.cer'
    go
    
    
    --5.创建端点
    create endpoint service_broker_book_endpoint
    state = started
    as tcp (listener_port = 4020)
    for service_broker (
    						authentication = certificate bookMasterCert,
    						encryption = required
                       )
    
    
    --6.创建SQL Server的登录名
    create login service_broker_login
    with password = 'service_broker_login123'
    
    
    --7.创建数据库用户名
    create user service_broker_user
    for login service_broker_login
    
    
    --8.授予数据库用户可以连接端点
    grant connect on endpoint::service_broker_book_endpoint 
                  to service_broker_login
    
    
    --9.通过另一个实例复制到本地服务器上的证书文件,来创建证书
    create certificate bookDistributionMasterCert
    authorization service_broker_user
    from file = 'c:\bookDistributionMasterCert.cer'
    go
    
    
    
    
    --实例2
    
    use master 
    go
    
    
    --删除数据库主密钥
    drop master key
    
    create master key encryption by password = '123456&^%'
    
    
    create certificate bookDistributionMasterCert
    with subject = 'bookDistribution Transport Security Service Broker',
    	 expiry_date = '2012-12-31' 
    
    
    backup certificate bookDistributionMasterCert
    to file = 'c:\bookDistributionMasterCert.cer'
    
    
    create endpoint service_broker_bookdistribution_endpoint
    state = started
    as tcp (listener_port = 4021)
    for service_broker (
    						authentication = certificate bookDistributionMasterCert,
    						encryption = required
                       )
    
    
    create login service_broker_login
    with password = 'service_broker_login123'
    
    
    create user service_broker_user
    for login service_broker_login
    
    
    grant connect on endpoint::service_broker_bookdistribution_endpoint 
                  to service_broker_login
    
    
    create certificate bookMasterCert
    authorization service_broker_user
    from file = 'c:\bookMasterCert.cer'
    go
    
    
    
    
    --启用对话安全模式
    --实例1
    use bookstore
    go
    
    --1.创建数据库主密钥
    create master key encryption by password = '123456!@#'  
    
    
    --2.创建证书,这里可以给当前数据库用户创建多个证书,不会有影响
    --当接收到其他服务器传送过来的消息时,可以用这个证书来解密消息
    create certificate BookStoreCert
    with subject = 'BookStore service broker cert',
         expiry_date = '2012-12-31'
    
    
    --3.备份证书
    backup certificate bookstorecert
    to file = 'c:\bookstorecert.cer'
    go
    
    
    --4.创建数据库用户,此用户只可以有一个证书
    create user bookDistributionUser
    without login
    go
    
    
    --5.通过从另一个实例复制过来的证书,来创建证书,并指定所有者为此用户
    create certificate bookDistributionCert
    authorization bookDistributionUser        --此用户只能拥有一个证书,
                                              --在发送消息时会用这个证书来加密消息
    from file = 'c:\bookDistributionCert.cer'
    
    
    --6.授予此用户名在某个服务上发送的权限
    grant send on service::[//BookConsulting/BookOrderService] to bookDistributionUser
    go
    
    
    --7.创建路由
    create route route_bookDistribution
    with service_name = '//BookConsulting/BookDistributionService',
         address = 'tcp://192.168.1.16:4021'
    
    
    --8.创建远程绑定
    create remote service binding bookDistributionBinding
    to service '//BookConsulting/BookDistributionService'
    with user = bookDistributionUser
    
    
    --9.开始会话,发送消息
    declare @conversation_handler uniqueidentifier
    declare @order_msg xml;
    
    
    begin dialog conversation @conversation_handler
    from service [//BookConsulting/BookOrderService]
    to service '//BookConsulting/BookDistributionService'
    on contract [//BookConsulting/BookOrderContract]
    
    
    set @order_msg = 
    	'<order id="1234" customer="22" orderdate="2012-10-01">
    	<LineItem ItemNumber="1" ISBN="1-12345-123-0" Quantity="1" />
    	</order>
    	';
    
    
    --send语句可以发送消息	
    send on conversation @conversation_handler
    message type [//BookConsulting/SendBookOrder]
    (@order_msg);
    
    
    
    
    --启用对话安全模式
    --实例2
    use bookdistribution
    go
    
    create master key encryption by password = '123456&^%'  
    
    
    --当接收到对方发送的消息后,用此证书来解密
    create certificate BookDistributionCert
    with subject = 'BookDistribution service broker cert',
         expiry_date = '2012-12-31'
    
    
    backup certificate bookDistributioncert
    to file = 'c:\bookDistributioncert.cer'
    
    
    create user bookStoreUser
    without login
    
    
    --在发送之前,用此证书来加密消息
    create certificate bookStoreCert
    authorization bookStoreUser
    from file = 'c:\bookStoreCert.cer'
    
    
    grant send on service::[//BookConsulting/BookDistributionService] to bookStoreUser
    
    
    create route route_bookStore
    with service_name = '//BookConsulting/BookOrderService',
         address = 'tcp://192.168.9.67:4020'
    
    
    create remote service binding bookStoreBinding
    to service '//BookConsulting/BookOrderService'
    with user = bookStoreUser
    
    
    --查询消息
    SELECT *
    FROM dbo.bookdistributionqueue  
            
    


    事件通知
    事件通知是集成到Service Broker的功能,这样可以在SQL Server实例中异步捕获SQL事件,将事件信息路由到特定的队列中。只需要最小的系统开销,就可以跟踪发生在SQL Server实例的事件,比如用户登录,存储过程重新编译,权限修改,对象处理(包括:对数据库、程序集、角色、表的create/alter/drop事件)。

    使用事件通知只需要创建队列和Service Broker组件,在SQL Server中已经内建了,用来捕捉和发送事件通知的消息类型、约定。

    IF NOT exists(select 1
                  from sys.databases
                  where name = 'EventTracking')
                  
    	create database EventTracking
    else
    	drop database EventTracking
    	
    go
    
    
    use eventtracking
    go
    
    
    --1.创建队列
    create queue SQLEventQueue
    with status = on
    go
    
    
    --2.在队列上创建服务,关联到内建的事件通知约定
    create service [//EventTracking/TrackLoginAlterService]
    on queue SQLEventQueue
    ([http://schemas.microsoft.com/SQL/Notifications/PostEventNotification]);
    
    
    --3.查询guid
    select service_broker_guid --6AE234DF-C4BB-4C1B-9E08-F4EA66359B6A
    from sys.databases
    where name = 'EventTracking'
    
    
    --4.创建server范围的事件通知,来跟踪SQL Server实例中所有登录名的创建,修改,删除
    create event notification EVENT_LoginEvent
    on server
    for create_login,alter_login,drop_login
    to service '//EventTracking/TrackLoginAlterService',
       '6AE234DF-C4BB-4C1B-9E08-F4EA66359B6A'   --service_broker_guid
    
    
    --5.创建一个登录名,事件通知,把消息放入队列
    create login login_ggg with password = '123456!@'
    
    
    --6.查询消息
    select CAST(message_body as xml) as event_Info
    from dbo.sqleventqueue
    
  • 相关阅读:
    file is universal (3 slices) but does not contain a(n) armv7s slice error for static libraries on iOS
    WebImageButton does not change images after being enabled in Javascript
    ajax OPTION
    编程遍历页面上所有TextBox控件并给它赋值为string.Empty?
    获取海洋天气预报
    C#线程系列教程(1):BeginInvoke和EndInvoke方法
    js控制只能输入数字和小数点
    Response.AddHeader(,)
    ManualResetEvent的理解
    Convert.ToInt32、int.Parse(Int32.Parse)、int.TryParse、(int) 区别
  • 原文地址:https://www.cnblogs.com/momogua/p/8304592.html
Copyright © 2011-2022 走看看