Question What is the difference between CustomExceptionFilter and GlobalExceptionHandler?

raysefo

Well-known member
Joined
Feb 22, 2019
Messages
361
Programming Experience
10+
Hi,

In my asp.net web API, I am using both GlobalExceptionHandler and CustomExceptionFilter. I think they do the same job, hiding the actual error from the client and send them "HTTP 500 - Internal Server Error. Please Contact your Administrator." response. I wonder if I remove GlobalExcepitonHandler and add Nlog into CustomExceptionFilter, can I still send the same response and log errors? What are your opinions?

UnhandledExceptionLogger can't catch all the errors that's why I would like to add logging inside of one of them.

CustomExceptionFilter:
C#:
public class CustomExceptionFilter : ExceptionFilterAttribute
    {

        public override void OnException(HttpActionExecutedContext actionExecutedContext)
        {
            base.OnException(actionExecutedContext);


            var response = new HttpResponseMessage(HttpStatusCode.InternalServerError)
            {
                //Content = new StringContent("An unhandled exception was thrown by service."),
                ReasonPhrase = "HTTP 500 - Internal Server Error. Please Contact your Administrator."
            };

            actionExecutedContext.Response = response;
        }
    }

GlobalExceptionHandler:
C#:
public class GlobalExceptionHandler : ExceptionHandler
    {
        
        public override void Handle(ExceptionHandlerContext context)
        {
            var result = new HttpResponseMessage(HttpStatusCode.InternalServerError)
            {
                Content = new StringContent("HTTP 500 - Internal Server Error. Please Contact your Administrator."),
                ReasonPhrase = "Exception"
            };

            
            context.Result = new ErrorMessageResult(context.Request, result);
        }

        public class ErrorMessageResult : IHttpActionResult
        {
            private HttpRequestMessage _request;
            private readonly HttpResponseMessage _httpResponseMessage;

            public ErrorMessageResult(HttpRequestMessage request, HttpResponseMessage httpResponseMessage)
            {
                _request = request;
                _httpResponseMessage = httpResponseMessage;
            }

            public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
            {
                return Task.FromResult(_httpResponseMessage);
            }
        }

      }
UnhandledExceptionFilter:
C#:
public class UnhandledExceptionLogger : ExceptionLogger
    {
        private static readonly Logger logger = LogManager.GetCurrentClassLogger();

        public override void Log(ExceptionLoggerContext context)
        {
            var timestamp = DateTime.UtcNow;

            //NLOG
            NLog(logger, context.Exception, timestamp);
        }

        private void NLog(Logger logger, Exception message, DateTime timestamp)
        {
            var sb = new StringBuilder();
            sb.AppendLine(message.ToString());
            sb.AppendLine(timestamp.ToLongDateString());
            logger.Error(sb.ToString());
        }
    }
 
Yep, I read it again, I have all those exception levels. When I added CustomExceptionFilter and used Nlog inside, I got this error.

