Execute different pieces of code based on a value in C# - c#

I have a piece of C# code that reacts to an HTTP trigger from Azure and gets executed. The piece of code sends an email containing a warning:
#r "Newtonsoft.Json"
#r "SendGrid"
using System;
using SendGrid.Helpers.Mail;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
public static SendGridMessage Run(HttpRequest req, ILogger log)
{
string requestBody = new StreamReader(req.Body).ReadToEnd();
log.LogInformation(requestBody);
var notifications = JsonConvert.DeserializeObject<IList<Notification>>(requestBody);
SendGridMessage message = new SendGridMessage();
message.Subject = "Sensor Anomaly Warning";
var content = "The following device has started registering anomalies:<br/><br/><table><tr><th>time</th><th>value</th><th>lower bound</th><th>upper bound</th><th>device</th></tr>";
foreach(var notification in notifications) {
log.LogInformation($" - time: {notification.time}, value: {notification.value}, lowerbound: {notification.lowerbound}, upperbound: {notification.upperbound}, device: {notification.device}");
content += $"<tr><td>{notification.time}</td><td>{notification.value}</td><td>{notification.lowerbound}</td><td>{notification.upperbound}</td><td>{notification.device}</td></tr>";
}
content += "</table>";
message.AddContent("text/html", content);
return message;
}
public class Notification
{
public string time { get; set; }
public string value { get; set; }
public string lowerbound { get; set; }
public string upperbound { get; set; }
public string device { get; set; }
}
Now, I want to execute this same piece of code that sends an email, but based on the value of notification.alert which stores a zero if an anomaly started and a 1 if the alert stopped. Coming from python, this would be as easy as setting an "if else" statement, where the function is called in each case.
However for this C# code, there is no function to call. The piece of code sends an email but it's just creating a class. In any case, I'm wondering if I can use a "if else" statement in C# based on the value of notification.alert that in one case sends an email saying something like "the device has started registering anomalies" and in the other "the device has stopped registering anomalies". I just can't get to do this, as I have to address the notification object, which is already inside the class.
I must say that I am not a C# developer but a Python developer, hence the doubts.

You can use if/else statement or switch to update the email body based on notification.alert. this function is not sending the email it's just setting up a message for the email body text.
using System;
using SendGrid.Helpers.Mail;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
public static SendGridMessage Run(HttpRequest req, ILogger log)
{
string requestBody = new StreamReader(req.Body).ReadToEnd();
log.LogInformation(requestBody);
var notifications = JsonConvert.DeserializeObject<IList<Notification>>(requestBody);
SendGridMessage message = new SendGridMessage();
message.Subject = "Sensor Anomaly Warning";
var content = "The following device has started registering anomalies: <br/><br/><table><tr><th>time</th><th>value</th><th>lower bound</th><th>upper bound</th><th>device</th></tr>";
foreach(var notification in notifications) {
log.LogInformation($" - time: {notification.time}, value: {notification.value}, lowerbound: {notification.lowerbound}, upperbound: {notification.upperbound}, device: {notification.device}");
content += notification.alert == 0 ? "the device has started registering anomalies" : "the device has stopped registering anomalies";
}
content += "</table>";
message.AddContent("text/html", content);
return message;
}
public class Notification
{
public string time { get; set; }
public string value { get; set; }
public string lowerbound { get; set; }
public string upperbound { get; set; }
public string device { get; set; }
public int alert { get; set;}
}

Related

Sending input parameters to AWS Lambda function from Unity

