I'm using .net 5 azure function with ServiceBusTrigger. In previous versin. I was using a parametr MessageReceiver to tell azure that I compleated task. For that I used
await messageReceiver.CompleteAsync(message.SystemProperties.LockToken);
My problem is that i new version (.net5) unlike the previous version (.net core 3.1) is param in string (json) not in object (maybe it's the error but I don't know which object to use, object I tried was Microsoft.Azure.ServiceBus.Core.MessageReceiver).
But now i do not have the object so i can not call the method.
Does someone knows the answer? Thak you for your time.
Example of my code:
Function("TasksFunction")]
public async Task Run([ServiceBusTrigger("queue", Connection = "ConnectionString")] string message, string id, MessageReceiver messageReceiver, FunctionContext executionContext)
{
try
{
await messageReceiver.CompleteAsync(message.SystemProperties.LockToken);
await DoWorkAsync(messageReceiver, message);
}
catch (Exception e)
{
log.LogCritical(e);
}
}
Try to bind your message to Message type instead of string
public async Task Run([ServiceBusTrigger("queue", Connection = "ConnectionString")] Message message, string id, MessageReceiver messageReceiver, FunctionContext executionContext)
Message has property SystemPropertiesCollection and use message.SystemProperties.LockToken
Related
We have void method which submits a message to azure service bus and
service bus client has send message which don't have an return value.
Please find the method below , what I can think of is make the method return a bool if there is no issue .
we are using Moq and Xunit and .Net 6 version
then I am not sure how to mock the _azureClientFactory.
is it a normal practice to skip this type of method from unit testing
can anybody help me on this or please share any pointers
public async Task SendMessage(string message)
{
try
{
var serviceBusCLient = _azureClientFactory.CreateClient("SubmitClient");
var serviceBusSender = serviceBusCLient.CreateSender("queue1");
var serviceBusMessage = new ServiceBusMessage(message);
await serviceBusSender.SendMessageAsync(serviceBusMessage);
}
catch (Exception ex)
{
_logger.LogError("ex.Message}");
throw new AzureBusServiceException($"sendmessage failed");
}
}
I am new to C# and I am trying to build a handler function with Lambda to push messages to an SNS topic, this is what I have:
using MessagePublisher;
using Amazon.Lambda.Core;
using Amazon.SimpleNotificationService;
using Amazon.SimpleNotificationService.Model;
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace SNSMessagePublisher
{
public class Function
{
public string PublishMessageHandler(NewMessage input, ILambdaContext context)
{
var client = new AmazonSimpleNotificationServiceClient(Amazon.RegionEndpoint.EUWest2);
LambdaLogger.Log($"Calling function name: {context.FunctionName}\n");
var publishRequest = new PublishRequest(
"arn:aws:sns:eu-west-2:123...9:TopicABC",
input.body);
client.PublishAsync(publishRequest);
return $"Message Published: {input.body}";
}
}
}
namespace MessagePublisher {
public class NewMessage {
public string body { get; set; }
}
}
I then trigger a set payload of:
{
"body": "test body"
}
and in the CloudWatch logs, I get an output of:
Calling function name: messagePublisher
And the Lambda console returns:
"Message Published: test body"
However, the topic never actually receives a message.
client.PublishAsync(publishRequest); is asynchronous, will return a Task and as such, you need to wait on the task to finish executing using await.
Without calling await on the task, there is no guarantee that the client has published the message before the Lambda finishes executing.
The message is not being sent as the task for sending the message hasn't finished executing before the Lambda function has returned.
This should work:
public async Task<string> PublishMessageHandler(NewMessage input, ILambdaContext context)
{
var client = new AmazonSimpleNotificationServiceClient(Amazon.RegionEndpoint.EUWest2);
LambdaLogger.Log($"Calling function name: {context.FunctionName}\n");
var publishRequest = new PublishRequest(
"arn:aws:sns:eu-west-2:123...9:TopicABC",
input.body);
await client.PublishAsync(publishRequest);
return $"Message Published: {input.body}";
}
As you're new to C#, I would recommend reading Microsoft's Asynchronous programming with async and await article.
I have a bot that does a hand-off to a human operator.
When the operator joins I receive an event in the 'OnEventActivityAsync' event.
At that moment I want to send a message to the client that they're connected to the operator.
How do I change the turnContext/Activity to send the message to the client?
Not entirely sure which part of code to post. (can't post entire project due to company policies)
protected override async Task OnEventActivityAsync(ITurnContext<IEventActivity> turnContext, CancellationToken cancellationToken)
{
if (turnContext.Activity.Name == "webchat/agentJoin")
{
_logger.LogInformation("webchat/agentJoin");
//Database stuff here
await turnContext.SendActivityAsync(MessageFactory.Text("Connected to customer"), cancellationToken);
//How do I send a message to the client here? turnContext sends the message to the agent, not client
}
}
Please See protocol definition in the below GitHub link experimentations:
https://github.com/microsoft/BotBuilder-Samples/tree/master/experimental/handoff-library
Factory Methods
SDK will include the following factory method to aid in creation of the events specified:
C#:
namespace Microsoft.Bot.Builder
{
public static class EventFactory
{
public static IEventActivity CreateHandoffInitiation(
ITurnContext turnContext,
object handoffContext,
Transcript transcript);
public static IEventActivity CreateHandoffResponse(
ConversationAccount Conversation,
string code);
public static IEventActivity CreateHandoffCompleted(
ConversationAccount Conversation,
string code,
Transcript transcript);
}
}
Protocol codes are defined as follows:
namespace Microsoft.Bot.Schema
{
public static class HandoffCodes
{
public const string Accepted = "accepted";
public const string Failed = "failed";
public const string TimedOut = "timedOut";
public const string EndOfConversation = "endOfConversation";
public const string TransferBack = "transferBack";
}
}
Thanks to the suggestion by Mick I took another look at proactive messages.
I had looked at it before, but never got it to work because of 'Unauthorized' errors.
Now I noticed there's a fix for that specific problem.
The code is based on the MS documentation for sending proactive notifications:
Send proactive Notifications
So what I do is:
turnContext.Adapter.ContinueConversationAsync(_appId, conversationReference, BotCallback, default(CancellationToken));
private async Task BotCallback(ITurnContext turnContext, CancellationToken cancellationToken)
{
// If you encounter permission-related errors when sending this message, see
// https://aka.ms/BotTrustServiceUrl
await turnContext.SendActivityAsync("You're now connected to: Ted");
}
I am attempting to convert my v1 function to a v2 function, but I cannot find a replacement for deferring a message.
In V1 of Azure Functions it was a method on the BrokeredMesage called .DeferAsync(). In V2 there is no longer a BrokeredMessage but just a Microsoft.Azure.ServiceBus.Message and this does not contain the method of .DeferAsync().
According to the docs:
The API is BrokeredMessage.Defer or BrokeredMessage.DeferAsync in the .NET Framework client, MessageReceiver.DeferAsync in the .NET Standard client, and mesageReceiver.defer or messageReceiver.deferSync in the Java client.
But how can I get access to the MessageReciever?
Here is an example of my function:
[FunctionName("MyFunction")]
public static void Run([ServiceBusTrigger("topic", "subscription", Connection = "AzureServiceBusPrimary")]Message message, ILogger log)
{
//Code
}
So does anyone know how to defer a V2 Message that is triggered from the Azure Service Bus?
As you mention, the new message receiver offers an async defer method and you can add this to your function by using the following code:
[FunctionName("MyFunction")]
public static async Task Run([ServiceBusTrigger("topic", "subscription", Connection = "AzureServiceBusPrimary")]Message message, string lockToken, MessageReceiver messageReceiver, ILogger log)
{
//Your function logic
await messageReceiver.DeferAsync(lockToken);
}
I use ExceptionFilterAttribute for my web api application to catch different unhandled exceptions, i.e.:
public class InvalidDriverExceptionAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
if (actionExecutedContext.Exception != null)
{
if (actionExecutedContext.Exception is Domain.InvalidDriverException)
{
var resp = actionExecutedContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, "User is not a driver");
actionExecutedContext.Response = resp;
}
}
//base.OnException(actionExecutedContext);
}
}
but I want to have similar engine for my web job. Is it possible?
but I want to have similar engine for my web job. Is it possible?
Yes. But because web jobs are continuous or schedule, there are some differences in how they are implemented. You could use ErrorTrigger to achieve your goal. An error trigger that allows you to annotate functions to be automatically called by the runtime when errors occur. It could monitor errors in web job when it is executed.My Demo result like this:filter null exception. For more details, you could refer to this article.
When developing jobs with Azure WebJob, it's a good practice to implement error monitoring in case something goes wrong when a job is executed.
The WebJobs ErrorTrigger extension, part of the Core extensions, will help us achieve that.
I have created derived class from FunctionExceptionFilterAttribute
public class ErrorHandlerAttribute : FunctionExceptionFilterAttribute
{
public override async Task OnExceptionAsync(FunctionExceptionContext exceptionContext, CancellationToken cancellationToken)
{
string body = $"ErrorHandler called. Function '{exceptionContext.FunctionName}': {exceptionContext.FunctionInstanceId} failed. ";
CombineErrorWithAllInnerExceptions(exceptionContext.Exception, ref body);
string[] emailList = System.Configuration.ConfigurationManager.AppSettings["SendErrorEmails"].Split(';');
await SendEmail.SendErrorNotificationAsync("WebJob - Common Driver Error", body);
}
private void CombineErrorWithAllInnerExceptions(Exception ex, ref string error)
{
error += $"ExceptionMessage: '{ex.Message}'.";
if (ex is Domain.BadStatusCodeException)
{
error += $"Status code: {((Domain.BadStatusCodeException)ex).StatusCode}";
}
if (ex.InnerException != null)
{
error += $"InnerEx: ";
CombineErrorWithAllInnerExceptions(ex.InnerException, ref error);
}
}
}
and then use it for method:
[NoAutomaticTrigger]
[ErrorHandler]
public async Task GetDriversAsync(TextWriter logger)
{
when exception occurs it call this code and send notification email to me