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
。
從我的猜測,是因爲交易還沒有提交。
C#與該問題無關。嘗試通過手動執行這些過程使其在沒有任何C#代碼的情況下工作。 –
它沒有C#,這意味着當我在MSSQL上執行它工作正常 –
當你通過SSMS或C#執行代碼應該沒有什麼區別。如果你有差異,那麼某些東西不會以相同的方式執行。嘗試使用SQL事件探查器來檢查使用C#代碼時執行的查詢,並查看差異 –