This is how I send my email:
public async System.Threading.Tasks.Task<string> SendInternalEmail(BasicEmailStructureViewModel Structure, List<string> AdditionalVariables, TenantEmailTemplate tenantEmailTemplate, TenantCommunication tenantCommunication, string ReceiverId, string ReceiverEmail, string ReceiverName, string CampaignName)
{
try
{
var client = new SendGridClient(tenantCommunication.SendgridApiKey);
var message = new SendGridMessage();
message.SetFrom(new EmailAddress(tenantCommunication.SendgridPrimarySender, tenantCommunication.SendgridPrimarySenderTag));
message.AddTo(new EmailAddress(ReceiverEmail, $"{ReceiverName}"));
message.Subject = tenantEmailTemplate.Subject;
message.SetTemplateId(tenantEmailTemplate.TemplateId);
List<string> jsonVars = new List<string>();
var subjectString = #$"""subject"":""{tenantEmailTemplate.Subject}""";
jsonVars.Add(subjectString);
foreach (PropertyInfo prop in Structure.GetType().GetProperties())
{
var variableString = #$"""{prop.Name}"":""{prop.GetValue(Structure, null)}""";
}
for (var i = 0; i < AdditionalVariables.Count; i++)
{
jsonVars.Add(AdditionalVariables[i]);
}
var flattenList = "{" + string.Join(",", jsonVars) + "}";
var emailData = Newtonsoft.Json.JsonConvert.DeserializeObject<object>(flattenList);
message.SetTemplateData(emailData);
if (CampaignName != null && CampaignName != "")
{
message.AddCustomArg("CampaignName", CampaignName);
}
var response = await client.SendEmailAsync(message);
if (response.IsSuccessStatusCode == true)
{
return Guid.NewGuid().ToString();
}
else
{
var errorMessage = response.Body.ReadAsStringAsync().Result;
return errorMessage;
}
}
catch(Exception e)
{
if (e != null)
{
return e.Message;
}
}
return "Invalid Email";
}
A typical input to this function will be like this:
var variableString =
#$"""verification_link"":""www.website.com?Key={Input.Key}""";
My email sends normally, however, none of the variables that I have set have been sent through. This is based roughly off the template sample on github: https://github.com/sendgrid/sendgrid-csharp/blob/main/examples/templates/templates.cs
Is there another sample I can use or what is the correct way to send variables dynamically?
I don't think that is the best way to construct the JSON for your dynamic template variables.
Would it be possible for you to build the variables as an object and then serialize them. Like:
var templateData = new {
subject = tenantEmailTemplate.Subjectm
otherVariableName = otherVariable
};
string emailData = JsonConvert.SerializeObject(templateData);
message.SetTemplateData(emailData);
Related
I have an email template, and in the template, I am replacing some fields passed.
But when I send the mail, the fields being replaced are empty.
On the point of returning the mailtext, when I verify, the fields are properly populated.
I'll be glad if i can get help regarding this.
Please see a snapshot
`
public static string transfer;
public static string airtime;
public static string bills;
public async static Task<string> GetMail(string userName, Goal goal, GoalEvent action)
{
var assembly = Assembly.GetAssembly(typeof(MailHelper));
string title, introText;
string mailText;
Stream stream;
if (action == GoalEvent.SpendActivate)
{
stream = assembly.GetManifestResourceStream("activate.html");
title = "Activated";
introText = $"You have just activated.";
}
else if (action == GoalEvent.SpendCashout)
{
stream = assembly.GetManifestResourceStream("cashout.html");
title = "SpendCashout";
introText = $"Congratulations! You have just been credited {goal.SpendDuration}";
}
else if (action == GoalEvent.SpendDeactivate)
{
stream = assembly.GetManifestResourceStream("deactivate.html");
title = "SpendDeactivated";
introText = $"You have just deactivated";
}
else if (action == GoalEvent.SpendEdit)
{
stream = assembly.GetManifestResourceStream("edit.html");
title = "Updated";
introText = $"You have just successfully updated the details";
}
else if (action == GoalEvent.SpendTopUp)
{
stream = assembly.GetManifestResourceStream("topup.html");
title = "TopUp Successful";
introText = $"We have successfully added NGN {goal.amountSaved}";
}
else
{
return String.Empty;
}
using (var reader = new StreamReader(stream, Encoding.UTF8))
{
mailText = await reader.ReadToEndAsync();
}
if (goal.OnAirtime) airtime = "Airtime and Data";
if (goal.OnBills) bills = "Bills";
if (goal.OnTransfer) transfer = "Transfer";
return ReplaceKeys(mailText,
("title", title),
("date", DateTime.UtcNow.AddHours(1).ToString("dd MMMM yyyy")),
("userName", userName),
("introText", introText),
("duration", goal.Duration.ToString()),
("percentage", goal.Percentage.ToString()),
("transactionTypes", $"{airtime ?? ""}, {bills ?? ""}, {transfer ?? ""}"),
("amountSaved", goal.amountSaved.ToString()),
("interest", goal.interestAccrued.ToString()),
("total", $"{goal.amountSaved + goal.interestAccrued}")
);
}`
please pardon some typos.
My one template is not replacing dynamics data in the email
My Code is given below
public static System.Net.HttpStatusCode SendEmailV2(DynamicsModel dynamicsmodel, string templateId, TraceWriter log)
{
log.Info("Executing SendEmailV2");
var SendGridApiCode = System.Environment.GetEnvironmentVariable("SendGridApiCode", EnvironmentVariableTarget.Process);
var fromEmail = System.Environment.GetEnvironmentVariable("FromEmail", EnvironmentVariableTarget.Process);
var fromName = System.Environment.GetEnvironmentVariable("FromName", EnvironmentVariableTarget.Process);
var dynamicTemplateData = new DynamicData
{
Name = dynamicsmodel.FullName
};
string output = JsonConvert.SerializeObject(dynamicTemplateData);
log.Info("json:" + output);
EmailAddress from = new EmailAddress(fromEmail, "test name");
EmailAddress to = new EmailAddress(dynamicsmodel.Email, dynamicsmodel.FullName);
var sendGridClient = new SendGridClient(SendGridApiCode);
var sendGridMessage = CreateSingleTemplateEmail(from, to, templateId, dynamicTemplateData);
var response = sendGridClient.SendEmailAsync(sendGridMessage).Result;
if (response.StatusCode == System.Net.HttpStatusCode.Accepted)
{
log.Info("Emails Sent from SendGrid");
}
else
{
log.Info("response.StatusCode:" + response.StatusCode.ToString());
}
return response.StatusCode;
}
My JSON which is being passed is given below
{"name":"Test User"}
This happens to one template only. Any help will be much appreciated
I've got a method that returning back from CompletionService.GetDescriptionAsync(Document, CompletionItem) gives me the following description:
void SQL.GetSQLiteDB(string url) (+ 1 overload)
This is a method I made on a Xamarin project, here are both method signatures:
public static void GetSQLiteDB(string url);
public static string GetSQLiteDB(string url, string name);
What's the Roslyn way to get information on both?
Here's how I'm setting up completions:
async Task InitCodeCompletion()
{
host = MefHostServices.Create(MefHostServices.DefaultAssemblies);
workspace = new AdhocWorkspace(host);
Type[] types =
{
typeof(object),
typeof(System.Linq.Enumerable),
typeof(System.Collections.IEnumerable),
typeof(Console),
typeof(System.Reflection.Assembly),
typeof(List<>),
typeof(Type),
typeof(SQL)
};
imports = types.Select(x => x.Namespace).Distinct().ToImmutableArray();
assemblies = types.Select(x => x.Assembly).Distinct().ToImmutableArray();
references = assemblies.Select(t => MetadataReference.CreateFromFile(t.Location) as MetadataReference).ToImmutableArray();
compilationOptions = new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary,
usings: imports);
projectInfo = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), "Script", "Script", LanguageNames.CSharp, isSubmission: true)
.WithMetadataReferences(references).WithCompilationOptions(compilationOptions);
project = workspace.AddProject(projectInfo);
documentInfo = DocumentInfo.Create(DocumentId.CreateNewId(project.Id), "Script", sourceCodeKind: SourceCodeKind.Script,
loader: TextLoader.From(TextAndVersion.Create(SourceText.From(""), VersionStamp.Create())));
document = workspace.AddDocument(documentInfo);
var services = workspace.Services;
completionService = CompletionService.GetService(document);
}
async Task<CodeCompletionResults> GetCompletions(string code)
{
string codeModified = "using SQL = XamTestNET5.Services.SQLiteGeneratorService; " + Environment.NewLine;
codeModified += "using HtmlSvc = XamTestNET5.Services.HtmlRetrievalService;" + Environment.NewLine;
// ^^^ The above two lines set up some simple namespace aliases in my project, if you know how to put this in a separate project document and use it in code completion please let me know in comments as otherwise doing so gives me an exception that you can't have multiple syntax trees
codeModified += code;
var source = SourceText.From(codeModified);
document = document.WithText(source);
// cursor position is at the end
var position = source.Length;
var completions = await completionService.GetCompletionsAsync(document, position);
return new CodeCompletionResults() { InputCode = code, ModifiedCode = codeModified, Completions = completions };
}
Here's how I'm getting them now and putting them in a browser control:
private async void CSharpShellEnvironment_EntryCodeCompletionEntry(object sender, CSharpShellEnvironment.EntryEventArgs e)
{
if (e.Value != "")
{
CodeCompletionResults results = await GetCompletions(e.Value);
CompletionList list = results.Completions;
if (list != null)
{
if (list.Items != null)
{
StringBuilder sb = new StringBuilder();
foreach (var item in list.Items)
{
string spanText = (item.Span.Start != item.Span.End) ? results.ModifiedCode.Substring(item.Span.Start, item.Span.Length) : "";
bool recommended = spanText == "" ? true : item.DisplayText.StartsWith(spanText);
if (recommended)
{
string fText = item.DisplayText.Substring(spanText.Length);
string props = "";
foreach(var p in item.Properties)
{
props += $"<span data-key=\"{p.Key}\" data-value=\"{p.Value}\"></span>";
}
string tags = "";
foreach(var t in item.Tags)
{
tags += $"<span data-tag=\"{t}\"></span>";
}
string descStr = "";
if (item.Tags != null)
{
if (item.Tags.Where(x => x.ToLower() == "method").FirstOrDefault() != null && item.Tags.Where(x => x.ToLower() == "public").FirstOrDefault() != null)
{
var desc = await completionService.GetDescriptionAsync(document, item);
descStr += $"<span data-desc=\"{desc.Text}\">";
foreach(var part in desc.TaggedParts)
{
descStr += $"<span data-desc-part-tag=\"{part.Tag}\" data-desc-part-text=\"{part.Text}\"></span>";
}
descStr += "</span>";
}
}
sb.AppendLine($"<div class=\"codecompleteentry\" data-display-text=\"{item.DisplayText}\" data-span-text=\"{spanText}\" data-final-text=\"{fText}\">{props}{tags}{descStr}{fText}</div>");
}
}
string scriptInputClick = "Array.prototype.forEach.call(document.getElementsByClassName('codecompleteentry'), function(el) { el.addEventListener('click', function(elem) { var text = { MessageType: 'CodeCompletion', Parameters: JSON.stringify({ DataDisplayText: el.getAttribute('data-display-text'), DataSpanText: el.getAttribute('data-span-text'), DataFinalText: el.getAttribute('data-final-text') }), Message: el.innerText }; window.chrome.webview.postMessage(text); } ); });";
sb.AppendLine($"<script type=\"text/javascript\">{scriptInputClick}</script>");
env.EnterCodeCompletionResponse(sb.ToString());
}
else
{
env.EnterCodeCompletionResponse(strNoSuggestions);
}
}
else
{
env.EnterCodeCompletionResponse(strNoSuggestions);
}
}
else
{
env.EnterCodeCompletionResponse(strNoSuggestions);
}
}
It seems on the surface that CompletionSurface has everything you need, but it doesn't, you need to reference the Document's SemanticModel in order to get all of the signature overloads of a method when the user types ( on a method during code completion.
It wasn't very obvious to me until I started looking through the RoslynPad source, which I recommend doing for a practical example: https://github.com/aelij/RoslynPad
List<IEnumerable<ReferencedSymbol>> allMethodRefs = new List<IEnumerable<ReferencedSymbol>>();
async Task<CodeCompletionResults> GetCompletions(string code)
{
string codeModified = "using SQL = XamTestNET5.Services.SQLiteGeneratorService; " + Environment.NewLine;
codeModified += "using HtmlSvc = XamTestNET5.Services.HtmlRetrievalService;" + Environment.NewLine;
// ^^^ I put my namespace aliases in the same SyntaxTree for now,
// I'd like a better solution though.
codeModified += code;
var source = SourceText.From(codeModified);
document = document.WithText(source);
// cursor position is at the end
var position = source.Length;
var completions = await completionService.GetCompletionsAsync(document, position);
syntaxRoot = await document.GetSyntaxRootAsync();
semanticModel = await document.GetSemanticModelAsync();
var methods = syntaxRoot.DescendantNodes().OfType<InvocationExpressionSyntax>();
allMethodRefs = new List<IEnumerable<ReferencedSymbol>>();
if (methods != null)
{
if (methods.Count() > 0)
{
foreach(var m in methods)
{
var info = semanticModel.GetSymbolInfo(m);
if (info.Symbol != null)
{
allMethodRefs.Add(await SymbolFinder.FindReferencesAsync(info.Symbol, solution));
}
else
{
foreach(var symbol in info.CandidateSymbols)
{
allMethodRefs.Add(await SymbolFinder.FindReferencesAsync(symbol, solution));
}
}
}
}
}
return new CodeCompletionResults() { InputCode = code, ModifiedCode = codeModified, Completions = completions };
}
I am using PushSharp 4.0.10.0 library to send the notification on iOS devices but it's not working. I have debugged it and found there is some ApnsConfiguration connection problem.
I am using this code to send the notificaiton:
public IHttpActionResult Notify()
{
HttpResponseMessage response = new HttpResponseMessage();
HttpContent requestContent = Request.Content;
string errorMessage = "Some error occured.please try again later";
HttpStatusCode responseCode = HttpStatusCode.Unauthorized;
string requestParameter = requestContent.ReadAsStringAsync().Result;
string tokan = "";
var r = Request;
var header = r.Headers;
try
{
if (requestParameter != null)
{
PushNotificationModel complaintModel = JsonConvert.DeserializeObject<PushNotificationModel>(requestParameter);
JsonConvert.DeserializeObject<PushNotificationModel>(requestParameter);
var appleCert = File.ReadAllBytes(HttpContext.Current.Server.MapPath("~/Images/User/xyz.pem"));
var config = new ApnsConfiguration(ApnsConfiguration.ApnsServerEnvironment.Production,
appleCert, "xyz");
// Create a new broker
var push = new ApnsServiceBroker(config);
int DeviceType = 1;
string deviceId = Convert.ToString(complaintModel.deviceToken);
string message = "New notification!!";
Guid complaintId = complaintModel.ComplaintId;
string detail = complaintModel.detail;
try
{
//System.Web.Hosting.HostingEnvironment.MapPath("~/Images/User/")
// var appleCert = File.ReadAllBytes(HttpContext.Current.Server.MapPath("~/Images/User/CTPwd.pem"));
push.OnNotificationFailed += (notification, aggregateEx) =>
{
aggregateEx.Handle(ex =>
{
// See what kind of exception it was to further diagnose
if (ex is ApnsNotificationException)
{
message = ex.Message;
}
else
{
message = "Not an APNSException";
}
// Mark it as handled
return true;
});
};
try
{
push.OnNotificationSucceeded += (notification) =>
{
message = "New Notification";
};
push.Start();
string appleJsonFormat = "{\"aps\": {\"alert\":" + '"' + message + '"' + ",\"sound\": \"default\"}}";
//string appleJsonFormat = "{\"aps\": {\"alert\": " + "Hello World" + ",\"sound\": \"default\"}}";
push.QueueNotification(new ApnsNotification
{
DeviceToken = deviceId,
Payload = JObject.Parse(appleJsonFormat)
});
push.Stop();
}
catch(Exception ex)
{
}
I have searched on google, but did not find any relevant answer. Is there any syntax problem ?
Thanks in advance.
Please use .P12 file format for push notification happy coding:)
I am trying validate Google Account using WebClient.
class PostDataBuilder
{
private static Dictionary<string, string>
ToPropertyDictionary(object data)
{
var values = data
.GetType()
.GetProperties()
.Select(x => new {
Key = x.Name,
Value = x.GetValue(data, null)
});
var result = new Dictionary<string, string>();
foreach (var item in values)
result.Add(item.Key, item.Value.ToString());
return result;
}
public static string Build(object data)
{
string result = "";
var dict = ToPropertyDictionary(data);
foreach (var name in dict.Keys)
result += name + "=" + HttpUtility.UrlEncode(dict[name]) + "&";
return result.Substring(0, result.Length - 1);
}
}
class Program
{
static void Main(string[] args)
{
string postText = PostDataBuilder.Build(
new
{
dsh = "-1903339439726094408",
GALX = "-Ggrv6gqusk",
timeStmp = "",
secTok = "",
Email = "WrongEmail#gmail.com",
Passwd = "WrongPassword",
signIn = "?????",
rmShown = "1"
});
byte[] data = Encoding.UTF8.GetBytes(postText);
WebClient wc = new WebClient();
byte[] result = wc.UploadData(
new Uri("https://accounts.google.com/ServiceLoginAuth"),
"POST", data);
string resultText = Encoding.UTF8.GetString(result);
}
}
ResultText variable has setted , even if data is correct. What's wrong?
You shouldn't ever screw around with login services such as the Google one or try to fake a browser. In the end it could be considered attempt hacking or whatever and it's very likely to break the next time they update their page (or even just because your IP changes).
Instead use OpenID or OAuth as described here.