After reviewing and trying many of the suggestions surrounding the error message:
"An asynchronous module or handler completed while an asynchronous
operation was still pending."
I found myself in the situation where even though the call to the MVC accountController actually EXECUTED the desired code (an email was sent to the right place with the right content) and a Try/Catch in the controller method would not 'catch' the error, the AngularJS factory that was initiating the call would receive a server error "page".
Factory:(AngularJS)
InitiateResetRequest: function (email) {
var deferredObject = $q.defer();
$http.post(
'/Account/InitiateResetPassword', { email: email }
)
.success(function (data) {
deferredObject.resolve(data);
})
.error(function (data) {
//This is a stop-gap solution that needs to be fixed..!
if (data.indexOf("An asynchronous module or handler completed while an asynchronous operation was still pending.") > 0) {
deferredObject.resolve(true);
} else {
deferredObject.resolve(false);
}
});
return deferredObject.promise;
}
MVC Controller (C#):
[HttpPost]
[AllowAnonymous]
public async Task<int> InitiateResetPassword(string email)
{
try
{
_identityRepository = new IdentityRepository(UserManager);
string callbackUrl = Request.Url.AbsoluteUri.Replace(Request.Url.AbsolutePath, "/account/reset?id=");
await _identityRepository.InitiatePasswordReset(email, callbackUrl);
return 0;
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
return 1;
}
}
Identity Repository/InitiatePasswordReset:
public async Task InitiatePasswordReset(string email, string callbackUrl)
{
try
{
var u = await _applicationUserManager.FindByEmailAsync(email);
string passwordResetToken = await GetResetToken(u);
callbackUrl = callbackUrl + HttpUtility.UrlEncode(passwordResetToken);
await _applicationUserManager.SendEmailAsync(u.Id, RESET_SUBJECT, string.Format(RESET_BODY, u.FirstName, u.LastName, callbackUrl));
}
catch(Exception ex)
{ //another vain attempt to catch the exception...
Console.WriteLine(ex.ToString());
throw ex;
}
}
The EmailService injected into the ASP.NET Identity "ApplicationUserManager"
public class EmailService : IIdentityMessageService
{
XYZMailer xyzMailer;
public EmailService()
{
xyzMailer = XYZMailer.getCMRMailer();
}
public async Task SendAsync(IdentityMessage message)
{
//original code as posted:
//await Task.FromResult(xyzMailer.SendMailAsync(message));
//solution from #sirrocco-
await xyzMailer.SendMailAsync(message);
}
}
and finally...the XYZMailer class
class XYZMailer
{
#region"Constants"
private const string SMTP_SERVER = "XYZEXCHANGE.XYZ.local";
private const string NO_REPLY = "noReply#XYZCorp.com";
private const string USER_NAME = "noreply";
private const string PASSWORD = "theMagicP#55word"; //NO, that is not really the password :)
private const int SMTP_PORT = 587;
private const SmtpDeliveryMethod SMTP_DELIVERY_METHOD = SmtpDeliveryMethod.Network;
#endregion//Constants
internal XYZMailer()
{
//default c'tor
}
private static XYZMailer _XYZMailer = null;
public static XYZMailer getXYZMailer()
{
if (_XYZMailer == null)
{
_XYZMailer = new XYZMailer();
}
return _XYZMailer;
}
public async Task<int> SendMailAsync(IdentityMessage message)
{
#if DEBUG
message.Body += "<br/><br/>DEBUG Send To: " + message.Destination;
message.Destination = "me#XYZCorp.com";
#endif
// Create the message:
var mail =
new MailMessage(NO_REPLY, message.Destination)
{
Subject = message.Subject,
Body = message.Body,
IsBodyHtml = true
};
// Configure the client:
using (SmtpClient client = new SmtpClient(SMTP_SERVER, SMTP_PORT)
{
DeliveryMethod = SMTP_DELIVERY_METHOD,
UseDefaultCredentials = false,
Credentials = new System.Net.NetworkCredential(USER_NAME, PASSWORD),
EnableSsl = true
})
{
// Send:
await client.SendMailAsync(mail);
}
return 0;
}
}
(note: originally the controller method was simply "public async Task InitiateResetPassword, I added the return type as an attempt to trap the error on the server. At runtime, return 0; does hit (breakpoint) the catch does not get hit and at the client")
At the moment I am simply filtering for the expected error message and telling javascript to treat it as a success. This solution has the benefit of 'actually working'... but it is not 'ideal'.
How do I prevent the error on the server?
or alternately,
How do I catch the error on the server?
You need to remove await Task.FromResult from EmailService because that makes it so the code executes synchronously instead of async.
As to why the the exception was still raised and bubbled up outside the try/catch - I suspect the Task.FromResult was the culprit here too - if you now raise an exception in SendAsync (just to test it) you should catch in the controller.
Related
I am trying to set up a WebSocket connection using the .net SignalR and React app as a client to be able to send private messages.
Here is my code on the client side:
const setUpSignalRConnection = async () => {
const connection = new HubConnectionBuilder()
.withUrl("http://localhost:5000/messaginghub")
.build();
setConnection(connection);
connection.on("ReceiveMessage", (message: string) => {
console.log("Recieved Message", message);
setChatMessages((oldArray) => [...oldArray, message]);
});
try {
await connection.start();
} catch (err) {
console.log("Errors", err);
}
return connection;
};
const SendMessage = async () => {
if (connection) {
try {
console.log("sending message");
await connection.send("SendPrivateMessage", user.user.email, message);
} catch (e) {
console.log("Errors sending message", e);
}
} else {
alert("No connection to server yet.");
}
};
and my server side code
public async Task SendPrivateMessage(string userEmail, string message)
{
var RecivingMessageUser = _unitOfWork.UserRepository.GetByEmail(userEmail);
var currUserEmail = Context.User.FindFirstValue(ClaimTypes.NameIdentifier);
var sender = _unitOfWork.UserRepository.GetByEmail(currUserEmail);
var newMessage = new MessagesDto
{
FromId = sender.UserId,
ToId = RecivingMessageUser.UserId,
MessageBody = message,
SentAt = DateTime.UtcNow,
};
await Clients.Group(userEmail).SendAsync("ReceiveMessage", message);
_unitOfWork.MessagingRepository.Insert(_mapper.Map<MessagesDto, Messages>(newMessage));
_unitOfWork.SaveChanges();
}
public override Task OnConnectedAsync()
{
var groupName = Context.User.FindFirstValue(ClaimTypes.NameIdentifier);
Groups.AddToGroupAsync(Context.ConnectionId, groupName);
return base.OnConnectedAsync();
}
public override Task OnDisconnectedAsync(Exception ex)
{
Groups.RemoveFromGroupAsync(Context.ConnectionId, Context.User.FindFirstValue(ClaimTypes.NameIdentifier));
return base.OnDisconnectedAsync(ex);
}
With console.logs I see that I am sending a message once and the message is stored in DB once but somehow on the other end, I am getting two received messages.
I am testing it on my local machine in two separate browsers.
What am I doing wrong?
Which method on your back-end is calling twice?
You are telling your message saved in to the DB once so it shouldn't be the SendPrivateMessage method which is calling towice.
I am writing a test method in xunit. So when a user fails to enroll, a specific message is returned in the catch block. In the test method, I want to check if the right message is returned. But when I run, I get this message instead:
EnrollUser failed with HTTP response code:BadRequest.
If anyone can help me find out, if it possible, how to retrieve the message I want.
Below is the code.
public async Task<IHttpActionResult> EnrollUser([FromUri]int id, int userId, int?
organizationId = null)
{
try
{
if (organizationId.HasValue)
{
Do something.....
}
else
{
Do something.....
}
return Ok();
}
catch (Exception e)
{
var errorMsg = $"User enrollment failed for userId:{userId}, serviceId:{id}.";
return (IHttpActionResult)BadRequest(errorMsg);
}
}
[Fact]
public async Task EnrollUser_Should_Return_Failure_Message()
{
const int userId = 2310;
const int serviceId = 9;
const string expectedMessage = "User enrollment failed for userId:{userId}, serviceId:{id}.";
Func<Task> act = () => EnrollUser(userId, serviceId);
var actualException = await Assert.ThrowsAsync<Exception>(act);
Assert.Equal(expectedMessage, actualException.Message);
}
The Exception is handled in the EnrollUser method so this method will never throw an exception, It will return BadRequest object instead that you can use to compare the message.
var result = await act;
Assert.Equal(expectedMessage, act.Request);
You have an API (NOT modifiable) which you want to consume, this API receives some parameters which if they are NOT properly validated, the API throws a message of the error, it is precisely this message that I want to capture, for example here in the image I pass an erroneous password and want to show that message to the user.
For this, create a class called Response, which is responsible for managing the different calls made to the API
Response.cs:
public class Response
{
public bool IsSuccess { get; set; }
public string Message { get; set; }
public object Result { get; set; }
[JsonProperty(PropertyName = "userMessage")]
public string userMessage { get; set; }
}
in my LoginViewModel I call the method that this API consumes, which is implemented in a class called ApiService.cs:
ApiService.cs:
public async Task<Response> GetLogin(
string urlAPILogin, string KeyLogin, string Rut, string Password)
{
try
{
var client = new HttpClient();
client.BaseAddress = new Uri(urlAPILogin);
string url = string.Format("login/index/?k=" + KeyLogin + "&rut=" + Rut + "&password=" + Password);
var response = await client.GetAsync(url);
var result = await response.Content.ReadAsStringAsync();
var model = JsonConvert.DeserializeObject<Response>(result);
if (!response.IsSuccessStatusCode)
{
return new Response
{
IsSuccess = false,
Message = response.StatusCode.ToString(),
Result = model,
};
}
return new Response
{
IsSuccess = true,
Message = "Ok",
Result = model,
};
}
catch (Exception ex)
{
return new Response
{
IsSuccess = false,
Message = ex.Message,
};
}
}
Now it is in my ViewModel (LoginViewModel) where I want to paint that message! and I try to capture it in the following way:
var response = await apiService.GetLogin(
urlAPILogin,
KeyLogin,
Rut,
Password);
if (string.IsNullOrEmpty(response.userMessage))
{
IsRunning = false;
IsEnabled = true;
await dialogService.ShowMessage(
"Error",
response.userMessage);
Password = null;
return;
}
but I'm not getting the expected response (he paints the blank message to me !!!)
being that the object if it brings the message !!
any help for me?
what am I doing wrong?
In your LoginViewModel method where you are awaiting the response, the variable with the userMessage you want is located a layer deeper.
Currently:
// userMessage is null in your *locals* section
await dialogService.ShowMessage("Error", response.userMessage);
Should be:
// This is where the wanted value is: userMessage is the desired message
await dialogService.ShowMessage("Error", response.Result.userMessage);
You will need to cast your response.Result as a Response since your Result variable is an object, but this should fix your problem.
Should be (casted):
// This is where the wanted value is: userMessage is the desired message
await dialogService.ShowMessage("Error", (response.Result as Response)?.userMessage);
I'm creating an Instagram API client on ASP MVC using HttpClient, I'm trying to make a get request but it fails without throwing exception or responding and doesn't respond to my timeout. Here is my code:
public class InstagramService
{
private HttpClient Client = new HttpClient {
BaseAddress = new Uri("https://api.instagram.com/v1/"),
Timeout = TimeSpan.FromMilliseconds(500)
};
public async Task<InstagramUser> GetInstagramUser(long? userId = null)
{
InstagramUser User = null;
string Parameter = (userId == null) ? "self" : userId.ToString();
try {
var response = await Client.GetAsync("users/" + Parameter + "/" + GetAccessToken());
if (response.IsSuccessStatusCode)
{
User = await response.Content.ReadAsAsync<InstagramUser>();
}
}catch(Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.InnerException.Message);
}
return User;
}
private string GetAccessToken()
{
return "?access_token=" + DB.config_det_sys.Single(i => i.codigo == "ACCESS_TOKEN_INSTAGRAM" && i.estado == true).Valor;
}
}
EDIT
Here I add how I call my service on the Home Controller, I will still test changing the controller to async Task
public class HomeController : Controller
{
private InstagramService IGService = new InstagramService();
public ActionResult About()
{
var apiCall = IGService.GetInstagramUser();
var model = apiCall.Result;
return View(model);
}
}
I tested on Postman trying to make the API call and it indeed worked, so where I'm failing to catch errors?
Your problem is here:
var model = apiCall.Result;
As I describe on my blog, you shouldn't block on asynchronous code. It can cause a deadlock.
Instead of Result, use await:
var model = await apiCall;
Adding to Stephen's answer, update the controller's action to be async all the way.
public class HomeController : Controller {
private InstagramService IGService = new InstagramService();
public async Task<ActionResult> About() {
var model = await IGService.GetInstagramUser();
return View(model);
}
}
We are using MassTransit asynchronous messaging (on top of RabbitMQ) for our microservice architecture.
We ran into issues testing consumers that in turn make asynchronous calls.
The example below shows a simple MassTransit consumer that uses RestSharp to make an outbound call and utilized the ExecuteAsync asynchronous method.
public class VerifyPhoneNumberConsumer : Consumes<VerifyPhoneNumber>.Context
{
IRestClient _restClient;
RestRequest _request;
PhoneNumber _phoneNumber;
PhoneNumberVerificationResponse _responseData;
public VerifyPhoneNumberConsumer(IRestClient client)
{
_restClient = client;
}
public void Consume(IConsumeContext<VerifyPhoneNumber> context)
{
try
{
//we can do some standard message verification/validation here
_restClient.ExecuteAsync<PhoneNumberVerificationResponse>(_request, (response) =>
{
//here we might do some standard response verification
_responseData = response.Data;
_phoneNumber = new PhoneNumber()
{
Number = _responseData.PhoneNumber
};
context.Respond(new VerifyPhoneNumberSucceeded(context.Message)
{
PhoneNumber = _phoneNumber
});
});
}
catch (Exception exception)
{
context.Respond(new VerifyPhoneNumberFailed(context.Message)
{
PhoneNumber = context.Message.PhoneNumber,
Message = exception.Message
});
}
}
}
A sample unit test for this might look like the following:
[TestFixture]
public class VerifyPhoneNumberConsumerTests
{
private VerifyPhoneNumberConsumer _consumer;
private PhoneNumber _phoneNumber;
private RestResponse _response;
private VerifyPhoneNumber _command;
private AutoResetEvent _continuationEvent;
private const int CONTINUE_WAIT_TIME = 1000;
[SetUp]
public void Initialize()
{
_continuationEvent = new AutoResetEvent(false);
_mockRestClient = new Mock<IRestClient>();
_consumer = new VerifyPhoneNumberConsumer(_mockRestClient.Object);
_response = new RestResponse();
_response.Content = "Response Test Content";
_phoneNumber = new PhoneNumber()
{
Number = "123456789"
};
_command = new VerifyPhoneNumber(_phoneNumber);
}
[Test]
public void VerifyPhoneNumber_Succeeded()
{
var test = TestFactory.ForConsumer<VerifyPhoneNumberConsumer>().New(x =>
{
x.ConstructUsing(() => _consumer);
x.Send(_command, (scenario, context) => context.SendResponseTo(scenario.Bus));
});
_mockRestClient.Setup(
c =>
c.ExecuteAsync(Moq.It.IsAny<IRestRequest>(),
Moq.It
.IsAny<Action<IRestResponse<PhoneNumberVerificationResponse>, RestRequestAsyncHandle>>()))
.Callback<IRestRequest, Action<IRestResponse<PhoneNumberVerificationResponse>, RestRequestAsyncHandle>>((
request, callback) =>
{
var responseMock = new Mock<IRestResponse<PhoneNumberVerificationResponse>>();
responseMock.Setup(r => r.Data).Returns(GetSuccessfulVericationResponse());
callback(responseMock.Object, null);
_continuationEvent.Set();
});
test.Execute();
_continuationEvent.WaitOne(CONTINUE_WAIT_TIME);
Assert.IsTrue(test.Sent.Any<VerifyPhoneNumberSucceeded>());
}
private PhoneNumberVerificationResponse GetSuccessfulVericationResponse()
{
return new PhoneNumberVerificationResponse
{
PhoneNumber = _phoneNumber
};
}
}
Because of the invocation of the ExecuteAsync method in the consumer, this test method would fall through if we did not put something to block it until it was signaled (or timed out). In the sample above, we are using AutoResetEvent to signal from the callback to continue and run assertions.
THIS IS A TERRIBLE METHOD and we are exhausting all resources to try to find out alternatives. If its not obvious, this can potentially cause false failures and race conditions during testing. Not too mention potentially crippling automated testing times.
What alternatives do we have that are BETTER than what we currently have.
EDIT Here is a source that I originally used for how to mock RestSharp asynchronous calls.
How to test/mock RestSharp ExecuteAsync(...)
Honestly, the complexity of doing asynchronous methods is one of the key drivers of MassTransit 3. While it isn't ready yet, it makes asynchronous method invocation from consumers so much better.
What you're testing above, because you are calling ExecuteAsync() on your REST client, and not waiting for the response (using .Result, or .Wait) in the consumer, the HTTP call is continuing after the message consumer has returned. So that might be part of your problem.
In MT3, this consumer would be written as:
public async Task Consume(ConsumeContext<VerifyPhoneNumber> context)
{
try
{
var response = await _restClient
.ExecuteAsync<PhoneNumberVerificationResponse>(_request);
var phoneNumber = new PhoneNumber()
{
Number = response.PhoneNumber
};
await context.RespondAsync(new VerifyPhoneNumberSucceeded(context.Message)
{
PhoneNumber = _phoneNumber
});
}
catch (Exception exception)
{
context.Respond(new VerifyPhoneNumberFailed(context.Message)
{
PhoneNumber = context.Message.PhoneNumber,
Message = exception.Message
});
}
}
I was able to come up with the following solution which seems far more elegant and proper. Feel free to correct me if I am wrong in assuming this.
I modified the RestSharp execution in my consumer so my consumer looks like the following:
public class VerifyPhoneNumberConsumer : Consumes.Context
{
IRestClient _restClient;
RestRequest _request;
PhoneNumber _phoneNumber;
PhoneNumberVerificationResponse _responseData;
public VerifyPhoneNumberConsumer(IRestClient client)
{
_restClient = client;
}
public void Consume(IConsumeContext<VerifyPhoneNumber> context)
{
try
{
//we can do some standard message verification/validation here
var response = await _restClient.ExecuteGetTaskAsync<PhoneNumberVerificationResponse>(_request);
_responseData = response.Data;
_phoneNumber = new PhoneNumber()
{
Number = _responseData.PhoneNumber
};
}
catch (Exception exception)
{
context.Respond(new VerifyPhoneNumberFailed(context.Message)
{
PhoneNumber = context.Message.PhoneNumber,
Message = exception.Message
});
}
}
}
This utilizes the TPL async capabilities of RestSharp so that I don't have to do it myself.
Because of this, I am able to change my test code to the following:
[Test]
public void VerifyPhoneNumber_Succeeded()
{
var test = TestFactory.ForConsumer<VerifyPhoneNumberConsumer>().New(x =>
{
x.ConstructUsing(() => _consumer);
x.Send(_command, (scenario, context) => context.SendResponseTo(scenario.Bus));
});
var response = (IRestResponse<PhoneNumberVerificationResponse>)new RestResponse<PhoneNumberVerificationResponse>();
response.Data = GetSuccessfulVericationResponse();
var taskResponse = Task.FromResult(response);
Expect.MethodCall(
() => _client.ExecuteGetTaskAsync<PhoneNumberVerificationResponse>(Any<IRestRequest>.Value.AsInterface))
.Returns(taskResponse);
test.Execute();
Assert.IsTrue(test.Sent.Any<VerifyPhoneNumberSucceeded>());
}