.net 6 Blazor WebAssembly Deployed to Azure 400 Error when trying to send email via SendGrid - azure-web-app-service

I have a basic Blazor WebAssembly project that is using SendGrid to send form data via email. Locally it works fine. I have deployed to Azure App Service and setup API Management as well.
Locally I set an EnvironmentVariable to hold my SendGrid Api key.
This is the EmailService code.
public async Task<ServiceResponse<Contact>> SendEmail(Contact info)
{
var apiKey = Environment.GetEnvironmentVariable("SENDGRID_API_KEY");
var toEmail = _config.GetSection("SendGrid:EmailTo").Value;
var toName = _config.GetSection("SendGrid:EmailName").Value;
var _subject = _config.GetSection("SendGrid:EmailSubject").Value;
var client = new SendGridClient(apiKey);
var from = new EmailAddress($"{info.Email}", $"{info.Name}");
var subject = _subject;
var to = new EmailAddress(toEmail, toName);
var plainTextContent = info.Message;
var htmlContent = info.Message;
var msg = MailHelper.CreateSingleEmail(from, to, subject, plainTextContent, htmlContent);
var response = await client.SendEmailAsync(msg);
if (response.IsSuccessStatusCode)
{
return new ServiceResponse<Contact>
{
Data = info,
Success = true,
Message = "Message has been sent."
};
}
else
{
return new ServiceResponse<Contact> { Success = false };
}
}
In Azure App Service I created an Application setting named "SENDGRID_API_KEY" and it holds the SendGrid API key. I also tried modifying the request before it is sent and added the Authorization header there as well.
When the form submits, it returns a 400 (Bad Request) error.
I do not have a secure certificate on this site yet.
Any ideas? Please let me know if you need more info.

Related

creating webjob to get status of webjobs of same app service

I am creating one webjob which needs to send mail of status of webjobs. I am using webjob API aka "https://xyz.scm.ase-03.com/api/triggeredwebjobs" to get the webjobs details. I am getting the response from my local httpclient call but while deploying it as a webjob on azure then I am getting null response. Here is my code:
var result = string.Empty;
var url = "https://domain.dev.xyz.com/api/";
var baseURL = "triggeredwebjobs";
string userPswd = "username " + ":" + "password"; // getting username and password from publish profile.
userPswd = Convert.ToBase64String(Encoding.Default.GetBytes(userPswd));
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(url);
client.Timeout = TimeSpan.FromMinutes(30);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",userPswd );
var response = new HttpResponseMessage();
response = client.GetAsync(baseURL).Result; // Here I am getting null value.
result = response.IsSuccessStatusCode ? (response.Content.ReadAsStringAsync().Result) : response.IsSuccessStatusCode.ToString();
}
I am in doubt that calling self webjobs api url maybe not working so I deployed it to another app service but no luck.
Can anyone let me know where is the issue may be?
Thanks in advance.

dotnet Core - Using azure AD authentication to retrive data from sharepoint REST API

My project is set up to use azure ad as login(from the dotnet core template). I have successfully managed to log in.
However, i want to use the same logged in user to retrive data from sharepoint rest api.
I have the following method:
public async Task<FileResults> Test()
{
var siteUrl = "https://xxxxx.sharepoint.com";
var username = "xx#xx.no";
var password = "xxxxxx";
var securePassword = new SecureString();
password.ToCharArray().ToList().ForEach(c => securePassword.AppendChar(c));
var credentials = new SharePointOnlineCredentials(username, securePassword);
var handler = new HttpClientHandler();
handler.Credentials = credentials;
var uri = new Uri(siteUrl);
handler.CookieContainer.SetCookies(uri, credentials.GetAuthenticationCookie(uri));
var json = string.Empty;
using (var client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("Accept", "application/json;odata=verbose");
var response = await client.GetAsync(siteUrl + "/_api/Web/GetFolderByServerRelativeUrl('/Delte%20dokumenter/Test')/Files");
json = await response.Content.ReadAsStringAsync();
var result = Newtonsoft.Json.JsonConvert.DeserializeObject<Rootobject>(json);
var files = result.FileResults;
return files;
}
}
This is working fine and im getting documents from sharepoint.
But, this is when using hardcoded credentials. How do i use the credentials of the logged in user via azure AD? Do i retrive the accesstoken?
To use the Azure AD Authentication you need to have one of the Authentication flows.
Note: Username/Password flow is not recommended.
After that you will be getting the tokens according to the scopes that are specified and you need to hit the Microsoft Graph Api, internally you need to hit the SharePoint API endpoints according to your requirement.
You can start exploring with this sample

Creating a C# Amazon SQS Client in ServiceStack

