Track email activity in C# code - c#-3.0

I am using sendgrid to send email. I can see sent mails activities in my sendgrid portal. Now I want track those activities in my c# code. Like what happened to mail - > delivered or bounced or blocked. Is there any solution?

It is possible using Sendgrid Events and it turns out to be rather simple.
Check out https://sendgrid.com/docs/API_Reference/Webhooks/event.html
You can decide how you want the receive the events, in my case I selected JSON.
In your C# web application, you can create a class like:
public class EmailEvent
{
[JsonProperty("sg_message_id")]
public string MessageId { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
[JsonProperty("timestamp")]
public long Timestamp { get; set; }
[JsonProperty("smtp-id")]
public string smtpid { get; set; }
[JsonProperty("event")]
public string Event { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("category")]
public string Category { get; set; }
[JsonProperty("userid")]
public string UserId { get; set; }
}
and a controller action like:
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> IncomingNotification([FromBody] EmailEvent[] events)
{
// be prepared to handle an array of events as sendgrid can send batches
}
You are free to name the action the way you want as long at it matches how you configured the SendGrid webhook.

Related

REST API - appropriate method and route to have child change what its parent resource is

Let's say I have 2 models, Location and Item, that correspond to 2 tables in a database, represented in c# below. Is something like a PATCH request to /items/{itemId} appropriate to change the location id of an item to refer to a different location resource? This is the first time I've been in a situation where I want to change the parent of a resource so I am unsure of the appropriate method and route. I'm working with DTO (data transfer objects) so ideally what I want to do is acceptable so I can have just one DTO patch class for updates to the Item model.
public class Location {
public long Id { get; set; }
public ushort RoomNumber { get; set; }
public string Description { get; set; }
public List<Item> Items { get; set; }
}
public class Item {
public long Id { get; set; }
public string AssetNumber { get; set; }
public string SerialNumber { get; set; }
public long LocationId { get; set; }
public Location Location { get; set; }
}
Given that your url is /items/{itemId} and not something like /location/{locationId}/items/{itemId}, I don't think there's any thing special about changing the locationId versus any other property from a HTTP/Rest perspective.
And PATCH is a good way to make a partial change to a resource.

Nested Properties with Inheritance

Online shop I am working on has entity Order that has member DeliveryDetails.
The purpose of DeliveryDetails is to contain data which is specific to delivery method selected by user (e.g. Shipping or Pick Up From Store), while some details are common for all methods (e.g. Firstname, Lastname, PhoneNumber). I was thinking about structure similar to the following using inheritance:
public class Order {
// ....other props...
public DeliveryMethodType DeliveryMethodType { get; set; }
public DeliveryDetailsBase DeliveryDetails { get; set; }
}
public class DeliveryDetailsBase
{
public int Id { get; set; }
public string CustomerId { get; set; }
public Order Order { get; set; }
public int OrderId { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public string PhoneNumber { get; set; }
}
public class DeliveryDetailsShipping : DeliveryDetailsBase
{
public string Street { get; set; }
public string Building { get; set; }
public string Appartment { get; set; }
public string PostalCode { get; set; }
public string City { get; set; }
public string Country { get; set; }
}
public class DeliveryDetailsPickupFromStore : DeliveryDetailsBase
{
public string StoreCode { get; set; }
}
However, I can't figure out how to make DeliveryDetails prop be assigned to different type of delivery method details depending on what method customer selected and how to fit it in EntityFramework on ASP.Core.
Workarounds I have already tried:
-> (1). Creating "super class" contatining props for ALL delivery methods and populate in db only those that are needed for selected delivery method (selection via setting enum DeliveryMethodType). OUTCOME: works, but with 1 big and ugly table featuring multiple nulls.
-> (2). In Order, creating prop DeliveryDetails which in turn embraces DeliveryDetailsPickupFromStoreDATA & DeliveryDetailsShippingDATA. OUTCOME: works, but with several related tables and quite a lot of ugly code checking selected type from enum, instantiating specific subclass for chosen delivery method and setting to null other unused subclasses.
TO SUM UP: Is there any more elegant and feasible way to organize this?
Is there any more elegant and feasible way to organize this?
Keep it simple, and inheritance isn't usually simple. :)
As a general rule I opt for composition over inheritance. It's easier to work with. Given an order that needs to be delivered to an address or to a store:
public class Order
{
public DeliveryMethod DeliveryMethod { get; set; } = DeliveryMethod.None;
public virtual OrderDeliveryAddress { get; set; } // should never be null.
public virtual OrderDeliveryStore { get; set; } // not null if delivery mode = store.
}
public class Address
{
public string Street { get; set; }
public string Building { get; set; }
public string Appartment { get; set; }
public string PostalCode { get; set; }
public string City { get; set; }
public string Country { get; set; }
}
public class OrderDeliveryAddress
{
public virtual Order Order { get; set; }
public virtual Address Address { get; set; }
}
public class Store
{
public int StoreId { get; set; }
public virtual Address { get; set; }
}
public class OrderDeliveryStore
{
public virtual Order Order { get; set; }
public virtual Store Store { get; set; }
}
Where DeliveryMethod is an Enum. { None = 0, ToAddress, ToStore }
When an order is placed the operator can choose to deliver it to an address, selecting the address of the customer, or entering a new address record; or they can deliver it to a store which can also set the OrderDeliveryAddress to the address of the store. You can establish checks in the database/system to ensure that the data integrity for the delivery method and referenced OrderDeliveryAddress/OrderDeliveryStore are in sync and raise any mismatches that might appear.
One consideration would be that when it comes to deliveries, you will probably want to clone a new Address record based on the customer address, or store address as applicable at the time of ordering rather than referencing their current address record by ID. The reason would be for historical integrity. An order will have been delivered to the address at that point in time, and if a customer address or store address changes in the future, past orders should still show the address that order was delivered.
EF Core has only implemented Table Per Hierarchy (TPH) inheritance.
Table Per Type (TPT) is still an open ticket (not implemented).
Table Per Concrete Type (TPC) is also still an open ticket (not implemented).
So, if TPH meets your requirements, you can follow this guide.
Basically, one table will be used and an extra column called Discriminator will be used to determine which implementation the record corresponds to.
If you are just getting started with Entity, my recommendation would be to not use inheritance and just use nullable columns for data that may or may not be needed depending on the type.

how to Pull data with paramter using Azure Offline Sync?

I have schema as below and I would like to know if I can get all the TaskCategoryMappings by CategoryId when I have to pulll all data. I went through the documentation here but I cant figure out how to do it ? All the examples are like this one based on UserId. but userid is used for also authentication and on the server side I already handle it fine to return only mappings belong to relevant user and i want in adition to filter by CategoryId?
another SO sample is here also using userId Parameter Passing with Azure Get Service
public class TaskCategoryMapping : TableData
{
public string TaskId { get; set; }
public string CategoryId { get; set; }
public string UserId { get; set; }
}
According to your description, I checked this issue on my side and found that it could work as expected, you could follow the details below to check your code:
Backend models:
public class Tag : EntityData
{
public string TagName { get; set; }
public bool Status { get; set; }
}
public class Message : EntityData
{
public string UserId { get; set; }
public string Text { get; set; }
public virtual Tag Tag { get; set; }
[ForeignKey("Tag")]
public string Tag_Id { get; set; }
}
GetAllMessage action:
// GET tables/Message
public IQueryable<Message> GetAllMessage()
{
return Query();
}
For the client, I just invoke the online table for retrieving the message entities as follows:
Model on client-side:
public class Message
{
public string Id { get; set; }
public string UserId { get; set; }
public string Text { get; set; }
public string Tag_Id { get; set; }
}
var result=await mobileServiceClient.GetTable<Message>().Where(msg => msg.Tag_Id == "c3cd4cf8-7af0-4267-817e-f84c6f0e1733").ToListAsync();
For offline table, the pull operation query would
await messageSyncTable.PullAsync($"messages_{userid}", messageSyncTable.Where(m => m.Tag_Id == "<Tag_Id>"));
Use fiddler, you could find that the request would look like this:
https://{your-app-name}.azurewebsites.net/tables/Message?$filter=Tag_Id eq 'c3cd4cf8-7af0-4267-817e-f84c6f0e1733'

Any idea on how to get this id from the conversation between attendee and bot?

Context:
BotFramework (C# SDK) + Messenger channel, bot handles two types of users: attendees (Messenger users) and organizers (who are Facebook Page's admins).
Use case:
When an attendee requests a human support (using an option in my bot's menu), the organizer will receive a message.
In that message, I would like to add a button that will do the following once clicked by the organizer:
stop the automatic replies from the bot to that user
redirect the organizer to Facebook's Page inbox, with the conversation (between the attendee and the bot) selected
What I have done:
I successfully did the part to stop the automatic replies
I got stuck on how to redirect the organizer to the right conversation in FB Page's inbox
Technically:
When I'm looking in Facebook Page, the link that seems to be the one that I should generate for my action is like the following: https://www.facebook.com/mypage-mypageId/inbox/?selected_item_id=someId
My problem is that I can't find this value for selected_item_id from my bot's conversation.
You will be able to get a link to the facebook page inbox (with the right thread) thanks to Facebook Graph API.
/me/conversations must be called to get the conversations of the Page (so you have to give an access_token of the page to the API call).
Then in those results, you have to make a match with the conversation of the attendee. To do this, you can use the property id of the Activity in your bot (Activity.Id, not Activity.Conversation.Id!) as this value is common between your bot and facebook graph results (just need to add "m_" to match): you can find it in one message.id on your Graph API results (careful: not conversation.id)
Then you can get the link value of the Graph API result for this conversation that you found: "link": "\/myBotName\/manager\/messages\/?threadid=10154736814928655&folder=inbox" in my test
Here is a sample of a Dialog that will search for the link for a specific message id:
[Serializable]
public class FacebookGetLinkTestDialog : IDialog<string>
{
public async Task StartAsync(IDialogContext context)
{
context.Wait(MessageReceivedAsync);
}
public async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
var jsonString = "";
var link = "";
using (var client = new HttpClient())
{
using (var response = await client.GetAsync($"https://graph.facebook.com/v2.9/me/conversations?access_token=yourAccessTokenHere").ConfigureAwait(false))
{
jsonString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var conversationList = Newtonsoft.Json.JsonConvert.DeserializeObject<ConversationsRootObject>(jsonString);
link = conversationList.data.Single(c => c.messages.data.Any(d => d.id.Equals("m_" + "yourActivityIdHere"))).link;
}
}
await context.PostAsync($"{link}");
}
}
public class ConversationsRootObject
{
public List<Conversation> data { get; set; }
public Paging paging { get; set; }
}
public class Conversation
{
public string id { get; set; }
public string snippet { get; set; }
public string updated_time { get; set; }
public int message_count { get; set; }
public int unread_count { get; set; }
public Participants participants { get; set; }
public FormerParticipants former_participants { get; set; }
public Senders senders { get; set; }
public Messages messages { get; set; }
public bool can_reply { get; set; }
public bool is_subscribed { get; set; }
public string link { get; set; }
}
public class Participant
{
public string name { get; set; }
public string email { get; set; }
public string id { get; set; }
}
public class Participants
{
public List<Participant> data { get; set; }
}
public class FormerParticipants
{
public List<object> data { get; set; }
}
public class Senders
{
public List<Participant> data { get; set; }
}
public class Messages
{
public List<FbMessage> data { get; set; }
public Paging paging { get; set; }
}
public class FbMessage
{
public string id { get; set; }
public string created_time { get; set; }
}
public class Cursors
{
public string before { get; set; }
public string after { get; set; }
}
public class Paging
{
public Cursors cursors { get; set; }
public string next { get; set; }
}

Entity Framework Core not loading related data

We are developing a new application using ASP.NET Core and EF Core. We're on the latest stable release (v1.1.2). We are unable to load related data via navigation properties.
I am aware that lazy loading is not supported in EF Core but every post on the subject I have looked at suggests that we should be able to explicitly load related data using .Include(). However, this is not working for us and the related entities are always null when we load them in code.
We have two entities - 'Exchange' and 'Trade'. 'Exchange' has a foreign key to 'Trade' and contains a Virtual Trade called Request and another called Offer, thus:-
[Table("Exchange")]
public partial class Exchange : BaseEntity
{
public string Pending { get; set; }
[Display(Name = "Exchange Date"), DataType(DataType.Date)]
public DateTime DateOfExchange { get; set; }
public decimal EstimatedHours { get; set; }
public decimal ActualHours { get; set; }
public string Description { get; set; }
public string FollowUp { get; set; }
public string Status { get; set; }
[ForeignKey("User")]
[Required]
public int Broker_Fk { get; set; }
public virtual User Broker { get; set; }
public int Request_Fk { get; set; }
public virtual Trade Request { get; set; }
public int Offer_Fk { get; set; }
public virtual Trade Offer { get; set; }
I have a View Model that instantiates an 'Exchange' which I know has a related 'Request':-
_vm.Exchanges = _context.Exchange.Include(i => i.Request).Where(t => t.Request.User_Fk == user.Id || t.Offer.User_Fk == user.Id).ToList();
This returns an Exchange, which I am passing to and rendering in the View Model:-
#foreach (var item in Model.Exchanges)
{
<span>#item.Request.Name</span> <br />
}
The problem is that #item.Request is null, even though I have explicitly included it when loading the Exchange. I know that there really is a related entity in existence because one of the other properties on Exchange is its foreign key, which is populated.
What am I missing? Every example I have seen posted suggests that what I've done should work.
Your model attributes are messed up:
[Table("Exchange")]
public partial class Exchange : BaseEntity
{
//...
[ForeignKey("Broker")]
[Required]
public int Broker_Fk { get; set; }
public virtual User Broker { get; set; }
[ForeignKey("Request")]
public int Request_Fk { get; set; }
public virtual Trade Request { get; set; }
//...
}