cannot convert from 'string' to 'SendGrid.Helpers.Mail.EmailAddress' - c#

I am trying to build some basic email functionality within a c# asp.net application. My skills are limited and I am learning.
I am trying to send a list of email addresses to the application. I get the following error when creating the list:
cannot convert from 'string' to 'SendGrid.Helpers.Mail.EmailAddress'
I can see that the list reader is bringing the email address column as a string and I need to convert this to the [SendGrid.Helpers.Mail.EmailAddress] but I have no idea how to do this.
protected async void sendButton_Click(object sender, EventArgs e)
{
// Prepare the email message info model
var apiKey = System.Web.Configuration.WebConfigurationManager.AppSettings["SendGrid_API_Key"];
var client = new SendGridClient(apiKey);
var com = new SqlConnection("Myconn");
com.Open();
string qry = "SELECT EmailAddress FROM MyTable";
var con = new SqlCommand(qry, com);
//var recipients = new List<EmailAddress>{
//new EmailAddress("Recipient1#test.co.uk", "User 1"),
//new EmailAddress("Recipient2#test.co.uk", "User 2") };
List<EmailAddress> columnData = new List<EmailAddress>();
using (SqlCommand command = new SqlCommand(qry, com))
{
using (SqlDataReader bb = command.ExecuteReader())
{
while (bb.Read())
{
columnData.Add(bb.GetString(0));
}
}
}
var msg = new SendGridMessage();
msg.SetFrom(new EmailAddress("Sender#azure.com", "Me"));
var recipients3 = columnData;
msg.AddTos(recipients3);
msg.SetSubject("Without ttttt");
msg.AddContent(MimeType.Text, "Dear Sir or Madam,!");
msg.AddContent(MimeType.Html, "<p>Dear Sir or Madam,!</p>");
var response = await client.SendEmailAsync(msg);
}
}