I'm learning AWS Lambda with C#. My function looks sort of like this:
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace Function_Redeem
{
public class Function
{
public FunctionOutput FunctionHandler(FunctionInput input, ILambdaContext context)
{
// do work with input
// return FunctionOutput
}
public class FunctionInput
{
public string someData { get; set; }
}
public class FunctionOutput
{
public string someAnswer { get; set; }
}
}
}
It works fine when using the Test button in AWS, as well as the test feature in Visual Studio.
Now, I'm trying to call this from Unity.
So first, I added an API Gateway trigger, and left the defaults:
API endpoint: [the url]
API type: HTTP
Authorization: NONE
Cross-origin resource sharing (CORS): No
Enable detailed metrics: No
Method: ANY
Resource path: /FunctionName
Stage: default
Then in Unity,
private static IEnumerator TestFunction(string uri, string data)
{
UnityWebRequest webRequest = UnityWebRequest.Put(uri, data);
yield return webRequest.SendWebRequest();
if (webRequest.isNetworkError)
Debug.LogError("Network error: " + webRequest.error);
else
Debug.Log(webRequest.downloadHandler.text);
}
I call it, with data being
{"someData":"Hello"}
The function call works, I know that it is reaching my function, but the input data (i.e. the someData field) is null. It seems like it's not parsing the data I'm sending so FunctionInput defaults to null someData.
What am I missing?
Since you are using API Gateway as a trigger to your lambda function, accept APIGatewayProxyRequest as input parameter to your handler(instead of FunctionInput). The field Body would have your serialized payload {"someData":"Hello"}
public class Function
{
public FunctionOutput FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
{ var requestBody = JsonConvert.DeserializeObject<FunctionInput>(request.Body);
// do work with input
// return FunctionOutput
}
public class FunctionInput
{
public string someData { get; set; }
}
public class FunctionOutput
{
public string someAnswer { get; set; }
}
}
}

MassTransit - Unit Testing a Large Payload Consumer

Using the InMemoryTestHarness, I am working on unit testing a Consumer that handles a command with a MessageData property. Using the InMemoryMessageDataRepository to populate the MessageData property works fine however, when the consumer attempts to load the payload (message.Body.Value) I am receiving the following exception: "The message data was not loaded: urn:msgdata:xxxxxxxxxxxxxxxxxxxxxxxxxx"}. What is the proper way to unit test a consumer that handles commands with a MessageData property?
I was going to use the In-memory transport, but it doesn't seem like the right approach since the unit test(s) will not receive immediate feedback from the consumer. Ultimately the end goal is for my unit tests to be able assert that specific exceptions are thrown or that the consumer completed successfully without errors.
using System;
using System.Linq;
using System.Threading.Tasks;
using MassTransit;
using MassTransit.MessageData;
using MassTransit.Testing;
using Newtonsoft.Json;
using Xunit;
namespace Test
{
public class LargePayloadConsumerTest
{
[Fact]
public async Task Consumer_Should_Deserialize_Message()
{
var harness = new InMemoryTestHarness();
var consumer = harness.Consumer<BigMessageConsumer>();
var command = new BigMessageCommand();
var dataRepo = new InMemoryMessageDataRepository();
var largePayload = new BigMessagePayload()
{
Id = 1,
FirstName = "TestFirstName",
MiddleName = "TestMiddleName",
LastName = "TestLastName"
};
var json = JsonConvert.SerializeObject(largePayload);
command.Body = await dataRepo.PutString(json);
var thisWorks = await command.Body.Value;
await harness.Start();
await harness.InputQueueSendEndpoint.Send(command);
Assert.True(harness.Consumed.Select<BigMessageCommand>().Any());
}
public class BigMessageConsumer : IConsumer<BigMessageCommand>
{
public async Task Consume(ConsumeContext<BigMessageCommand> context)
{
try
{
var json = await context.Message.Body.Value;
var deserialized = JsonConvert.DeserializeObject<BigMessagePayload>(json);
Console.WriteLine($"{deserialized.Id}: {deserialized.FirstName} {deserialized.MiddleName} {deserialized.LastName}");
}
catch (Exception e)
{
//throws {"The message data was not loaded: urn:msgdata:xxxxxxxxxxxxxxxxxxxxxxxxxx"}
Console.WriteLine(e);
throw;
}
}
}
public class BigMessageCommand
{
public MessageData<string> Body { get; set; }
}
public class BigMessagePayload
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
}
}
}
You need to configure the receive endpoint to handle the message data property, similar to this:
e.UseMessageData<BigMessageCommand>(dataRepo);
Since you're using the test harness, you can add it to the receive endpoint before you add the consumer test harness:
void ConfigureReceiveEndpoint(IReceiveEndpointConfigurator configurator)
{
configurator.UseMessageData<BigMessageCommand>(dataRepo);
}
harness.OnConfigureReceiveEndpoint += ConfigureReceiveEndpoint;

