I'm creating a MVC Core app and deploying it to an Azure App Service. I'm trying to send emails using SendGrid from the application which seems to be working fine in my local environment but does not work in production. I'm using free subscriptions for anything Azure.
I've followed this pretty much to the tee.
This type of question has popped up on stack overflow and github (here and here, etc), but after going through about 50 such posts nothing seems to be working for me. Reading through the documentation in SendGrid doesn't help a lot either because all the examples provided looks like my own code. I don't get any exceptions, and like I mentioned it works just fine locally.
Please help
Code
string sendGridApiKey = _configuration["SENDGRID_API_KEY"];
var client = new SendGridClient(sendGridApiKey);
var msg = new SendGridMessage();
msg.SetFrom(new EmailAddress(email: "management#enr.com",
name: "ENR Management"));
msg.AddTo(new EmailAddress(email: user.Email, name: user.FriendlyName));
msg.SetSubject("Reset Password");
msg.AddContent(MimeType.Html, $"Please reset your password by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'> clicking here </a>.");
msg.AddContent(MimeType.Text, "Please reset your password by clicking the link");
var response = await client.SendEmailAsync(msg).ConfigureAwait(false);
Being called by
_emailService.SendResetPasswordEmail(
user: user,
callbackUrl: callbackUrl).Wait();
appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "XXX",
"ENRModelsDB": "XXX"
},
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"SENDGRID_API_KEY": "SG.XXX",
"AllowedHosts": "*"
}
I also have the same key/value in my App Service in Azure under Configuration -> Application setting for what it's worth.
Could it be that your App Service has the configuration setup with different value?
Another suggestion to you is you to debug your app running in the App Service to see what exactly is happening.
Introduction to Remote Debugging on Azure Web Sites
*it is old but it will give you the idea.
I finally found the issue and I feel so stupid.
I only send 1 email from my app, the password reset email. On my live environment, it would fail at this step in ForgotPassword.cshtml.cs (the scaffolded page)
if (user == null || !(await _userManager.IsEmailConfirmedAsync(user)))
{
// Don't reveal that the user does not exist or is not confirmed
return RedirectToPage("./ForgotPasswordConfirmation");
}
because when I seeded the user I did not set email confirmed to be true.
Could not have done it without the remote debug suggestion. It never even got to the part where it is supposed to send the email, and no errors reports because there was none.
Found some newer articles (here and here) to help with the remote debugging which came with its own rabbit holes.
Thanx for the suggestion #KodiaMx
Related
I am developing tests for a website that requires login for the whole page. This website uses Google Sign-In for authentication. All of the Google accounts used for authentication require two-factor authentication.
This means to test one part of the website, the test suite needs to sign in for each test three times - which eventually leads to problems with authentication requiring human interaction, or even requiring extra steps to authenticate.
To resolve this problem, I followed the Reuse Signed-In State part of the Playwright documentation so that sign in would happen once and then saved and shared among the tests.
This works fine for just normal tests. However, I also started using Page Object Models to describe my pages and allow for easier maintenance of the test suite. For some reason, in tests that create new instances of Page Object Model classes, the tests do not make use of the saved state and thus are not logged in.
How can this saved state be passed onto a POM instance in Playwright so that signed-in state can be reused? Perhaps I've missed something simple?
Used a global-setup.ts file to declare login:
async function globalSetup(config: FullConfig) {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto("http://localhost:8000/login");
await page.getByRole("button", { name: "Connexion" }).click();
await page.getByRole("button", { name: "Continue with Google" }).click();
await page.getByRole("textbox", { name: "Adresse e-mail ou numéro de téléphone" }).fill(process.env.USERNAME);
await page.getByRole("textbox", { name: "Adresse e-mail ou numéro de téléphone" }).press("Enter");
await page.getByRole("textbox", { name: "Saisissez votre mot de passe" }).fill(process.env.PASSWORD);
await page.locator("#passwordNext").click();
await page.goto("http://localhost:8000");
// Save signed-in state to 'storageState.json'.
await page.context().storageState({ path: "storageState.json" });
await browser.close();
}
I also added this to the playwright.config.ts file:
const config: PlaywrightTestConfig = {
globalSetup: require.resolve('./global-setup'),
use: {
storageState: 'storageState.json'
}
};
Here is an example of a test making use of the POM, which then doesn't use the state created in global setup. The login still happens, but then the new browser opened doesn't have the state and thus gets stuck on the login page:
test("apply a filter", async ({ page }) => {
const dashboardHome = new DashboardHome(page);
await new LoginPage(page).login();
await dashboardHome.bookingLink.waitFor();
await dashboardHome.bookingLink.click();
const reservationsPage = new ReservationsPage(page);
await reservationsPage.orderNumberFilter.waitFor();
reservationsPage.filter({ orderID: "22222" });
await expect(page).toHaveURL("http://localhost:8000/booking/22222");
});
I had similar issues with global setup and re-write my global setup in fixture (kinda global) where I used it everywhere. I amn't very experienced in test automation and can't explain why globalsetup didn't work. I also believe it's something simple, that i can't catch. Hope it help you.
That definitely seems confusing, especially since switching to a POM shouldn’t affect it (I have successfully used the POM and this one-time saved and reused auth).
I can’t think how switching to use page objects would affect it, and would be curious to see your setup. But one potential reason for your problem is that I’ve seen and worked with sites where if you go to the login page, you’re automatically “logged out” in some way, thus negating your login during setup. If you already logged in during setup and saved that auth state, you should be able to bypass/skip the login page altogether in the test and go directly to the page you need to work with. I would actually expect/be curious if you run into the same problem when not using the POM.
Let me know if that solution works for you, or if you even still have the issue at this point, but if that’s not the issue I may need more clarification or info to help further.
Since we migrated to an Amazon EC instance we're getting sometimes double POST requests to our SaaS application. I have no idea where this is coming from and why this is happening. I've been searching and looking at different options, but can't find the root cause. We migrated from IIS7 to IIS10 on a Windows Server 2022 Datacenter.
Here is an example of an SEQ logging session at 1 client:
SEQ Log
You can see the endpoint was requested multiple times (= OK), but there is also a double POST request at 18:19:41 and 18:18:27. This is logged from within the ASP.NET MVC controller. If I look at the IIS 10 logs, I see the same thing. So the request seems to be initiated from the browser and not doubled in the pipeline.
The MVC controller looks something like this (simplified):
if (ViewData.ModelState.IsValid){
try
{
NHibernateSession.Current.Transaction.Begin();
foreach (var item in deliveryDTosToSave){
var delivery = new Delivery
{
//copying over the DTO to the delivery
};
_deliveryRepository.SaveNew(delivery, userCode, item.Index);
}
NHibernateSession.Current.Transaction.Commit();
return RedirectToAction("Add", "Delivery", new { tab, pharmacyId });
}
catch (RuleException ex)
{
NHibernateSession.Current.Transaction.Rollback();
}
}
On the client-side, the javascript to submit is something like this:
$('#formDeliveries').submit(function () {
if (!canSubmit) {return false;}
$("#loading").show();
canSubmit = false;
});
Things I looked for:
user double-clicking on the submit button: we've blocked this through JS after initial submit. I interviewed several users, and they are not double-clicking.
bug in browser: last user I logged in used Edge 107, which is recent. I can't find anything on the matter
HTTPS redirects: the website is HTTPS-only and users have to be authenticated to use it.
HTTP/3 fall-back scenario's: could be possible as we've enabled HTTP/3 when migrating to Amazon. However users are seeing this behaviour only sometimes and not always from the same browser.
We've tried to simulate the behaviour, but cannot find it. We've logged into the users computer and tried to simulated it while looking at the network requests through the developers utils, but cannot simulate it. I was hoping to see it happening live, so we can rule out any javascript items. If the network log in developer tools shows only 1 POST, it probably has to do something with the IIS pipeline.
Any advice would be greatly appreciated.
I'm building an application with microservices communicating through RabbitMQ (request-response pattern). Everything works fine but still I have a problem with error "There is no matching message handler defined in the remote service." - When I send POST to my Client app, it should simply send the message with data through client (ClientProxy) and the Consumer app should response. This functionality actually works, but always only for the second time. I know it sounds strange but on my first POST request there is always the error from Client and my every second POST request works. However this problem is everywhere in my whole application, so the particular POST request is just for the example.
Here is the code:
Client:
#Post('devices')
async pushDevices(
#Body(new ParseArrayPipe({ items: DeviceDto }))
devices: DeviceDto[]
) {
this.logger.log('Devices received');
return this.client.send(NEW_DEVICES_RECEIVED, devices)
}
Consumer:
#MessagePattern(NEW_DEVICES_RECEIVED)
async pushDevices(#Payload() devices: any, #Ctx() context: RmqContext) {
console.log('RECEIVED DEVICES');
console.log(devices);
const channel = context.getChannelRef();
const originalMsg = context.getMessage();
channel.ack(originalMsg);
return 'ANSWER';
}
Client has the RMQ settings with queueOptions: {durable: true} and the consumer as well queueOptions: {durable: true} with noAck: false
Please do you have any ideas what may causes the problem? I have tried sending the data with JSON.stringify and changing the message structure to {data: devices} but the error is still there.
I had same error and finally solve it today.
In my project, there is an api-gateway as a hybrid application to receive requests and pass data to other systems, every second request gives an error like below.
error: There is no matching message handler defined in the remote service.
Then I tried to remove the api-gateway hybrid application scope in the code below, the error is gone, hope this helps you out with this.
// api-gateway main.ts
const app = await NestFactory.create(AppModule);
// run as a hybrid app —→ remove it
app.connectMicroservice({
transport: Transport.RMQ,
noACK: false,
options: {
urls: [`amqp://${rmqUser}:${rmqPassword}#127.0.0.1:5672`],
queue: 'main_queue',
queueOptions: {
durable: false,
},
},
});
// run hybrid app
await app.startAllMicroservices(); —→ remove it
await app.listen(3000);
I solved this issue by placing the #EventPattern decorator on to a #Controller decorator method
I had this error while NOT using RabbitMQ. I found very little help online around this error message outside of it being related to RabbitMQ.
For me it was an issue where I was importing a DTO from another microservice in my microservice's Controller. I had a new DTO in my microservice that has a similar name to one in another microservice. I accidentally selected the wrong one from the automated list.
Since there wasn't any real indicator that my build was bad, just this error, I wanted to share in case others made the same mistake I did.
I encountered this same issue today and could not find any solution online and stumbled upon your question. I solved it in a hacky way and am not sure how it will behave when the application scales.
I basically added one #EventPattern (#MessagePattern in your case) in the controller of the producer microservice itself. And I called the client.emit() function twice.
So essentially the first time it gets consumed by the function that is in the producer itself and the second emit actually goes to the actual consumer.
This way only one POST call is sufficient.
Producer Controller:
#EventPattern('video-uploaded')
async test() {
return 1;
}
Producer client :
async publishEvent(data: VideosDto) {
this.client.emit('video-uploaded', data);
this.client.emit('video-uploaded', data);
}
I've experienced the same error in my another project and after some research I've found out that problem is in the way of distributing messages in RabbitMQ - named round-robin. In my first project I've solved the issue by creating a second queue, in my second project I'm using the package #golevelup/nestjs-rabbitmq instead of default NestJS library, as it is much more configurable. I recommend reading this question
I am getting the following error while trying to register a user for the Twilio Voice client:
[ERROR VoiceClient] Inside register:deviceToken:completion:, failed to register for Twilio push notifications. Error:Failed to register. Code: 6.
Here is the setup:
Push credentials have been registered with Twilio. A VoIP Push certificate has been registered and those kind of pushes are only in Production mode. Let's say the app ID is "com.bundle.appIDX".
The server side has been setup so that the correct push credentials are fed to the IpMessagingGrant object.
At the client side, the following piece of code is executed:
VoiceClient.sharedInstance().register(withAccessToken: self.accessToken, deviceToken: self.voipToken)
This immediately fails with the error above.
Using version '=2.0.0-beta4' for TwilioVoiceClient, and using version '2.9.1' for twilio-node server side component (https://github.com/twilio/twilio-node/tree/2.9.1).
Tried playing with "Use this credential for sending to a sandbox APN" option and no result.
Tried using both development and provisioning profiles at the client side for the app ID "com.bundle.appIDX".
Is Twilio really supporting VoIP pushes? If yes, what could be wrong with this setup?
Thanks,
Guven.
=======
Edit after Viktor's guidance:
I now manually create the VoiceGrant. I set the value of the key property to 'voice'. Here is what the grant looks like:
{
outgoing_application_sid: 'APXX',
push_credential_sid: 'CRXX',
endpoint_id: 'XX'
}
Still getting the registration error.
I have also tried this format since this is how it looks in 2.11.0 version:
{ outgoing: { application_sid: 'APXX' },
push_credential_sid: 'CRXX',
endpoint_id: 'XX'
}
Any ideas where the problem might be? Attaching the cloud code as well:
var accessToken = new twilio.AccessToken("ACXX", "SKXX", "PPXX", accessTokenOptions);
var voiceGrantConfig = {"outgoingApplicationSid": "APXX",
"endpointId": clientName,
"pushCredentialSid": "CRXX"};
var voiceGrant = new VoiceGrant(voiceGrantConfig);
voiceGrant.key = "voice";
console.log(voiceGrant.toPayload());
accessToken.addGrant(voiceGrant);
var token = accessToken.toJwt();
Edit 2: I have actually upgraded to twilio-node 2.11.0 and still getting the error. Here is the access token right before generating the jwt.
AccessToken {
accountSid: 'ACXX',
keySid: 'SKXX',
secret: 'PPXX',
ttl: 86400,
identity: undefined,
nbf: undefined,
grants:
[ VoiceGrant {
outgoingApplicationSid: 'APXX',
outgoingApplicationParams: undefined,
pushCredentialSid: 'CRXX',
endpointId: 'XX' } ] }
[Edited based on feedback from Guven]
You need a "voice" grant. Otherwise your requests will be denied to the Voice product. You either need to manually add that section to the JSON before signing it or you need to upgrade to the 2.11.0 version. Specifically your token needs to look like this:
{
"sub": "ACxxxx",
"iss": "SKxxxx",
"grants": {
"voice": {
"outgoing": {
"application_sid": "APxxxx"
},
"push_credential_sid": "CRxxxxx"
},
"identity": "voice_test"
},
"jti": "SKxxxxx",
"exp": 1479315711
}
Note, also the "identity" element as well. This is the identifier of your user. Typically its username or an ID of the user record in your system.
Checkout the quickstart app for a code sample for generating the right token (it's in Python but should give you a good idea of how to get started).
I have an Ember CLI app with a Rails back-end API. I am trying to set up end-to-end testing by configuring the Ember app test suite to send requests to a copy of the Rails API. My tests are working, but I am getting the following strange error frequently:
{}
Expected: true
Result: false
at http://localhost:7357/assets/test-support.js:4519:13
at exports.default._emberTestingAdaptersAdapter.default.extend.exception (http://localhost:7357/assets/vendor.js:52144:7)
at onerrorDefault (http://localhost:7357/assets/vendor.js:42846:24)
at Object.exports.default.trigger (http://localhost:7357/assets/vendor.js:67064:11)
at Promise._onerror (http://localhost:7357/assets/vendor.js:68030:22)
at publishRejection (http://localhost:7357/assets/vendor.js:66337:15)
This seems to occur whenever a request is made to the server. An example test script which would recreate this is below. This is a simple test which checks that if a user clicks a 'login' button without entering any email/password information they are not logged in. The test passes, but additionally I get the above error before the test passes. I think this is something to do with connecting to the Rails server, but have no idea how to investigate or fix it - I'd be very grateful for any help.
Many thanks.
import Ember from 'ember';
import { module, test } from 'qunit';
import startApp from 'mercury-ember/tests/helpers/start-app';
module('Acceptance | login test', {
beforeEach: function() {
this.application = startApp();
},
afterEach: function() {
Ember.run(this.application, 'destroy');
}
});
test('Initial Login Test', function(assert)
{
visit('/');
andThen(function()
{
// Leaving identification and password fields blank
click(".btn.login-submit");
andThen(function()
{
equal(currentSession().get('user_email'), null, "User fails to login when identification and password fields left blank");
});
});
});
You can check in the Network panel of Chrome or Firefox developer tools that the request is being made. At least with ember-qunit you can do this by getting ember-cli to run the tests within the browser rather than with Phantom.js/command-line.
That would help you figure out if it's hitting the Rails server at all (the URL could be incorrect or using the wrong port number?)
You may also want to see if there is code that needs to be torn down. Remember that in a test environment the same browser instance is used so all objects need to be torn down; timeouts/intervals need to be stopped; events need to be unbound, etc.
We had that issue a few times where in production there is no error with a utility that sent AJAX requests every 30 seconds, but in testing it was a problem because it bound itself to the window (outside of the iframe) so it kept making requests even after the tests were torn down.