As pointed out in the comments, you are trying to add a String into a list of email addresses:
while (bb.Read())
{
columnData.Add(bb.GetString(0)); //error is here.
}
What you need to to is create a new object EmailAddress - with your retrieve string as parameter for the EmailAddress constructor:
while (bb.Read())
{
columnData.Add(new EmailAddress(bb.GetString(0)));
}
Edit:
If you have another field in myTable then change your query to:
string qry = "SELECT EmailAddress, Car FROM MyTable";
Create a list to hold the car values:
I have assumed the Car column is a string
var columnDataCar = new List<string>();
Retrive the values:
while (bb.Read())
{
columnData.Add(new EmailAddress(bb.GetString(0)));
columnDataCar.Add(bb.GetString(1);
}
Now columnDataCar holds the data for the Car field.
foreach(var item in columnDataCar)
{
msg.AddContent(MimeType.Text, item);
}
Hope it helps.

Related

Update all null values in column .netcore console app

I've got a console app which updates a column in the database called InstagramId based off user input. I want to be able to query the database and if there's a instagramId which is null, to update it with the correct instagramID based off their instagramUsername.
I wasn't sure on the approach if I should create a fake table based off all the null instagramIds and then use those to update my column or if theres another cleaner approach. This console app is only a one time use so just a quick fix up.
class Program
{
static async Task Main(string[] args)
{
// receive a profile name
var tasks = new List<Task<InstagramUser>>();
foreach (var arg in args)
{
if (string.IsNullOrEmpty(arg)) continue;
var profileName = arg;
var url = $"https://instagram.com/{profileName}";
tasks.Add(ScrapeInstagram(url));
}
try
{
var instagramUsers = await Task.WhenAll<InstagramUser>(tasks);
foreach (var iu in instagramUsers)
{
iu.Display();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
public static async Task<InstagramUser> ScrapeInstagram(string url)
{
using (var client = new HttpClient())
{
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
// create html document
var htmlBody = await response.Content.ReadAsStringAsync();
var htmlDocument = new HtmlDocument();
htmlDocument.LoadHtml(htmlBody);
// select script tags
var scripts = htmlDocument.DocumentNode.SelectNodes("/html/body/script");
// preprocess result
var uselessString = "window._sharedData = ";
var scriptInnerText = scripts[0].InnerText
.Substring(uselessString.Length)
.Replace(";", "");
// serialize objects and fetch the user data
dynamic jsonStuff = JObject.Parse(scriptInnerText);
dynamic userProfile = jsonStuff["entry_data"]["ProfilePage"][0]["graphql"]["user"];
//Update database query
string connectionString = #"Server=mockup-dev-db";
using (SqlConnection con = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand("Update ApplicationUser Set InstagramId = '" + userProfile.id + "'" + "where Instagram = '" + userProfile.username + "'", con);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
// create an InstagramUser
var instagramUser = new InstagramUser
{
FullName = userProfile.full_name,
FollowerCount = userProfile.edge_followed_by.count,
FollowingCount = userProfile.edge_follow.count,
Id = userProfile.id,
url = url
};
return instagramUser;
}
else
{
throw new Exception($"Something wrong happened {response.StatusCode} - {response.ReasonPhrase} - {response.RequestMessage}");
}
}
}
}
}
It seems like there are two problems here
Retrieving a list of username from the DB which have null instagram IDs
For each of these, downloading and populating the instagram ID
It looks like you've already solved 1, so let's look at number 2:
This data can be fetched using an SQL query:
SELECT Instagram FROM ApplicationUser WHERE InstagramId IS NULL
In C# this could look like:
using (SqlConnection con = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand("SELECT Instagram FROM ApplicationUser WHERE InstagramId IS NULL", con);
cmd.Connection.Open();
var instagramUsernames = new List<string>();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
instagramUsernames.Add(reader.GetString(0));
}
}
Now you have all the usernames in the instagramUsernames list and can execute your existing code (with minor modifications) in a foreach loop.
Instead of looping through the args you'd now loop through the list of instagramUsernames (so the above code would come at the start of the Main method):
foreach (var arg in args)
Would become foreach (var arg in instagramUsernames)

Grouping not working as expected returning more emails than should

I have a sales order table with 23 transaction they are assigned to either department 1 or 2 I have looked at the data and its has the right assigns to it based on the cateory name however the problem is in my exucuation of the loop as I am getting 23 emails instead of just 5 sales order emails which is what it should be
Say for Example The table is
SalesOrder Number Depart
1111 1
1111 2
2222 2
2222 2
I should be getting one email for sales order 1111 sent to department 1 and one sent to department 2 but in the 2222 case I should get one email including all 2222
I think the issue is the group by does not no how to batch and I am asking what is the best way of doing that.
public void ProcessTransactions(string csvFileName)
{
var engine = new FileHelperEngine<SalesOrderHeader>();
var SalesOrders = engine.ReadFile(csvFileName);
var engine2 = new FileHelperEngine<SalesOrdersLines>();
var OrderLines = engine2.ReadFile(csvFileName);
GetSalesOrdersForImport();
ImportTransActions(SalesOrders.ToList());
CreateSalesOrder(_salesOrders.ToList(), _salesOrders.ToList());
var groupedSalesOrders = SalesOrders.OrderBy(x => x.SalesOrderNumber)
.GroupBy(x => x.SalesOrderNumber);
foreach(var group in groupedSalesOrders)
{
foreach (var item in group)
{
GetEmailsFromDepartment(item.DepartmentId);
GetSalesOrdersByDepartment(item.DepartmentId);
SendEmailNotificationPerDepartments(item.SalesOrderNumber.ToString());
}
}
}
My Get Emails for Department function is as below
public List<EmailDepartMents> _emailListsByDepartment { get; set; }
public void GetEmailsFromDepartment(string departmentId )
{
string connectionString = ConfigurationManager.AppSettings["connectionString"];
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
string selectQuery = #"SELECT [Code]
,[Name]
,[U_DepartmentId] AS DepartmentId
,[U_CardCode] as CardCode
,[U_Email] As Email
FROM [NKCoatings].[dbo].[#FIT_DEPARTMENTS]
where [U_DepartmentId]='" + departmentId +"'";
_emailListsByDepartment = connection.Query<EmailDepartMents>(selectQuery).ToList();
}
}
}
Edit 2
To Show send email function in case there is a issue with it in it self.
public void SendEmailNotificationPerDepartments(List SalesOrders)
{
try
{
SAPbobsCOM.UserTable sboTable = (SAPbobsCOM.UserTable)company.UserTables.Item("DEPARTMENTS");
SAPbobsCOM.BusinessPartners sboBP = (SAPbobsCOM.BusinessPartners)company.GetBusinessObject(SAPbobsCOM.BoObjectTypes.oBusinessPartners);
string emailAddressCC = ConfigurationManager.AppSettings["EmailAddressTo"];
string body;
string stmpServer = ConfigurationManager.AppSettings["SmtpAddress"];
string EmailUserName = ConfigurationManager.AppSettings["EmailUserName"];
string EmailPassword = ConfigurationManager.AppSettings["EmailPassword"];
string SmtpPort = ConfigurationManager.AppSettings["SmtpPort"];
MailMessage Msg = new MailMessage();
Msg.From = new MailAddress("development#test.com");
Msg.IsBodyHtml = true;
Msg.Subject = "Sales Orders Created in SAP";
body = "Sales orders has been imported into sap";
StringBuilder sb = new StringBuilder();
using (Html.Table table = new Html.Table(sb, id: "some-id"))
{
table.StartHead();
using (var thead = table.AddRow())
{
thead.AddCell("Works Order Number");
thead.AddCell("Purchase Order Number");
thead.AddCell("Date Required");
thead.AddCell("Stock Item Code");
thead.AddCell("Stock Item Name");
thead.AddCell("Customer");
}
table.EndHead();
table.StartBody();
foreach (var order in SalesOrders.Where(w=>w.DepartmentId == DepartmentId && w.SalesOrderNumber ==salesOrderId).OrderBy(o=>o.SalesOrderNumber))
{
using (var tr = table.AddRow(classAttributes: "someattributes"))
{
tr.AddCell(order.WorksOrderNumber, "style:font-bold;");
tr.AddCell(order.PurchaseOrderNumber.ToString());
tr.AddCell(order.DateRequired.ToString());
tr.AddCell(order.ItemCode.ToString());
tr.AddCell(order.Description.ToString());
if(sboBP.GetByKey(order.CardCode))
{
sboBP.CardName.ToString();
}
}
}
}
foreach (var address in _emailListsByDepartment)
{
Msg.To.Add(address.Email);
}
foreach (var address in emailAddressCC.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries))
{
Msg.CC.Add(address);
}
body = body + Environment.NewLine + sb.ToString();
Msg.Body = body;
SmtpClient smtp = new SmtpClient(stmpServer);
smtp.Credentials = new NetworkCredential(EmailUserName, EmailPassword);
smtp.Host = stmpServer;
smtp.Port = Convert.ToInt16(SmtpPort);
smtp.Send(Msg);
}
catch (Exception ex)
{
log.Error("Error has occoured at the send email notification " + ex.ToString());
}
}
I think i am just having a saturday night black out here but I hope someone can help me out maybe I am doing something wrong.
It could look something like this:
var list = new List<Email>()
{
new Email() {SalesOrderNumber = 10, Depart = 1},
new Email() {SalesOrderNumber = 10, Depart = 2},
new Email() {SalesOrderNumber = 20, Depart = 2},
new Email() {SalesOrderNumber = 20, Depart = 2},
};
var groups = list.GroupBy(e => e.SalesOrderNumber) // sort all emails by SalesOrderNumber
.Select(g => g.GroupBy(e => e.Depart)) // sort groups by Depart
.Aggregate((l, r) => l.Concat(r)); // aggregate result to only one collection of groups
foreach (var group in groups)
{
Console.WriteLine($"Group of SalesOrderNumber: {group.First().SalesOrderNumber}, Depart: {group.Key}");
foreach (var email in group)
{
Console.WriteLine(email);
}
}