There is some documentation on using Amazon SQS as an MQ Server forServiceStack Messaging API
But the message publisher is frontend web code and when you dig into the Email Contacts demo app, it is using Rabbit MQ.
There is a ServiceStack Email Contacts AWS App demo but it doesn't use the Messaging API.
Trying to use the Rabbit MQ Integration Test in Email Contacts as an example:
[Test]
public void Can_Send_Email_via_MqClient()
{
var mqFactory = new RabbitMqMessageFactory();
using (var mqClient = mqFactory.CreateMessageQueueClient())
{
mqClient.Publish(new EmailContact { ContactId = 1, Subject = "UnitTest MQ Email #1", Body = "Body 1" });
mqClient.Publish(new EmailContact { ContactId = 1, Subject = "UnitTest MQ Email #2", Body = "Body 2" });
}
}
I quickly confused and lead astray and the ServiceStack API for Sqs seems very different than RabbitMQ. I cannot even seem to be able to use a strongly type POCO as a Message:
[Fact(DisplayName = "Tests that a successful message is published and received")]
public async void TestMessage()
{
var mqFactory = new SqsConnectionFactory("awskey", "awssecret", RegionEndpoint.USWest1);
using (IAmazonSQS mqClient = mqFactory.GetClient())
{
var req = new SendMessageRequest("query", "hello");
await mqClient.SendMessageAsync(req);
//mqClient.Publish(new Hello { Name = "World" });
//var rec = new ReceiveMessageRequest();
//await mqClient.Re
//var responseMsg = mqClient.Get<HelloResponse>(QueueNames<HelloResponse>.In);
//mqClient.Ack(responseMsg);
//responseMsg.GetBody().Result //= Hello, World!
}
}
Is there an example app using the ServiceStack Messaging API with SQS as the MQ Server?
There is a ServiceStack Email Contacts AWS App demo but it doesn't use the Messaging API.
Note AWS Apps does register the AWS SqsMqServer:
//EmailContacts
ConfigureSqsMqServer(container);
//..
private void ConfigureSqsMqServer(Container container)
{
container.Register<IMessageService>(c => new SqsMqServer(
AwsConfig.AwsAccessKey, AwsConfig.AwsSecretKey, RegionEndpoint.USEast1) {
DisableBuffering = true,
});
var mqServer = container.Resolve<IMessageService>();
mqServer.RegisterHandler<EmailContacts.EmailContact>(ExecuteMessage);
mqServer.Start();
}
There's also a number of examples in SqsMqServerTests.cs.
If you want to use ServiceStack MQ's high-level APIs, you'd need to use ServiceStack's MQ classes instead of AWS's SQS classes directly.
Basically it works like every other MQ Server, you can fetch an MQ Client from the IMessageFactory or IMessageService (registered in your AppHost) and use it to publish DTOs:
var mqFactory = HostContext.TryResolve<IMessageFactory>(); //or
//var mqFactory = HostContext.TryResolve<IMessageService>().MessageFactory;
using (var mqClient = mqFactory.CreateMessageQueueClient())
{
mqClient.Publish(new Hello { Name = "World" });
}
Although the preferred API within a ServiceStack Service is to use PublishMessage():
PublishMessage(new Hello { Name = "World" });
Note requests to the /oneway pre-defined endpoint are automatically published to the registered MQ Server.
In client Apps without a registered SqsMqServer you'd create a SqsMqMessageFactory:
var mqFactory = new SqsMqMessageFactory(new SqsQueueManager(...));
using (var mqClient = mqFactory.CreateMessageQueueClient())
{
mqClient.Publish(new Hello { Name = "World" });
}

Create custom extension through Graph API with Client Credentials auth

I have a .NET Web API that I am using to do some interaction with Microsoft Graph and Azure AD. However, when I attempt to create an extension on the user, it comes back with Access Denied.
I know it is possible from the documentation here however, it doesnt seem to work for me.
For the API, I am using client credentials. So my web app authenticates to the API using user credentials, and then from the API to the graph it uses the client.
My app on Azure AD has the Application Permission Read and Write Directory Data set to true as it states it needs to be in the documentation for a user extension.
I know my token is valid as I can retrieve data with it.
Here is my code for retrieving it:
private const string _createApprovalUrl = "https://graph.microsoft.com/beta/users/{0}/extensions";
public static async Task<bool> CreateApprovalSystemSchema(string userId)
{
using(var client = new HttpClient())
{
using(var req = new HttpRequestMessage(HttpMethod.Post, _createApprovalUrl))
{
var token = await GetToken();
req.Headers.Add("Authorization", string.Format("Bearer {0}", token));
req.Headers.TryAddWithoutValidation("Content-Type", "application/json");
var requestContent = JsonConvert.SerializeObject(new { extensionName = "<name>", id = "<id>", approvalLimit = "0" });
req.Content = new StringContent(requestContent, Encoding.UTF8, "application/json");
using(var response = await client.SendAsync(req))
{
var content = await response.Content.ReadAsStringAsync();
ApprovalSystemSchema schema = JsonConvert.DeserializeObject<ApprovalSystemSchema>(content);
if(schema.Id == null)
{
return false;
}
return true;
}
}
}
}
Is there anyone who may have a workaround on this, or information as to when this will be doable?
Thanks,
We took a look and it looks like you have a bug/line of code missing. You appear to be making this exact request:
POST https://graph.microsoft.com/beta/users/{0}/extensions
Looks like you are missing the code to replace the {0} with an actual user id. Please make the fix and let us know if you are now able to create an extension on the user.

