So let me explain the situation. Our asp.net mvc application is running on Windows server 2012 r2 and IIS 8.5.9600.16384. Now randomly user session is lost 4/5 times a day although timeout is set to 1000 minutes in process mode. Now checking the event viewer I found 4 errors occurs when when user session is lost (every time below errors repeat when session is lost). Below are the errors...
1.
An unhandled exception occurred and the process was terminated.
Application ID: /LM/W3SVC/7/ROOT
Process ID: 7680
Exception: System.Net.Mail.SmtpException
Message: The operation has timed out.
StackTrace: at System.Net.Mail.SmtpClient.Send(MailMessage message)
at PDSO.Models.MailClient.<>c__DisplayClass2_1.<SendGMail>b__0(Object o) in
D:\Development\Projects\YunuscoMRP\YunuscoMRP\Models\Repository\MailClient.cs:line 67
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext,
ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback
callback, Object state, Boolean preserveSyncCtx)
at
System.Threading.QueueUserWorkItemCallback.System.Threading.
IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
`
Application: w3wp.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.Net.Mail.SmtpException
at System.Net.Mail.SmtpClient.Send(System.Net.Mail.MailMessage)
at PDSO.Models.MailClient+<>c__DisplayClass2_1.<SendGMail>b__0(System.Object)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object)
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
`
3.
`
Faulting application name: w3wp.exe, version: 8.5.9600.16384, time stamp: 0x52157ba0
Faulting module name: KERNELBASE.dll, version: 6.3.9600.19724, time stamp: 0x5ec50c3e
Exception code: 0xe0434352
Fault offset: 0x000156e8
Faulting process id: 0x1e00
Faulting application start time: 0x01d8165b6e64aacc
Faulting application path: C:\Windows\SysWOW64\inetsrv\w3wp.exe
Faulting module path: C:\Windows\SYSTEM32\KERNELBASE.dll
Report Id: 38d3cbc4-824f-11ec-8116-000c293f4b2c
Faulting package full name:
Faulting package-relative application ID:
`
4.
An unhandled Microsoft .NET Framework exception occurred in w3wp.exe [7680].
Just-In-Time debugging this exception failed with the following error: Debugger could not be
started because no user is logged on.
Check the documentation index for 'Just-in-time debugging, errors' for more information.
I have one class to handle outgoing email. Code is provided below
public string SendGMail(string fromEmail, string toEmail, string mailSubject, string mailBody,
string senderName, string senderPass, string attacmmentLocationPath)
{
try
{
MailMessage mail = new MailMessage();
mail.From = new MailAddress(fromEmail);
mail.To.Add(toEmail);
mail.Subject = mailSubject;
mail.Body = mailBody;
mail.IsBodyHtml = true;
//// mail.Attachments.Add(new Attachment(#attacmmentLocationPath));
//---------------- Enable the block before publish ----------
ThreadPool.QueueUserWorkItem(o =>
{
using (SmtpClient client = new SmtpClient("smtp.office365.com"))
{
client.Port = 587;
client.Credentials = new System.Net.NetworkCredential(senderName, senderPass);
client.EnableSsl = true;
client.Send(mail);
}
});
//-------------------------------------------------------------
return "Success";
}
catch (Exception ex)
{
bool error = new ErrorLogRepository().InsertErrorToDatabase("", "MailClient", "SendGmail", ex.ToString());
return "Error";
}
}
Can anyone suggest what is wrong with my sending email code or what is causing the session timeout/iis restart/application pool restart ?
You should add a try-catch block to your work item to handle the SMTP client exception and log the error gracefully. Because the work item executes outside of your SendMail function, the try-catch block in the SendMail function does not handle the exception.
ThreadPool.QueueUserWorkItem(o =>
{
try
{
using (SmtpClient client = new SmtpClient("smtp.office365.com"))
{
client.Port = 587;
client.Credentials = new System.Net.NetworkCredential(senderName, senderPass);
client.EnableSsl = true;
client.Send(mail);
}
}
catch (Exception ex)
{
bool error = new ErrorLogRepository().InsertErrorToDatabase("", "MailClient", "SendGmail", ex.ToString());
}
});
Related
I created a simple Web Api selfHost as windows service which listens to an address which is dynamically loads from the database and normally it includes port number( like : http://localhost:1900)
When I change the address( for example port number, something like http://localhost:1901) the service can catch the requests on the new port but the requests on old port ( http:localhost:1900) leads to crashing the service and it will be stopped.
I just could debug my service and saw just NullReference Error and not any more info about it.
I don't know even where this error happened and non of my logs could help me.
what do you think about this error? Have you ever seen this kind of error before?
For more info I should say just some errors I can see in Event Viewer window :
Application: {Service.exe}
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.NullReferenceException
at System.Web.Http.SelfHost.HttpSelfHostServer+d__35.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
at System.Web.Http.SelfHost.HttpSelfHostServer+d__34.MoveNext()
at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.b__6_1(System.Object)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object)
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
Faulting application name: {Service.exe}, version: 1.0.0.0, time stamp: 0xc594704b
Faulting module name: KERNELBASE.dll, version: 10.0.14393.3383, time stamp: 0x5ddcb9ff
Exception code: 0xe0434352
Fault offset: 0x000dc232
Faulting process id: 0x7370
Faulting application start time: 0x01d72886545b1d41
Faulting application path: {Service PhysicalAddress}
Faulting module path: C:\Windows\System32\KERNELBASE.dll
Report Id: 305c75f4-8c83-484a-b673-565abfc2b7d6
Faulting package full name:
Faulting package-relative application ID
For more details I bring my Service Class Body below :
class service
{
HttpSelfHostConfiguration config;
HttpSelfHostServer server;
Timer _timer = new Timer();
protected override void OnStart(string[] args)
{
_timer.Interval = 2000;
_timer.Elapsed += _timer_Elapsed;
_timer.Enabled = true;
}
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
var listenToUrl = _getDestUrlFromDB();
var configChanged = false;
if (config != null && config.BaseAddress.AbsoluteUri != listenToUrl + "/")
{
configChanged = true;
config.Dispose();
}
config = new HttpSelfHostConfiguration(uploadApiUrl.Data);
config.Routes.MapHttpRoute("default",
"api/{controller}/{id}",
new { controller = "Home", id = RouteParameter.Optional });
config.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Windows;
if (server == null)
{
server = new HttpSelfHostServer(config);
var task = server.OpenAsync();
task.Wait();
}
else if (configChanged)
{
try
{
Process.Start("cmd", $#"netsh http add urlacl url={listenToUrl} ");
Process.Start("cmd", $#"delete urlacl url={listenToUrl} ");
server.Dispose();
server = new HttpSelfHostServer(config);
var task = server.OpenAsync();
task.Wait();
}
catch (Exception ex)
{
}
}
}
}
When writing a message to the Azure Service Bus (using Microsoft.Azure.ServiceBus standard library, not the .Net Framework version) it works fine. However, when switching networks to a network that blocks that traffic and running it again I would expect an error being raised by SendAsync yet no error is thrown, therefor the function considers the send successful even though it is not.
Am I missing some logic to make sure that errors do get raised and trapped, it seems to be inline with all the examples I have seen.
I have tried this possible solution ..
Trouble catching exception on Azure Service Bus SendAsync method
.ContinueWith(t =>
{
Console.WriteLine(t.Status + "," + t.IsFaulted + "," + t.Exception.InnerException);
}, TaskContinuationOptions.OnlyOnFaulted);
.. and at no point does ContinueWith get hit.
[HttpPost]
[Consumes("application/json")]
[Produces("application/json")]
public ActionResult<Boolean> Post(Contract<T> contract)
{
Task.Run(() => SendMessage(contract));
// Other stuff
}
private async Task<ActionResult<Boolean>> SendMessage(Contract<T> contract)
{
JObject json = JObject.FromObject(contract);
Message message = new Message();
message.MessageId = Guid.NewGuid().ToString();
message.ContentType = ObjectType;
message.PartitionKey = ObjectType;
message.Body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(contract));
foreach (KeyValuePair<String, String> route in DataRouting)
{
JToken jToken = json.SelectToken(route.Value);
if (jToken != null)
{
message.UserProperties[route.Key] = jToken.Value<String>();
}
else
{
String routeError = $"Could not find routing information in request for: {route.Key} in {route.Value}";
Logger.LogError(routeError);
return new UnprocessableEntityObjectResult(routeError);
}
}
// Send the message
try
{
await topicClient.SendAsync(message);
}
catch(Exception ex)
{
return new UnprocessableEntityObjectResult($"'Could not transmit message to service bus - {ex.Message}'");
}
return new OkObjectResult(true);
}
I expect that the error trap would be hit if the SendAsync fails to send the message. However it essentially fire and forgets, the message send is blocked by the firewall but is never reported to the caller by throwing an error.
Ok, found the answer, but I will leave this out there in case anyone else does this to themselves. It was down to my general muppetry when putting the MVC Controller together. Set async on the Post action and configure the await on the send. Obvious really but I missed it.
public virtual async Task<ActionResult<Boolean>> Post(Contract<T> contract){}
...
// Send the message
try
{
await topicClient.SendAsync(message).ConfigureAwait(false);
return new OkObjectResult(true); // Success if we got here
}
catch(Exception ex)
{
return new UnprocessableEntityObjectResult($"'Could not transmit message to service bus - {ex.Message}'");
}
I am using a SQS FIFO queue with SSE enabled. When I use a SQS client to call getQueueUrl(), an exception is thrown with the message All requests to this queue must use HTTPS and SigV4.
Using the latest version of the aws-java-sdk:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk</artifactId>
<version>1.11.160</version>
</dependency>
The following code reproduces the issue:
public class SimpleSqsClient {
private static ClientConfiguration clientConfiguration() {
ClientConfiguration clientConfiguration = new ClientConfiguration();
clientConfiguration.setProxyHost("proxy.foo.com");
clientConfiguration.setProxyPort(8099);
clientConfiguration.setProxyUsername("username");
clientConfiguration.setProxyPassword("password");
clientConfiguration.setProtocol(Protocol.HTTP);
clientConfiguration.setPreemptiveBasicProxyAuth(false);
return clientConfiguration;
}
public static void main(String[] args) throws Exception {
/*
* The ProfileCredentialsProvider will return your [default] credential
* profile by reading from the credentials file located at
* (~/.aws/credentials).
*/
AWSCredentials credentials = null;
try {
credentials = new ProfileCredentialsProvider().getCredentials();
} catch (Exception e) {
throw new AmazonClientException("Cannot load the credentials from the credential profiles file. "
+ "Please make sure that your credentials file is at the correct "
+ "location (~/.aws/credentials), and is in valid format.", e);
}
AmazonSQS sqs = AmazonSQSClientBuilder.standard().withClientConfiguration(clientConfiguration())
.withCredentials(new ProfileCredentialsProvider("SOME_PROFILE"))
.withRegion(Regions.US_EAST_1).build();
System.out.println("===========================================");
System.out.println("Simple SQS Test");
System.out.println("===========================================\n");
try {
System.out.println(sqs.getQueueUrl("some-sse-enabled-queue.fifo"));
} catch (AmazonServiceException ase) {
System.out.println("Caught an AmazonServiceException, which means your request made it "
+ "to Amazon SQS, but was rejected with an error response for some reason.");
System.out.println("Error Message: " + ase.getMessage());
System.out.println("HTTP Status Code: " + ase.getStatusCode());
System.out.println("AWS Error Code: " + ase.getErrorCode());
System.out.println("Error Type: " + ase.getErrorType());
System.out.println("Request ID: " + ase.getRequestId());
} catch (AmazonClientException ace) {
System.out.println("Caught an AmazonClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with SQS, such as not "
+ "being able to access the network.");
System.out.println("Error Message: " + ace.getMessage());
}
}
}
Output:
Caught an AmazonServiceException, which means your request made it to Amazon SQS, but was rejected with an error response for some reason.
Error Message: All requests to this queue must use HTTPS and SigV4. (Service: AmazonSQS; Status Code: 403; Error Code: InvalidSecurity; Request ID: ...)
HTTP Status Code: 403
AWS Error Code: InvalidSecurity
Error Type: Client
Request ID: ...
Changing
clientConfiguration.setProtocol(Protocol.HTTP);
to
clientConfiguration.setProtocol(Protocol.HTTPS);
Resolved the issue
I have an MVC Web API project that I am working on. I created a controller with an action. I am able to hit the action properly using Postman, but when an external system tries to reach my controller, it gets a 500 error. The owner of the external service cannot give me any details beyond that, they can only retry the request.
Here is one of the log entries of their requests in IIS log
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken
2017-02-15 20:38:58 192.168.2.34 POST /Route/to/actionName 8002 - 192.168.2.37 Apache-HttpClient/4.5.2+(Java/1.8.0_102) - 500 0 0 146
First I thought may be the action is being hit, so I added an exception handler and added logging.
[Route("actionName")]
[HttpPost]
public IHttpActionResult actionName(MessageModel message)
{
try
{
// code to handle the action
}
catch (Exception e)
{
// Code to log exception in the log file
}
}
Tried above and saw nothing in the log, I have run tests for failed requests to make sure the above exception handler logs and it does.
So the next thing I decided to do was to handle application level errors in Global.asax and log exception there.
protected void Application_Error(object sender, EventArgs e)
{
if (Request.HttpMethod == "POST")
{
var request = SomeMethodToReadRequestContentsInString();
var service = new SomeExceptionLoggingService();
var exception = Server.GetLastError();
if (exception == null)
{
exception = new ApplicationException("Unknown error occurred");
}
service.LogException(exception, Request.UserHostAddress, Request.UserAgent, request);
}
}
And to my surprise, nothing in the log file.
So then I decided to log ALL Post requests and see if I register ANYTHING in the log.
protected void Application_EndRequest(object sender, EventArgs e)
{
if (Request.HttpMethod == "POST")
{
var request = Helper.ReadStreamUnknownEncoding(Request.InputStream);
var service = new InterfaceTestingService();
var exception = Server.GetLastError();
if (exception == null)
{
exception = new ApplicationException("No Error in this request");
}
service.LogException(exception, Request.UserHostAddress, Request.UserAgent, request);
}
}
And again, nothing!
How do I catch this bug? My goal is to see the Content-Type, and contents.
I tried to add a Custom Field in IIS log settings to include `Content-Type', but the log files still don't have that.
I added a handler for Application_BeginRequest logging everything I did in Application_EndRequest. And it turns out, the content-length was zero, and there was no content. I also restarted IIS Web Server to get it to log custom fields too.
What's strange is that if I send empty content through Postman, I get the action code executed but for some reason when they do it, it doesn't.
I created a custom attribute, inheriting from HandleErrorAttribute:
public class CustomHandleErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
try
{
Utility.LogAndNotifyOfError(filterContext.Exception, null, true);
}
catch(Exception ex)
{
filterContext.Exception = ex;
}
}
}
, and then registered with:
filters.Add(new CustomHandleErrorAttribute());
This has always worked as intended. However a common problem with my log method is that it uses a custom event log source when writing to the event log, which the app pool account typically doesn't have the permissions to create. Creating the event log source is a simple powershell script, however I wanted to actually include that tidbit in the error:
try
{
log.WriteEntry(error, EventLogEntryType.Error);
}
catch(SecurityException ex1)
{
throw new ErrorHandlerException($"The event log could not be written to due to a SecurityExcption. The likely issue is that the '{eventLogSource}' does not already exist. Please run the following powershell command:\r\n"
+ $"New - EventLog - LogName Application - Source {eventLogSource}", ex1);
}
The problem is that the catch in the OnException is never hit. When debugging, the custom error I throw from LogAndNotifyOfError instead triggers a second call to OnException, and the detail of my ErrorHandlerException is never seen. I want the asp.net error page that comes up to be with my custom error detail rather than the SecurityException that was originally raised.
You can even see the surrounding try in the displayed error:
Edit: Entire log method listed:
public static void LogAndNotifyOfError(Exception ex, String extraInfo, Boolean sendEmail)
{
//if the error handler itself faulted...
if (ex is ErrorHandlerException)
return;
string eventLogName = "Application";
string eventLogSource = "MySourceName";
String error = ex.ToString();
if (error.Length > 28000)
error.Substring(0, 28000);//event log is limited to 32k
error += "\r\n\r\nAdditional Information: \r\n"
+ "Machine Name: " + Environment.MachineName + "\r\n"
+ "Logged in user:" + App.CurrentSecurityContext.CurrentUser?.UserId + "\r\n"
+ extraInfo + "\r\n";
EventLog log = new EventLog(eventLogName);
log.Source = eventLogSource;
try
{
log.WriteEntry(error, EventLogEntryType.Error);
}
catch(SecurityException ex1)
{//this doesn't work - for some reason, OnError still reports the original error.
throw new ErrorHandlerException($"The event log could not be written to due to a SecurityExcption. The likely issue is that the '{eventLogSource}' does not already exist. Please run the following powershell command:\r\n"
+ $"New - EventLog - LogName Application - Source {eventLogSource}", ex1);
}
//if the email-to field has been set...
if (!String.IsNullOrEmpty(App.Config.General.ErrorHandlerSendToAddresses) && sendEmail)
{
//...then send the email
MailMessage email = new MailMessage();
email.To.Add(App.Config.General.ErrorHandlerSendToAddresses);
email.IsBodyHtml = false;
email.Subject = String.Format("Error in {0}", eventLogSource);
email.Body = email.Subject + "\r\n\r\n"
//+ "Note: This error may be occuring continuously, but this email is only sent once per hour, per url, in order to avoid filling your mailbox. Please check the event log for reoccurances and variations of this error.\r\n\r\n"
+ "The error description is as follows: \r\n\r\n"
+ error + "\r\n\r\n";
SmtpClient smtp = new SmtpClient();
smtp.Send(email);
}
}
I figured it out (sort of). It would appear that when the newly throw exception has an inner exception, it is only displaying that inner exception. It does not matter what the type is on the outer or inner exception.