1

我不知道這個問題是否重複。如果這個問題重複,請給我鏈接。如何調用由服務代理組成的存儲過程

我的問題是如何調用由BEGIN TRANSACTION & COMMIT TRANSACTION(Service Broker)組成的2個存儲過程。

我有2個存儲過程用於執行Service Broker的某些操作。

這是包含BEGIN CONVERSATION存儲過程:下面

USE [EventCloud] 
GO 

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 

ALTER PROCEDURE [dbo].[SendingMessage_Group_Id] 
    @reference_id UNIQUEIDENTIFIER 
AS 
BEGIN 
    DECLARE @ch UNIQUEIDENTIFIER 
    DECLARE @conversation_group_id UNIQUEIDENTIFIER 
    DECLARE @msg NVARCHAR(MAX) 

    SET @conversation_group_id = @reference_id 

    BEGIN TRY 
     BEGIN TRANSACTION 

      BEGIN DIALOG CONVERSATION @ch 
       FROM SERVICE [InitiatorService] 
       TO SERVICE 'TargetService' 
       ON CONTRACT [http://ssb.csharp.at/SSB_Book/c03/HelloWorldContract] 
       WITH RELATED_CONVERSATION_GROUP = @conversation_group_id, 
        ENCRYPTION = OFF 

      SET @msg = '<HelloWorldRequest>1234</HelloWorldRequest>' 

      ;SEND ON CONVERSATION @ch MESSAGE TYPE [http://ssb.csharp.at/SSB_Book/c03/RequestMessage] 
      (
       @msg 
      ) 

     COMMIT TRANSACTION; 
    END TRY 
    BEGIN CATCH 
     ROLLBACK TRANSACTION 
    END CATCH 
END 

代碼是TargetQueue的內部激活存儲過程:

USE [EventCloud] 
GO 

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 

ALTER PROCEDURE [dbo].[ProcessRequestMessage] 
AS 
BEGIN 
    DECLARE @ch UNIQUEIDENTIFIER 
    DECLARE @messagetypename NVARCHAR(256) 
    DECLARE @messagebody XML 
    DECLARE @responsemessage XML; 
    DECLARE @errorcode INT 
    DECLARE @errormessage NVARCHAR(3000); 

    WHILE (1 = 1) 
    BEGIN 
     BEGIN TRY 
      BEGIN TRANSACTION; 
       WAITFOR(
        RECEIVE TOP (1) 
         @ch = conversation_handle, 
         @messagetypename = message_type_name, 
         @messagebody = CAST(message_body AS XML) 
        FROM TargetQueue 
       ) 

       IF (@@ROWCOUNT = 0) 
       BEGIN 
        ROLLBACK TRANSACTION 
        BREAK 
       END 

       -- Process the requested message and send back to Initiator 
       ELSE IF (@messagetypename = 'http://ssb.csharp.at/SSB_Book/c03/RequestMessage') 
       BEGIN 
        -- Store the received request message in a table 
        INSERT INTO ProcessedMessages (ID, MessageBody, ServiceName, ProcessedDateTime) 
        VALUES (NEWID(), @messagebody, 'TargetService', GETDATE()) 

        -- Construct the response message 
        SET @responsemessage = 
         '<HelloWorldResponse>' + 
          @messagebody.value('/HelloWorldRequest[1]', 'NVARCHAR(MAX)') + 
         '</HelloWorldResponse>'; 

        -- Send the response message back to the initiating service 
        SEND ON CONVERSATION @ch MESSAGE TYPE [http://ssb.csharp.at/SSB_Book/c03/ResponseMessage] 
        (
         @responsemessage 
        ); 

        -- END the conversation on the target's side 
        END CONVERSATION @ch; 
       END 

       -- End the conversation if meet the message type 
       IF (@messagetypename = 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog') 
       BEGIN 
        -- End the conversation 
        END CONVERSATION @ch; 
       END 

      COMMIT TRANSACTION 
     END TRY 
     BEGIN CATCH 
      ROLLBACK TRANSACTION 
      PRINT ERROR_MESSAGE() 
     END CATCH 
    END 
END 

而這個代碼,用於接收從InitiatorQueue響應消息:

ALTER PROCEDURE [dbo].[ProcessMessageWithTimeOut] 
    @reference_id UNIQUEIDENTIFIER, 
    @receive_timeout INT 
AS 
BEGIN 
    DECLARE @ch UNIQUEIDENTIFIER 
    DECLARE @conversation_group_id UNIQUEIDENTIFIER 
    DECLARE @messagetypename NVARCHAR(256) 
    DECLARE @messagebody XML 
    DECLARE @responsemessage XML 
    DECLARE @errorcode INT 
    DECLARE @errormessage NVARCHAR(3000) 
    DECLARE @queuing_order BIGINT 
    DECLARE @timeout INT 

    SET @conversation_group_id = @reference_id 
    SET @timeout = @receive_timeout 

    DECLARE @tableMessage TABLE 
    (
     queuing_order BIGINT, 
     conversation_handle UNIQUEIDENTIFIER, 
     message_type_name NVARCHAR(256), 
     message_body VARBINARY(MAX) 
    ) 

    BEGIN TRY 
     BEGIN TRANSACTION 
      WAITFOR(
       RECEIVE 
        queuing_order, 
        conversation_handle, 
        message_type_name, 
        message_body 
       FROM InitiatorQueue INTO @tableMessage 
       WHERE conversation_group_id = @conversation_group_id 
      ), TIMEOUT @timeout; 

      DECLARE @count INT 
      SET @count = (SELECT COUNT(*) FROM @tableMessage) 
      IF (@count = 0) 
      BEGIN; 
       THROW 50001, 'No message response within 5 seconds.', 1 
      END 

      IF (@count <>2) 
      BEGIN 
       DECLARE @timeout2 INT 
       SET @timeout2 = ABS(@timeout * 0.5) 

       WAITFOR(
        RECEIVE 
         queuing_order, 
         conversation_handle, 
         message_type_name, 
         message_body 
        FROM InitiatorQueue INTO @tableMessage 
        WHERE conversation_group_id = @conversation_group_id 
       ), TIMEOUT 5000 
       SET @count = (SELECT COUNT(*) FROM @tableMessage) 
       IF (@count <> 2) 
       BEGIN; 
        THROW 50002, 'End Dialog without Response Message', 1 
       END 
      END 

      WHILE (@count <> 0) 
      BEGIN 
      SET @queuing_order = (SELECT TOP 1 queuing_order FROM @tableMessage) 
      SET @ch = (SELECT conversation_handle FROM @tableMessage WHERE queuing_order = @queuing_order) 
      SET @messagetypename = (SELECT message_type_name FROM @tableMessage WHERE queuing_order = @queuing_order) 
      SET @messagebody = CAST((SELECT message_body FROM @tableMessage WHERE queuing_order = @queuing_order) AS XML) 

       IF (@messagetypename = 'http://ssb.csharp.at/SSB_Book/c03/ResponseMessage') 
       BEGIN 
        -- Store the received response message in a table 
        INSERT INTO ProcessedMessages (ID, MessageBody, ServiceName, ProcessedDateTime) 
        VALUES (NEWID(), @messagebody, 'InitiatorService', GETDATE()) 
       END 

       ELSE IF (@messagetypename = 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog') 
       BEGIN 
        -- End the conversation on the initiator's side 
        END CONVERSATION @ch 
       END 
       DELETE FROM @tableMessage WHERE queuing_order = @queuing_order 
       SET @count = (SELECT COUNT(*) FROM @tableMessage) 
      END 

     COMMIT TRANSACTION; 
    END TRY 
    BEGIN CATCH 
     IF ERROR_NUMBER() = 50001 
     BEGIN 
      ;THROW 
     END 

     IF ERROR_NUMBER() = 50002 
     BEGIN 
      ;THROW 
     END 
     ;THROW 
     ROLLBACK TRANSACTION 
     PRINT ERROR_MESSAGE() 
    END CATCH 
END 

這是我的C是,用於調用存儲過程#代碼:

public async Task<TestObject> Begin_Conversation_With_Group_Id(Guid ch) 
{ 
    try 
    { 
     return await Context.Database.SqlQuery<TestObject>(
     "EXEC SendingMessage_Group_Id @ch", 
     new SqlParameter("ch", ch)) 
      .SingleOrDefaultAsync(); 
    } 
    catch (Exception e) 
    { 
     TestObject exception = new TestObject(); 
     exception.Data = "Cannot get the data due to: " + " " + e.Message; 
     return exception; 
    } 
} 

public async Task<TestObject> Process_Response_Message_With_TimeOut(Guid ch) 
{ 
    var timeout = 5000; 
    try 
    { 
     return await Context.Database.SqlQuery<TestObject>(
      "EXEC ProcessMessageWithTimeOut @ch, @timeout", 
      new SqlParameter("ch", ch), 
      new SqlParameter("timeout", timeout)) 
       .SingleOrDefaultAsync(); 
    } 
    catch (SqlException ex) 
    { 
     TestObject exception = new TestObject(); 
     exception.Data = "Process is not finish yet due to: " + ex.Message + " " + ex.Number; 
     return exception; 
    } 
} 

問題是,當我運行的代碼,該消息還處於TargetQueue,由右應該由內部激活來接收和處理。

但它工作正常,如果只調用1個存儲過程(SendingMessage_Group_Id)。該消息能夠迴應到InitiatorQueue而不是停留在TargetQueue

從我的猜測,是因爲交易還沒有提交。

+1

C#與該問題無關。嘗試通過手動執行這些過程使其在沒有任何C#代碼的情況下工作。 –

+0

它沒有C#,這意味着當我在MSSQL上執行它工作正常 –

+0

當你通過SSMS或C#執行代碼應該沒有什麼區別。如果你有差異,那麼某些東西不會以相同的方式執行。嘗試使用SQL事件探查器來檢查使用C#代碼時執行的查詢,並查看差異 –

回答

0

該問題已解決。

發生此問題的原因是因爲我使用導致此情況發生的框架。 該框架在啓動時包含一個事務,所以我需要做的是禁用框架事務,然後解決問題。

我正在使用的框架是ASP.NET Zero