C#:
2019-08-19 22:26:43.5956||ERROR|Game.Handlers.CustomExceptionFilter|System.Threading.Tasks.TaskCanceledException: A task was canceled.
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at BusinessService.Utility.Utilities.<CallRazer>d__3.MoveNext() in C:\Users\197199\Documents\Visual Studio 2017\Projects\Game\BusinessService\Utility\Utilities.cs:line 138
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at BusinessService.GameServicesTest.<CallProducts>d__11.MoveNext() in C:\Users\197199\Documents\Visual Studio 2017\Projects\Game\BusinessService\GameServicesTest.cs:line 478
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at BusinessService.GameServicesTest.<GameProducts>d__10.MoveNext() in C:\Users\197199\Documents\Visual Studio 2017\Projects\Game\BusinessService\GameServicesTest.cs:line 449
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Game.Controllers.LoadTestController.<PostProducts>d__5.MoveNext() in C:\Users\197199\Documents\Visual Studio 2017\Projects\Game\Game\Controllers\LoadTestController.cs:line 205
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Threading.Tasks.TaskHelpersExtensions.<CastToObject>d__1`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__6.MoveNext()
 
Would it be httpclient timeout?
Well it could be. If your httpclient is being terminated by another thread or a disposing method. Is it? Given you're having problems with connection pools as well as thread pools, I wouldn't rule out anything.
 
I added timeout but unfortunately didn't help my spike test.

C#:
 //Timeout
_httpClient.Timeout = TimeSpan.FromSeconds(600);
//Call Game
var response = await _httpClient.PostAsync("https://test.com/" + url, content);
return response;
 
What if the problem is at the 3rd party service? I mean it might be, right? All this time I was trying to find bugs in my code with a reason but I think It is possible that might be due to 3rd party rest API test environment.
 
Last edited:
This problem like some of your other problems seem to reside with your administrator of your server. I was going back reviewing some of your posts 1# and 2#, and your server isn't responsive, quite likely because it needs be reconfigured. See this re this :
Screenshot_29.jpg

And this :
Screenshot_31.jpg

The request failed due to an underlying issue such as network connectivity, DNS failure, server certificate validation or timeout. ~Microsoft

This seems evident that most of your issues reside on your server and the fact they are not responsive should tell you something isn't right. If you can't connect to them, then how do you expect your application to connect to them? And as of now, your subdomain from gamesultan redirects to a new destination => http://qa-api.mol.com/pinstore/ and that seems to be pinging ok, and is also responding fine and not stalling unlike the above. @raysefo are you the only developer or are there other people involved with this project? I ask because I've worked on a number of projects similarly where network/security/tech administrators had caused a lot of headache unnecessarily by changes they made to the servers, and if that is your situation, you need to tell them to get the hell out until you finish your own work first, and you should request full access to set the system up yourself. They can secure it when you're done.
Screenshot_33.jpg

Your server is responding to ping requests via IP. Your subdomain does not, but its now redirecting elsewhere. I notice you are also using secured connections, and your code does not. According to Microsoft, this can also cause exceptions in your application.
 
Thank you for the explanation @Sheepings.

are you the only developer or are there other people involved with this project?
Yes, I am the only one in this project. As I mentioned sometime in one of my posts that the server (185.201.212.218) we are using is hosted in the cloud. I have admin rights but I have little experience with server management, mostly google engineering :) https://teststore.gamesultan.com/ is the 3rd party rest API which I am calling. They gave permission for our IP (185.201.212.218) to access their API.

Your subdomain does not, but its now redirecting elsewhere.
I am afraid I don't get what you mean by "your subdomain"? My server IP is 185.201.212.218.

I notice you are also using secured connections, and your code does not.
I also don't understand this. Can you elaborate, please?
 
Last edited:
Lets go one at a time here... In my reply above, click 1# and on that page search and you will see what I am eluding to.
C#:
                        //Call Game Sultan
                        var response = await _httpClient.PostAsync("https://teststore.gamesultan.com/" + url, content);
I understand that you are trying to plug that server, but that server isn't responding. Not to mention it's now directing its traffic to a new domain name as I've already explained above. Between your server, the 3rd party, and whoever is involved with your setup, resides the problem. Looking at the screenshots in the first spoiler, your or/and there server are not responding. Frankly, I would not have used a cloud server but that's a discussion for another time. Also, what is the purpose of this IP : 185.201.212.218 ? Is this where your website will reside or what? I am just trying to get a clear understanding as to what you're actually doing in more detail.

You need to make some enquiries into this yourself, and ask your hosting provider for help with what you're trying to do, so that you have the correct server setup for the job. If you have a managed server with your hosting provider, you should have your server configured and running properly by this evening or tomorrow. You should also be enquiring to the third party about the traffic to your third party provider, and get them to confirm your requests are hitting their systems. You should also ask them how many requests you can make at one time. It is possible they could be limiting your interactions. This can be done on their end, if you're flooding their system with requests.
All this time I was trying to find bugs in my code with a reason but I think It is possible that might be due to 3rd party rest API test environment.
Lets stick to finding out a few things first, and then we can move from there, to some of your other posts where I would address some minor discrepancies. Also, does this gamesultan.com have an open API we can read about?
I notice you are also using secured connections, and your code does not. => I meant to say, they, as in; gamesultan are using https, and there are protocols for posting to secured connections. You can Bing around on that one yourself.
 
Thank you @Sheepings.

lso, what is the purpose of this IP : 185.201.212.218 ? Is this where your website will reside or what? I am just trying to get a clear understanding as to what you're actually doing in more detail.
My rest API is in this server. (185.201.212.218) Here is the flow; client calls my API and my API calls this 3rd party API.

Also, does this gamesultan.com have an open API we can read about?
Unfortunately, there is no open API.

I will propose our server admin and 3rd party admin to make a test in order to find out where is the problem. I will make google engineering about protocols for posting to secured connections.
 
Hopefully, we can make tests with the admins. For time being, I made another test. Increased threads 25 by 25 in time. When latency gets more than 100 seconds I got System.Threading.Tasks.TaskCanceledException: A task was canceled error.

2019-08-21 22_42_51-View Results in Table.jmx (T__Home_View Results in Table.jmx) - Apache JMe...png
2019-08-21 22_42_51-View Results in Table.jmx (T__Home_View Results in Table.jmx) - Apache JMe...png
 
I would first move from cloud hosting. You could use a cloud server if your main server ever went down. But I would be then looking at making sure your server has the correct configurations for whatever it is that you're running. That is solely the responsibility of your server management people; whomever they may be. I would then check with the gamesultan people to ensure they have properly given you the access you need, and that they haven't miss-configured something, since there so-called API isn't public, it doesn't show that they have a well tested platform that runs error-free.

Frankly, I would be worried about using a service form a company who don't know how to setup their own DNS records correctly. With no ptr records, and incorrect mx records along with allowing recursive queries which is a crappy thing to do. Yea, I wouldn't hold my breath that they know what they're doing when it comes to server configurations and security. Are you aware of any other websites that use gamesultan? Hopefully, you get it sorted soon. When you get the answers to #11, post them up.

As an aside, while I do believe your issues are external, it also wouldn't hurt to exhaust all your efforts to make sure your HttpClient is not being disposed of while using async/await. A quick check shows that this error can arise if the client is disposed of. Check your logs for the line number of the error. Put a break point on the error and when it hits, you can check CancellationToken.IsCancellationRequested Property (System.Threading) and if that returns false, you can bet your money something somewhere is timing out for sure. As I suggested you before, get VNC on your server and get VS Community installed on there and then test your application from your live server. What may work in development, doesn't always work in production.
 
As an aside, while I do believe your issues are external, it also wouldn't hurt to exhaust all your efforts to make sure your HttpClient is not being disposed of while using async/await. A quick check shows that this error can arise if the client is disposed of. Check your logs for the line number of the error. Put a break point on the error and when it hits, you can check CancellationToken.IsCancellationRequested Property (System.Threading) and if that returns false, you can bet your money something somewhere is timing out for sure
Yes I have VS community installed on cloud server and I sometimes do remote debugging. So do you mean I should debug while I am load test with Jmeter? Because I am not sure if the debugging would be right/easy while load testing.

Instead of debugging, Can I log IsCancellationRequested here?
C#:
try
{
                     
       //Timeout
       _httpClient.Timeout = TimeSpan.FromSeconds(600);
        //Call Game Sultan
         var response = await _httpClient.PostAsync("https://test.com/" + url, content);
         return response;
}
catch (TaskCanceledException)
{
        //Nlog here
                     
        
bool value = e.CancellationToken.IsCancellationRequested;
string time;
if (_httpClient.Timeout.TotalHours > 1)
 {
            time = $"{_httpClient.Timeout.TotalHours:N1} hours";
 }
else if (_httpClient.Timeout.TotalMinutes > 1)
 {
             time = $"{_httpClient.Timeout.TotalMinutes:N1} minutes";
 }
 else if (_httpClient.Timeout.TotalSeconds > 1)
 {
            time = $"{_httpClient.Timeout.TotalSeconds:N1} seconds";
 }
 else
 {
           time = $"{_httpClient.Timeout.TotalMilliseconds:N0} milliseconds";
}
 throw new TimeoutException($"No response after waiting {time}. Value {value}");
 }
 finally
 {
         content.Dispose();
 }

By the way, I have to pass a CancellationToken into this CallRazer method in order to make it cancellable right? I don't have such a code. I mean it must be something else but I will try to debug and make sure.

Are you aware of any other websites that use gamesultan?
Yes, they have one as far as I know and it is operating.
 
Last edited:
Back
Top Bottom