Handling exceptions during localizing in .net5 - c#

I would like to ask you if it is possible to handle exception during localizing? For instance I have made recently mistake in my resx file, and my localizer caused that in one language users got error (in translated version I wrote something like "foo {2} bar" instead of "foo {0} bar". I would like to handle this exception that localizer returns the "not translated" string.
Is it possible to write some kind of special exception handler for localizer? Should it implements any interface or something?
Many thanks for your answer.

I think you might need to custom a Resource filters with OnResourceExecuted().
Filter types
Each filter type is executed at a different stage in the filter pipeline:
Authorization filters
run first and are used to determine whether the user is authorized for the request. Authorization filters short-circuit the pipeline if the request is not authorized.
Resource filters
Run after authorization.
OnResourceExecuting runs code before the rest of the filter pipeline. For example, OnResourceExecuting runs code before model binding.
OnResourceExecuted runs code after the rest of the pipeline has completed.
Action filters
Run code immediately before and after an action method is called. Can change the arguments passed into an action. Can change the result returned from the action. Are not supported in Razor Pages.
Exception filters
apply global policies to unhandled exceptions that occur before the response body has been written to.
Result filters
run code immediately before and after the execution of action results. They run only when the action method has executed successfully. They are useful for logic that must surround view or formatter execution.
The following diagram shows how filter types interact in the filter pipeline.

i use a simpler way without any middle ware ,i translate the exception messages into localized string as below ,
call the method in your catch with the original exception message
catch (Exception dex)
{
return Json(new { success = false, responseText = Models.SiteUtils.FriendlyErrorMessage(dex) });
}
method for localization of error messages ,will search for the exception message and get your version of it ,
notice i use Message.Contains(x.OriginalError) so i do not need to translate he whole message exactly ,you may decide to use exact match if you need based on your own logic
public static string FriendlyErrorMessage(Exception dex)
{
var Message = dex.Message;
var listOfStrings = new tblErrorMsgMappingVM().GetAll().ToList();
var ErrorMessage = listOfStrings.Find(x => Message.Contains(x.OriginalError));
if (ErrorMessage != null)
{
Message = ErrorMessage.ErrorMessage;
}
else
Message = "Unknown Error ,pelase review the log";
var value = new tblLocalizationRecordsVM().GetResourceValue(Message, "ErrorMsg");
return value;
}

Related

Microsoft Graph SDK Request Next Link of the Batch Response

I am using Microsoft Graph SDK to create a batch request that contains individual requests to request 20 different users. When I call GetNextLinkAsync() the result is always null. I have tried requesting 1000 different users using batch requests each containing 20 individual requests. This works fine, response is always returned in a single batch response.
I couldn't understand why the response is returned in single batch response content rather than giving me the link to fetch the next response?
Even though next link is null always, how can I follow it using Graph SDK? It is a string. It's not like next page request.
foreach (var batchRequest in batchRequests)
{
try
{
var responses = await PostBatchRequest(batchRequest.Request);
foreach (var id in batchRequest.RequestIds)
{
try
{
var user = await responses.GetResponseByIdAsync<User>(id);
users.Add(user.UserPrincipalName, user.Id);
} catch (ServiceException e)
{
logger.LogInformation(e.StatusCode);
}
}
} catch (ServiceException e)
{
logger.LogInformation(e.StatusCode);
}
}
I couldn't find proper documentation that tells you how to follow next link using Graph SDK or why it is always null for this type of requests, or are there any special type of requests for which next link is returned?
So a lot of this is framework stuff that's inside my wrapper classes, but the crux of the solution to your issue should be inside here:
var results = await batch.ParseAsync<ContactFolderContactsCollectionResponse, IContactFolderContactsCollectionPage>(response => {
var page = response.Value;
if (response?.AdditionalData != null && response.AdditionalData.ContainsKey("#odata.nextLink"))
{
page.InitializeNextPageRequest(Application.GraphConnection.Client, (string)response.AdditionalData["#odata.nextLink"]);
}
return page;
});
In this snippet I'm parsing out a ContactFolderContactsCollectionResponse from a batch with steps generated from a get request that would normally return a IContactFolderContactsCollectionPage. The ContactFolderContactsCollectionResponse is fetched by the wrapper internals using
GetResponseByIdAsync<ContactFolderContactsCollectionResponse>(id)
So it's pretty analogous to what you're doing except that there is probably some kind of UserResponse type that you should probably be using instead of User.
In my case the ContactFolderContactsCollectionResponse contains the IContactFolderContactsCollectionPage I actionally want in the Vvalue property hence:
var page = response.Value;
Now, IContactFolderContactsCollectionPage normally has a NextPageRequest property, but when you parse it directly from the ContactFolderContactsCollectionResponse, this is not filled out. Luckily, we can find the raw #odata.nextPage link in the ContactFolderContactsCollectionResponse's AdditionalData dictionary, and we can set it using the IContactFolderContactsCollectionPage.InitializeNextPageRequest methhod.
Hence the :
if (response?.AdditionalData != null && response.AdditionalData.ContainsKey("#odata.nextLink"))
{
page.InitializeNextPageRequest(Application.GraphConnection.Client, (string)response.AdditionalData["#odata.nextLink"]);
}
Hopefully that give you enough thread to pull on. Sorry if the rest of the syntax is confusing, as I said, a lot of it is operating in a wrapper framework I'm building and I
don't have time to build and test a clean solution.
It's also possible that the whole thing is different anyway on account of you having a batch with a thousand steps as opposed to a batch whose steps return thousands of objects like as in my case.
Either way, happy hunting.

.Net Core Identity 2 Provider login Cancel leads to unhandled exception

I've added LinkedIn as a provider. I have implemented the login and register with LinkedIn without any issue. In the use case where the user CANCELS from within the provider Pages (either linkedIn login or cancels the authorization of the app) the identity middleware seems to throw an unhandled exception:
An unhandled exception occurred while processing the request.
Exception: user_cancelled_login;Description=The user cancelled LinkedIn login
Unknown location
Exception: An error was encountered while handling the remote login.
Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler.HandleRequestAsync()
System.Exception: user_cancelled_login;Description=The user cancelled LinkedIn login
Exception: An error was encountered while handling the remote login.
The provider setup in startup defines the callback:
services.AddAuthentication().AddOAuth("LinkedIn", "LinkedIn", c =>
{
c.ClientId = Configuration["Authentication:LinkedIn:ClientId"];
c.ClientSecret = Configuration["Authentication:LinkedIn:ClientSecret"];
c.Scope.Add("r_basicprofile");
c.Scope.Add("r_emailaddress");
c.CallbackPath = "/signin-linkedin";
....
And As I have said the middleware seems to handled ALL other cases except where the user cancels within the LinkedIn pages. The return URL from LinkedIn looks correct:
https://localhost:44372/signin-linkedin?error=user_cancelled_login&error_description=The+user+cancelled+LinkedIn+login&state=CfDJ8MA7iQUuXmhBuZKmyWK9xeAgBBkQvnhf1akLhCIn9bsajCPUf7Wg22oeZBH9jZOIY3YrchMSWZ4dH7NQ1UngLKEuqgU-IHfBglbgJDtS-wc4Z-6DnW66uR0G1ubvNVqatFJHYv17pgqZT98suVkvKgihcJdbNEw7b1ThkuFbn9-5EcYhQ5ln6ImoTgthT8io1DOcCfc_-nBVfOa93a6CpUJTsZc9w93i70jn5dKKXSLntZe0VyRSA0r0PKc5spu5En-0R1rxiLjsjo4dy89PV3A
But never gets to my ExternalCallback controller method where the other cases like successful login/authorization are handled??
I'm wondering if this is working for anyone else with 3rd part providers?
There's a Github issue that explains what's happening here in more detail, with a bit of information as to why it's happening and even an indication that this won't be "fixed":
Handling the RemoteFailure event is the right thing to do. We should update our docs/samples to show how to handle that event and at least show a more appropriate message to the user. The error page sample could include a link to enabled the user to try logging in again.
Unfortunately it's difficult to implement this event in a very generic way that's also super useful because each remote auth provider has its own behavior for different types of failures.
The workaround for this (as quoted above) is to handle the RemoteFailure event:
services.AddAuthentication().AddOAuth("LinkedIn", "LinkedIn", c => {
// ...
c.Events.OnRemoteFailure = ctx =>
{
// React to the error here. See the notes below.
return Task.CompletedTask;
}
// ...
});
ctx is an instance of RemoteFailureContext, which includes an Exception property describing what went wrong. ctx also contains a HttpContext property, allowing you to perform redirects, etc, in response to such exceptions.
I've found the following to work well for me, based on this and similar to Kirk Larkin's answer. The part that took a little figuring out was where to redirect to, without causing problems for subsequent login attempts.
services.AddAuthentication().AddOAuth("LinkedIn", "LinkedIn", c =>
{
...
c.Events = new OAuthEvents()
{
OnRemoteFailure = (context) =>
{
context.Response.Redirect(context.Properties.GetString("returnUrl"));
context.HandleResponse();
return Task.CompletedTask;
}
};
};

MessageReceiver.RegisterMessageHandler throws exceptions continuously if network is down

I have successfully implemented a connection to ServiceBus with MessageReceiver using RegisterMessageHandler that starts a pump (from this example) and all seems to work just fine.
But in case of exception like e.g. when I turn off network connection the pump throws exceptions continuously to the ExceptionHandler. Every second or even faster. I am wondering if this is supposed default behavior and more importantly if it's possible to change, so that e.g. connection retries can happen every 1 minute. Or am I supposed to do Thread.Sleep or something to achieve that?
receiver.RegisterMessageHandler(
async (message, cancellationToken1) => await HandleMessage(receiver, message),
new MessageHandlerOptions(HandleException)
{
AutoComplete = false,
MaxConcurrentCalls = 1
});
P.S. This is how I solved it now, but not sure if it's a proper way:
private Task HandleException(ExceptionReceivedEventArgs args)
{
_logger.Error(...);
return Task.Delay(60000);
}
P.S Here is the RetryPolicy.Default dump:
Azure Service Bus has a default retry policy (RetryPolicy.Default), but given the transport is trying to receive messages and the broker is not available, will raise exceptions.
ExceptionReceivedContext provides a context, ExceptionReceivedContext which has an action that has failed, and the original exception. You can evaluate the action and decide what needs to be done. You could also check if the exception is transient or not. For transient errors, based on the action, you could just wait for the message to be retried again later (Receive action). In other cases you could either log an error or take a more specific action.
Try to configure the "RetryExponential" on your "SubscriptionClient" like this:
var receiver = new Microsoft.Azure.ServiceBus.SubscriptionClient(_serviceBusConnString, _topic, _subscription, this._receiveMode, new RetryExponential(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10), _retryPolicyMaximumRetryCount));
This is the parameters descriptions:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.servicebus.retryexponential?view=azure-dotnet
Here other post about what the properties means:
ServiceBus RetryExponential Property Meanings

WCF Web Services, returning an Error/exception string

I have a set of WCF web services, which, if an exception occurs, will use OutgoingWebResponseContext to return the error description back to the caller.
My problem is that sometimes, when something goes wrong, the web service is shown as failed, with an ERR_CONNECTION_RESET message, rather than returning the error message, and I would like to prevent this from happening.
For example, here's my beautiful C# code which queries my Northwind database, and returns a list of Customer names.
Or rather, it would do, but I've deliberately stuck an exception in there.
public List<string> GetAllCustomerNames()
{
// Get a list of unique Customer names.
//
try
{
throw new Exception("Oh heck, something went wrong !");
NorthwindDataContext dc = new NorthwindDataContext();
var results = (from cust in dc.Customers select cust.CompanyName).Distinct().OrderBy(s => s).ToList();
return results;
}
catch (Exception ex)
{
OutgoingWebResponseContext response = WebOperationContext.Current.OutgoingResponse;
response.StatusCode = System.Net.HttpStatusCode.InternalServerError;
response.StatusDescription = ex.Message;
return null;
}
}
In my AngularJS controller, I can call this web service...
$http.get('http://localhost:15021/Service1.svc/getAllCustomerNames')
.then(function (data) {
// We successfully loaded the list of Customer names.
$scope.ListOfCustomerNames = data.GetAllCustomerNamesResult;
}, function (errorResponse) {
// The WCF Web Service returned an error
var HTTPErrorNumber = errorResponse.status;
var HTTPErrorStatusText = errorResponse.statusText;
alert("An error occurred whilst fetching Customer Names\r\nHTTP status code: " + HTTPErrorNumber + "\r\nError: " + HTTPErrorStatusText);
});
...and if this exception occurs, I do see the full exception message...
Wonderful.
For all readers, who've wanted to know a simple, generic way to return and display Exceptions from your WCF web services, there's your solution !
Okay, so now I'll remove my Exception line of code, and the web service runs fine again. The Customer data is returned to the Angular controller without any problems.
But.. if an exception occurs when connecting to the database (for example, it times out, I have the wrong database name in my connection string, etc), then the following line of code does throw an exception...
NorthwindDataContext dc = new NorthwindDataContext();
...my catch code does kick in (I put a breakpoint on it to check), and we set the StatusDescription to the Exception message..
But the response which is sent back doesn't contain either my HTTP Status number or text.
My Angular controller just receives an HTTP Status Code of 0, with no StatusMessage.
And if I hit F12 in Chrome, you can see that it actually says the web service failed, rather than returning Status Code 403, and there's no message.
So my question is simply, is there a way to prevent this failure from happening ?
Obviously, its much friendlier to return a description of what went wrong, rather than just "The web service failed miserably... but we can't tell you why."
If I can get over this issue, this'd be a nice way to make all of our WCF web services error-message friendly in our in-house apps. But of course, for production systems, sure, you wouldn't really want to bombard the user with technical exception messages.
Update, many hours later..
I found the cause, and the solution.
Are you ready for this?
The problem was that when the DataContext line threw an exception...
NorthwindDataContext dc = new NorthwindDataContext();
...the exception message had a line-feed in it.
Cannot open database "Northwind" requested by the login.
The login failed.Login failed for user 'MikesWrongUserName'.This session has been assigned a tracing ID of '1f0513d1-9ce1-47ef-9d44-1f4546eb0b73'. Provide this tracing ID to customer support when you need assistance.
That line-feed was causing the problem. If you attempt to return that in a StatusDescription field, it causes the entire web service to be reported as "failed".
So, the solution is to simply remove any line-feeds before you return the exception message.
So here, finally, is an example of how to use a try..catch in your WCF web services, so they'll always return exception messages back to the caller.
public List<string> GetAllCustomerNames()
{
// Get a list of unique Company Names.
//
try
{
NorthwindDataContext dc = new NorthwindDataContext();
var results = (from cust in dc.Customers select cust.CompanyName).Distinct().OrderBy(s => s).ToList();
return results;
}
catch (Exception ex)
{
OutgoingWebResponseContext response = WebOperationContext.Current.OutgoingResponse;
response.StatusCode = System.Net.HttpStatusCode.InternalServerError;
// If a database Exception occurs, it might have a line-feed in it,
// which will cause the web service to completely fail (no Status
// Code or Status Message will get returned.)
response.StatusDescription = ex.Message.Replace("\r\n", "");
return null;
}
}
Thanks for all of your suggestions!

What to do/throw when you have hit a API limit

I am using a API with a limit, there is a high possibility that I could hit the limit.
I am wondering how people handle this? Do they check if they hit the limit and then throw an exception? If so what type of exception?
Are there any best practices?
I am able to see if I hit the limit like below:
if (!string.IsNullOrEmpty(result.error))
{
// we have hit a limit
}
This API is used for a MVC application.
I am caching the ActionResult methods with the API content ([OutputCache]). If the Action method does not recieve the API result then the view will be empty, but if i throw something it will end up on the custom errors page.
You should first log what happened using the information you receive from result.error and then create a custom exception and throw it including the original error message.
if (!string.IsNullOrEmpty(result.error))
{
// we have hit a limit
// log error
// throw new MyException(result.error);
}
Normally you can't do much in this type of error so you log it, throw the exception and it's somebody's else problem. When the exception is caught, you could decide, based on the exception type, to wait and retry.

Categories