Azure Function used to write to queue - can I set metadata?

I can see from this page that you can access a queue message metadata properties simply enough when they are used as a trigger, but I want to do the opposite.
I have an Azure function which writes messages to a queue, but it current has the default Expiration Time and I want to set a much shorter expiration time so they only live on the queue for a very short period.
Is there a way when writing the message to the queue from the Azure Function to set the Expiration time?
Thanks
EDIT 1:
One caveat is that I dont know the name of the queue ahead of time. That is part of the incoming message, so the queuename is set as a parameter of the output binding
I made the change as recommended by #Mikhail. Here is the function as it stands:
#r "Microsoft.WindowsAzure.Storage"
#r "Newtonsoft.Json"
using System;
using Microsoft.WindowsAzure.Storage.Queue;
using Newtonsoft.Json;
public static void Run(MyType myEventHubMessage, CloudQueue outputQueue, TraceWriter log)
{
var deviceId = myEventHubMessage.DeviceId;
var data = JsonConvert.SerializeObject(myEventHubMessage);
var msg = new CloudQueueMessage(data);
log.Info($"C# Event Hub trigger function processed a message: {deviceId}");
outputQueue.AddMessage(msg, TimeSpan.FromMinutes(3), null, null, null);
}
public class MyType
{
public string DeviceId { get; set; }
public double Field1{ get; set; }
public double Field2 { get; set; }
public double Field3 { get; set; }
}
And the output binding in my function.json:
{
"type": "CloudQueue",
"name": "$return",
"queueName": "{DeviceId}",
"connection": "myConn",
"direction": "out"
}
Change the type of your parameter to CloudQueue, then add a message manually and set the expiration time property (or rather Time To Live).
public static void Run(string input, CloudQueue outputQueue)
{
outputQueue.AddMessage(
new CloudQueueMessage("Hello " + input),
TimeSpan.FromMinutes(5));
}
Edit: if your output queue name depends on request, you can use imperative binding:
public static void Run(string input, IBinder binder)
{
string outputQueueName = "outputqueue " + input;
QueueAttribute queueAttribute = new QueueAttribute(outputQueueName);
CloudQueue outputQueue = binder.Bind<CloudQueue>(queueAttribute);
outputQueue.AddMessage(
new CloudQueueMessage("Hello " + input),
TimeSpan.FromMinutes(5));
}

Twilio Rest API Helper Library, v 5.0.1, C# - MessageResource.Create function call not returning properly