I'm trying to send emails using sendgrid in nodejs.But am getting "TypeError: object is not a function" error

Here is my code snippet
var sendgrid = require('sendgrid')('xxxxxx', 'xxxxxx');
var email = new sendgrid.Email();
email.addTo('xyz#gmail.com');
email.setFrom('xyz#gmail.com');
email.setSubject('welcome to send grid');
email.setHtml('<html><body>HELLO evryone ...,</body></html>');
sendgrid.send(email, function(err, json) {
if(!err)
{
console.log("mail sent successssss");
res.send({"status":0,"msg":"failure","result":"Mail sent successfully"});
}
else
{
console.log("error while sending mail")
res.send({"status":1,"msg":"failure","result":"Error while sending mail."});
}
});
Installed sendgrid throgh npm also.am getting "TypeError: object is not a function" error.MAy i know why.??
Version:--
sendgrid#3.0.8 node_modules\sendgrid
└── sendgrid-rest#2.2.1
It looks like you're using sendgrid#3.0.8 but trying to call on the sendgrid#2.* api.
v2 implementation: https://sendgrid.com/docs/Integrate/Code_Examples/v2_Mail/nodejs.html
v3 implementation:
https://sendgrid.com/docs/Integrate/Code_Examples/v3_Mail/nodejs.html
Give the v3 a go.
As for the type error:
v2
var sendgrid = require("sendgrid")("SENDGRID_APIKEY");
you're invoking a function
however you have v3 installed
require('sendgrid').SendGrid(process.env.SENDGRID_API_KEY)
and it's now an object
REQUESTED UPDATE:
I don't know too much about the keys given, but since they have tons of different supported libraries, it's completely possible that some of them use both while others use only one. If you really only have a USER_API_KEY nad PASSWORD_API_KEY, just use the user_api_key
Here is their source for the nodejs implementation module SendGrid:
function SendGrid (apiKey, host, globalHeaders) {
var Client = require('sendgrid-rest').Client
var globalRequest = JSON.parse(JSON.stringify(require('sendgrid-rest').emptyRequest));
globalRequest.host = host || "api.sendgrid.com";
globalRequest.headers['Authorization'] = 'Bearer '.concat(apiKey)
globalRequest.headers['User-Agent'] = 'sendgrid/' + package_json.version + ';nodejs'
globalRequest.headers['Accept'] = 'application/json'
if (globalHeaders) {
for (var obj in globalHeaders) {
for (var key in globalHeaders[obj] ) {
globalRequest.headers[key] = globalHeaders[obj][key]
}
}
}
The apiKey is attached to the header as an auth, and it looks like that's all you need.
Try following their install steps, without your own implementation,
1) (OPTIONAL) Update the development environment with your SENDGRID_API_KEY, for example:
echo "export SENDGRID_API_KEY='YOUR_API_KEY'" > sendgrid.env
echo "sendgrid.env" >> .gitignore
source ./sendgrid.env
========
2) Make this class and if you did the above use process.env.SENDGRID_API_KEY else put your USER_API_KEY
var helper = require('sendgrid').mail
from_email = new helper.Email("test#example.com")
to_email = new helper.Email("test#example.com")
subject = "Hello World from the SendGrid Node.js Library!"
content = new helper.Content("text/plain", "Hello, Email!")
mail = new helper.Mail(from_email, subject, to_email, content)
//process.env.SENDGRID_API_KEY if above is done
//else just use USER_API_KEY as is
var sg = require('sendgrid').SendGrid(process.env.SENDGRID_API_KEY)
var requestBody = mail.toJSON()
var request = sg.emptyRequest()
request.method = 'POST'
request.path = '/v3/mail/send'
request.body = requestBody
sg.API(request, function (response) {
console.log(response.statusCode)
console.log(response.body)
console.log(response.headers)
})

Resources