How to check linq query result against Sql Server Database for data already exist or not?

I am using active directory for getting all the departsment and filtering distinct departments using linq query, below is my code
private static DomainController GetDomainController(string domainpath)
{
var domainContext = new DirectoryContext(DirectoryContextType.Domain, domainpath);
var domain = Domain.GetDomain(domainContext);
var controller = domain.FindDomainController();
return controller;
}
private static MyMethod()
{
var domainController = GetDomainController(ActiveDirectorySettings.DomainPath);
// Lookup the information in AD
var ldapEntry = new DirectoryEntry(string.Format("LDAP://{0}", domainController)) { AuthenticationType = AuthenticationTypes.Secure | AuthenticationTypes.FastBind };
DirectorySearcher ds;
ds = new DirectorySearcher(ldapEntry)
{
SearchScope = SearchScope.Subtree,
Filter = "(&" + "(objectClass=user)" + "(department=" + departmentname + "*))"
};
ds.PropertiesToLoad.Add("department");
if (ds.FindAll().Count >= 1)
{
//DataSet du = DataReader.CheckAdUserExist();
var results = ds.FindAll();
var uniqueSearchResults = results.Cast<SearchResult>().Select(x => GetProperty(x,"department")).Distinct();
addUsersList.AddRange(uniqueSearchResults.Select(departmentName => new UsersAndDepartments
{
UserDepartment = departmentName
}));
}
}
I want to check the linq query result with the database whether department already exist or not, I am not sure how to do that?
If what you want is to create a simple database connection using SqlConnection you just need to query your DB using the department parameter you received from your AD request.
try{
SqlConnection connection = new SqlConnection("YourConnectionstring");
connection.Open();
//Your connection string can be found through your Server DB
//Now you go through your SearchResultCollection populated by SearchResult objects
foreach(SearchResult res in uniqueSearchResult){
SqlCommand cmd = new SqlCommand("Select * from yourTable where department=" +res.Properties["department"][0].ToString() + "", connection);
SqlDataReader reader = cmd.ExecuteReader();
//Here you verify if there are corresponding rows in your table
//with the request you have executed
if(!reader.HasRows()){
//If you have not found corresponding rows, then you add the department to your
//list
addUsersList.Add(res.Properties["department"][0].ToString());
}
}
connection.close();
}catch(Exception e){
Console.WriteLine("Exception caught : \n\n" + e.ToString();
}
This should work.
There are plenty of tutorials for this, but if you are making alot of requests I do not recommend using this connection method you will just lose too much time / organization, maybe try using a persistence Framework like Entity Framework :
https://www.codeproject.com/Articles/4416/Beginners-guide-to-accessing-SQL-Server-through-C
Hope this answers your question!
Here is my solution, I have solved it myself
private static DomainController GetDomainController(string domainpath)
{
var domainContext = new DirectoryContext(DirectoryContextType.Domain, domainpath);
var domain = Domain.GetDomain(domainContext);
var controller = domain.FindDomainController();
return controller;
}
private static MyMethod()
{
var domainController = GetDomainController(ActiveDirectorySettings.DomainPath);
// Lookup the information in AD
var ldapEntry = new DirectoryEntry(string.Format("LDAP://{0}", domainController)) { AuthenticationType = AuthenticationTypes.Secure | AuthenticationTypes.FastBind };
DirectorySearcher ds;
ds = new DirectorySearcher(ldapEntry)
{
SearchScope = SearchScope.Subtree,
Filter = "(&" + "(objectClass=user)" + "(department=" + departmentname + "*))"
};
ds.PropertiesToLoad.Add("department");
if (ds.FindAll().Count >= 1)
{
// getting list of all departments from the database
var departmentsList = AllDepartments();
// getting list of all departments from active directory
var results = ds.FindAll();
// filtering distinct departments from the result
var uniqueSearchResults = results.Cast<SearchResult>().Select(x => GetProperty(x,"department")).Distinct();
// here firstly i am getting the department list from the database and checking it for null, then using linq query i am comparing the result with ad department results
if (departmentsList != null)
{
addUsersList.AddRange(from sResultSet in uniqueSearchResults
where !departmentsList.Exists(u => u.UserDepartment == sResultSet)
select new UsersAndDepartments
{
UserDepartment = sResultSet
});
}
else
{
addUsersList.AddRange(uniqueSearchResults.Select(departmentName => new UsersAndDepartments
{
UserDepartment = departmentName
}));
}
}
}

Rally .NET: Query for project admins that belong to a specific project?

I am looking for a List object that is populated with project admins for a specific project that is within a specific workspace.
Would like some sample code that can query the API for to retrieve all the project admins email addresses.
Here is some sample code I have tried.
public void getProjectAdmins(string workspaceRef, string projectRef)
{
this.EnsureRallyIsAuthenticated();
Request projectAdminRequest = new Request("User");
projectAdminRequest.Workspace = workspaceRef;
projectAdminRequest.Project = projectRef;
projectAdminRequest.ProjectScopeUp = RallyConstant.ProjectScopeUp;
projectAdminRequest.ProjectScopeDown = RallyConstant.ProjectScopeDown;
projectAdminRequest.Fetch = new List<string>()
{
"Admin", "Email"
};
try
{
//query the items in the list
projectAdminRequest.Query = new Query();
QueryResult result = _rallyRestApi.Query(projectAdminRequest);
//iterate through the result set
foreach (var admin in result.Results)
{
var adminResult = admin[RallyConstant.Owner];
if (adminResult != null)
{
var x = adminResult[RallyQueryConstant.ReferenceObject];
}
}
}
catch (WebException)
{
Console.WriteLine(RallyQueryConstant.WebExceptionMessage);
}
}
You should be able to query the ProjectPermission endpoint filtered to your project in question like so:
Request projectAdminRequest = new Request("ProjectPermission");
projectAdminRequest.Workspace = workspaceRef;
projectAdminRequest.Fetch = new List<string>() {"User", "EmailAddress"};
projectAdminRequest.Query = Query.And(
new Query("Project", Query.Operator.Equals, "/project/12345"),
new Query("Role", Query.Operator.Equals, "Project Admin"));
Fetching User and EmailAddress should include the data you're looking for in your request.

Check if a string contains a value within a generic list and replace it

I have a string with a message containing some fields I want to swap out to actual values
var message = "Hi [CustomerName]. Its [TODAY], nice to see you were born on the [DOB]!";
var mappingCodes = new List<string> {"[CUSTOMER_NAME]","[DOB]",[TODAY]};
var customEmails = new Dictionary<string, string>();
var today = DateTime.Now;
var customers = new List<Customer>()
{
new Customer()
{
FirstName = "Jo",
LastName = "Bloggs",
Email = "jo#bloggs.com",
DOB = "10/12/1960"
}
};
foreach (var customer in customers)
{
var emailMessage = "";
customEmails.Add(customer.Email,emailMessage);
}
What I'm trying to do is loop through each of the customers and take the message replacing any of the mappingCodes with actual codes.
e.g. [Today] Would be the today and CustomerName would be Customer.FirstName + Customer.LastName
There could be 1000's of customers so I need something robust. I'm just not sure how to first check the string contains any of the mappingCodes and then replace them with the desired values.
Any advice?
You could try something like this. String.Format is rather efficient. It also would allow you to format Date.Today, if you want.
var customers = new List<Customer>()
{
new Customer()
{
FirstName = "Jo",
LastName = "Bloggs",
Email = "jo#bloggs.com",
DOB = "10/12/1960"
}
};
foreach (var customer in customers)
{
var emailMessage = String.Format("Hi {0}. Its {1}, nice to see you were born on the {2}!", customer.FirstName, DateTime.Today, customer.DOB);
customEmails.Add(customer.Email,emailMessage);
}
You can use Regex.Replace(string, MatchEvaluator):
var customers = new[] {
new {
Name = "Fred Flintstone",
City = "Bedrock"
},
new {
Name = "George Jetson",
City = "Orbit City"
}
};
string template = "Hello, [NAME] from [CITY]!";
var re = new Regex(#"\[\w+\]"); // look for all "words" in square brackets
foreach (var customer in customers)
{
Trace.WriteLine(
re.Replace(template, m => {
// determine the replacement string
switch (m.Value) // m.Value is the substring that matches the RE.
{
// Handle getting and formatting the properties here
case "[NAME]":
return customer.Name;
case "[CITY]":
return customer.City;
default:
// The "mapping code" is not supported, I just return the
// original substring
return m.Value;
}
}));
}
Obviously the above is just the general approach, you'll have to modify it to support your mapping codes and data structures.

Categories