I am using the Twilio REST API helper library, v 5.0.1 in my C# ASP.NET MVC Web Application. I created the following helper class and function to send out text messages:
using MyApplication.Web.Helpers;
using System;
using System.Configuration;
using Twilio;
using Twilio.Exceptions;
using Twilio.Rest.Api.V2010.Account;
using Twilio.Types;
namespace MyApplication.Web.Services
{
public class TwilioSmsSender : ISmsSender
{
public string AccountSid { get; set; }
public string AuthToken { get; set; }
public string FromPhoneNumber { get; set; }
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public string SmsPrefix { get; set; }
public string SmsSuffix { get; set; }
public TwilioSmsSender()
{
//get our Twilio account info from the config file
AccountSid = ConfigurationManager.AppSettings["TwilioAccountSid"];
AuthToken = ConfigurationManager.AppSettings["TwilioAuthToken"];
FromPhoneNumber = ConfigurationManager.AppSettings["SmsService.FromPhoneNumber"];
SmsPrefix = ConfigurationManager.AppSettings["SmsPrefix"];
SmsSuffix = ConfigurationManager.AppSettings["SmsSuffix"];
if (FromPhoneNumber.Length == 10)
{
FromPhoneNumber = $"+1{FromPhoneNumber}";
}
TwilioClient.Init(AccountSid, AuthToken);
}
public INotificationResponse SendTextMessage(string phoneNumber, string message, bool useFormatting = true)
{
var resp = new TwilioSmsSenderResponse();
resp.Succeeded = false;
resp.AttemptDateTimeUtc = DateTime.UtcNow;
if (useFormatting)
{
message = $"{SmsPrefix}{message}{SmsSuffix}";
}
try
{
var msgResponse = MessageResource.Create(
to: new PhoneNumber($"+1{phoneNumber}"),
from: new PhoneNumber($"{FromPhoneNumber}"),
body: message);
//Previous line works (i.e, I get the text message that I'm sending out successfully).
//However, none of the following lines are running...
//As you see, this is in a try/catch block... and it doesn't go to the catch block either!
if (msgResponse.ErrorCode == null)
{
//successfully queued
resp.Succeeded = true;
resp.ReferenceId = msgResponse.Sid;
resp.AttemptDateTimeUtc = DateTime.UtcNow;
}
else
{
//Twilio sent an error back
log.Info($"Twilio sent an error back: {msgResponse}");
resp.Succeeded = false;
resp.Notes = $"ErrorCode: {msgResponse.ErrorCode}, ErrorMessage: {msgResponse.ErrorMessage}";
resp.AttemptDateTimeUtc = DateTime.UtcNow;
}
}
catch (Exception e)
{
resp.Succeeded = false;
resp.Notes = ExceptionsHelper.GetExceptionDetailsAsString(e);
resp.AttemptDateTimeUtc = DateTime.UtcNow;
log.Error($"Twilio Error: {resp.Notes}, to: {phoneNumber}, message: {message}");
}
return resp;
}
}
}
Unfortunately, my code is not behaving as I expected it would after the MessageResource.Create() call. That is, the text-message is sent out correctly and I receive the SMS on my phone. However, I expect the call to return control to my msgResponse variable and I expect the
if (msgResponse.ErrorCode == null) ...
line and subsequent lines to run but that is not happening. I can put a breakpoint on the var msgResponse line and it will run that just fine but it does not run any code lines after that. You’ll see that I have the call in a try/catch. I suspected there was an exception that was occurring but it doesn’t seem so because it doesn’t go to my catch block either! The text message is being sent successfully! All I want to do is to get an acknowledgement back so that I can properly log it and send that information back to the routines that are calling this function.
Any help would be greatly appreciated!
version 5.0.2 fixed this for me just update twilio to 5.0.2. they just added .ConfigureAwait(false); with CreateAsync

How to pass values to a list in ActiveCampaign using C#

I have a list in ActiveCampaign (Email Marketing API). In there I need to add contacts who have 3 parameters firstName, lastName, email. Those parameters should be passesd to that list using C# console app.
So first I need to access to the ActiveCampaign API using its API Key. And there is also a list ID for that particular list. Then I need to pass values to that list using my C# console app.
Here is my sample code.
Please help me to achieve it
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace ActiveCampaignListAdd
{
class Program
{
private const string URL = "https://osandadeshannimalarathna.api-us1.com";
private string API_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
private static string api_action = "/admin/api.php?api_action=contact_add";
private static string listIDAndStatus = "?listid=2&status=1";
// private string api_output = "Json";
static void Main(string[] args)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(URL);
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// List data response.
HttpResponseMessage response = client.GetAsync(api_action + listIDAndStatus).Result; // Blocking call!
if (response.IsSuccessStatusCode)
{
// Parse the response body. Blocking!
var dataObjects = response.Content.ReadAsAsync<IEnumerable<Contacts>>().Result;
foreach (var d in dataObjects)
{
Console.WriteLine(d.firstName);
Console.WriteLine(d.lastName);
Console.WriteLine(d.email);
}
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
}
}
}
public class Contacts
{
public string firstName { get; set; }
public string lastName { get; set; }
public string email { get; set; }
}
}
There are several free Activecampaign C# libraries available. I would start by picking one... Just search GitHub.

Categories