How to Call a method from a Class Library Variably - c#

I am trying to find a solution that allows me to write one method in my forms project that can variably call multiple different methods from my class library project.
The reason for this being that I want to implement retry logic around these methods and prevent myself from repeating it for each different variety of method. The only consistent thing about the class library methods are that they all return Task<bool> so its easy to await on and perform logic with.
So far I have the following:
public async Task Runner(string methodName, params object[] parameters)
{
ThreadTimer.Start();
var tries = 0;
var ok = false;
while (tries <= 180)
{
try
{
var parameterTypes = (from p in parameters select p.GetType()).ToArray();
var mi = typeof(string).GetMethod(methodName, parameterTypes); //Currently returns null
var result = (Task<bool>)mi.Invoke(null, parameters);
ok = await result;
if (ok) break;
}
catch (Exception ex)
{
if (ex.InnerException == null)
{
ExceptionLabel2.Text = ex.Message;
}
else
{
ExceptionLabel1.Text = ex.Message;
ExceptionLabel2.Text = ex.InnerException.Message;
}
}
finally
{
tries++;
}
}
if (ok)
{
ThreadTimer.Dispose();
}
else
{
CShellControls.ExitWindowsEx(0, 0); //Logoff
}
}
The idea behind this is to declare a method name in a string and pass an array of parameters with it. I then used .GetMethod() to try and fetch the desired method info but unfortunately this returns null.
I have tried a few different methods but I'm open to suggestions and critique. As far as optimizing code goes I haven't really thought much into it, I just want to try and get this working first before approaching a more efficient method.
Thank you in advance!

Related

where the error coming from inside Try Catch

I am doing 5 things inside a try/catch. If there is a error, how can i tell which function the error is coming from. so on line Console.WriteLine("Invalid operation"); I want it to display which function the error is so that its easy to debug.
I am trying to avoid using 5 different try/catch in Main OnGet() method. I was thinking to put try/catch inside each sub-method but I am return IQueryable so I wont be able to return error as type string. even so I will end up have 5 different if statement to check for error in OnGet()
How do you guys handle something like this?
public async Task<IActionResult> OnGetAsync(int p = 1, int s = 20)
{
try
{
// get all Data
IQueryable<MY_Model> Query = await _services.Get_All_CoursesTaken();
// Add Filters
Query = AddFilters(Query );
// Add Sorting
Query = AddSorting(Query );
// Add Paging
Query = AddPaging(p, s, Query );
//Display Data
My_List= await Query.AsNoTracking().ToListAsync();
}
catch (InvalidOperationException)
{
Console.WriteLine("Invalid operation");
}
return Page();
}
private IQueryable<MY_Model> AddFilters(IQueryable<MY_Model> Query)
{
//some code
}
private IQueryable<MY_Model> AddSorting(IQueryable<MY_Model> Query)
{
//some code
}
private IQueryable<MY_Model> AddPaging(int p, int s, IQueryable<MY_Model> Query)
{
//some code
}
Maybe your solution is:
Tuple
You can return IQueryable and String as return type in methods.
private Tuple<IQueryable<MY_Model>,string> AddFilters(IQueryable<MY_Model> Query)

How to handle exceptions from API calls in Unity and pass them down to the UI?

I'm trying to figure out what to do with some errors in Unity when I call an API and how to propogate it up to the user interface - where and how to handle things. I've built aspnet APIs but there I'd normally use some error handling middleware to keep my controllers clean.
Let say we have some code like this (I'm using controller / repository language cos that's what I know).
A UI button fires an event like OnLoginButtonPressed.
An AuthController class reacts to the event by calling it's login method and then doing some logic when the response comes through, as follows:
public async void Login(LoginModel input)
{
var result = await AuthRepo.instance.Login(input);
app.token = result;
EventService.OnSuccessfulLogin();
}
The Auth.Repo calls the API and tries to return a Token class (just a wrapper around a JWT string)
public async Task<Token> Login(LoginModel input)
{
string json = JsonConvert.SerializeObject(input);
var request = UnityWebRequest.Post(app.baseURL + "authentication/login", json);
request.SetRequestHeader("Content-Type", "application/json");
request.SendWebRequest();
while (!request.isDone)
{
await Task.Yield();
}
if (request.result == UnityWebRequest.Result.Success)
{
Token token = JsonConvert.DeserializeObject<Token>(request.downloadHandler.text);
return token;
}
else
{
throw
}
}
So that's without exception handling. So I want to try to let the user know if there is a connection error, or they have put invalid details etc... I'm guessing I'm supposed add some logic into the AuthRepo such as:
if (request.result == UnityWebRequest.Result.Success)
{
Token token = JsonConvert.DeserializeObject<Token>(request.downloadHandler.text);
return token;
}
else if (request.result== UnityWebRequest.Result.ConnectionError)
{
throw new ConnectionException(request.error);
}
else if (request.result == UnityWebRequest.Result.DataProcessingError)
{
throw new BadRequestException(request.error);
}
else
{
throw new System.Exception(request.error);
}
This seems like a lot of code, and would end up in every method in every repo (unless I pull it out into some helper method?).... anyway, and then in the controller I would do something like:
try {
var result = await AuthRepo.instance.Login(input);
app.token = result;
EventService.OnSuccessfulLogin();
}
catch (ConnectionException ex)
{
EventService.OnConnectionError(ex.Message);
//some UI object would listen for this event and show the connection error message.
}
catch (BadRequestException ex)
{
EventService.LoginFailedError(ex.Message);
}
finally
{
EventService.UnknownError(ex.Message);
}
Is this completely down the wrong path? Seems like the code is just gonna get swamped with exception handling, or is this the correct way?
I've worked through a few YouTube videos that seem to suggest this is right, but they don't really show my use case (talking to APIs) so I'm just trying to be sure.
because UnityWebRequest.Result is an enum, you can start by using a switch statement here. Not only is this cleaner, it performs better too.
Another thing you can do is create an abstract class (e.g. APIException) and make that responsible for creating the correct exception instances, by giving it some static method like APIException FromUWRResult(UnityWebRequest.Result result).
Handling the exceptions can be done in APIException too. Give it an abstract method Handle() and implement accordingly in each of the deriving classes.
Now your code would look like this:
var ex = APIException.FromUWRResult(request.result);
if(ex != null) {
throw ex;
}
...
catch(APIException ex) {
ex.Handle();
}

delete azure table storage row without checking for existence

I've been using azure table storage for years, and I'm not sure what the "proper" way to do this is with the newest WindowsAzure.Storage library, version 5.0.1-preview (for use in a new ASP.NET 5 application):
Problem:
Given a partition key and row key, delete the row without checking for existence first, and without failing if it does not exist.
Current Solution: This code works... but the exception handling is confusing:
public async Task DeleteRowAsync(CloudTable table, string partition, string row)
{
var entity = new DynamicTableEntity(partition, row);
entity.ETag = "*";
var op = TableOperation.Delete(entity);
try
{
await table.ExecuteAsync(op);
}
catch (Exception ex)
{
var result = RequestResult.TranslateFromExceptionMessage(ex.Message);
if (result == null || result.HttpStatusCode != 404)
throw ex;
}
}
Questions:
The exception itself pointed me to this TranslateFromExceptionMessage method... I can't find a whole lot of information on that and WrappedStorageException (the type of the exception that is thrown). Is this some kind of new/preferred way to check for 404 errors on storage exceptions? Does anyone know if all storage exceptions will now use this, or do I need to write code to test and figure it out?
There is an InnerException of type StorageException. Presumably our older code that used StorageException.RequestInformation.HttpStatusCode could access this inner exception in the same way. Is that "OK", or is parsing these new XML error messages better or more robust somehow?
Is there a different approach altogether that I should be considering for this case?
If you are using the latest client (Azure.Data.Tables), the delete method automatically swallows 404 responses and does not throw. This approach avoids the need to write code that introduces race conditions (checking first before performing an operations) or having to handle this condition with a try/catch block.
If you want to know if the operation actually deleted a table or it didn't exist, you can inspect the Status property of the response.
Response response = await tableClient.DeleteAsync();
if (response.Status == (int)HttpStatusCode.NotFound)
{
// entity didn't exist)
}
The RequestResult.TranslateFromExceptionMessage method is now marked [Obsolete] and I wanted a way to ignore 404's myself.
Based on your tip to check out the RequestInformation.HttpStatusCode I came up with the following:
try
{
await table.ExecuteAsync(op);
}
catch (StorageException storEx)
{
if (storEx.RequestInformation.HttpStatusCode != 404)
{
throw;
}
}
There is a similar approach found in the AspNet WebHooks project when configured to use Azure Table Storage. Take a look at the Microsoft.Aspnet.WebHooks.custom.AzureStorage StorageManager class.
I'm not sure this adds much on top of what you'd already found, but they handle everything without throwing an exception and always return a status code so you can react to that as necessary.
One difference here is they pass in the table and the operation to a multi-purpose ExecuteAsync method, rather than having one specifically for delete, but that's just an implementation detail.
Relevant code from their example:
public async Task<TableResult> ExecuteAsync(CloudTable table, TableOperation operation)
{
if (table == null)
{
throw new ArgumentNullException(nameof(table));
}
if (operation == null)
{
throw new ArgumentNullException(nameof(operation));
}
try
{
var result = await table.ExecuteAsync(operation);
return result;
}
catch (Exception ex)
{
var errorMessage = GetStorageErrorMessage(ex);
var statusCode = GetStorageStatusCode(ex);
var message = string.Format(CultureInfo.CurrentCulture, AzureStorageResources.StorageManager_OperationFailed, statusCode, errorMessage);
_logger.Error(message, ex);
return new TableResult { HttpStatusCode = statusCode };
}
}
public string GetStorageErrorMessage(Exception ex)
{
if (ex is StorageException storageException && storageException.RequestInformation != null)
{
var status = storageException.RequestInformation.HttpStatusMessage != null ?
storageException.RequestInformation.HttpStatusMessage + " " :
string.Empty;
var errorCode = storageException.RequestInformation.ExtendedErrorInformation != null ?
"(" + storageException.RequestInformation.ExtendedErrorInformation.ErrorMessage + ")" :
string.Empty;
return status + errorCode;
}
else if (ex != null)
{
return ex.Message;
}
return string.Empty;
}
public int GetStorageStatusCode(Exception ex)
{
return ex is StorageException se && se.RequestInformation != null ? se.RequestInformation.HttpStatusCode : 500;
}

Does .BeginInvoke always need .EndInvoke for Threadpool threads?

So C#/.NET question. Do I always need to call .EndInvoke when invoking asynchronously with .BeginInvoke some method? I have read somewhere it is mandatory, but the problem is .EndInvoke will block execution? Is there some kind of universal solution?
Yes, you do have to call EndInvoke().
but the problem is .EndInvoke will block execution?
Not when you call it from the callback method, which is the proper patttern.
Yes, it is mandatory for 2 reasons:
1) to avoid possible resoure leak
2) to catch any Exception that might have been thrown
Below is example code:
public delegate void DelegateHelper2(..parameters...);
private void ff(..parameters...);{}
DelegateHelper2 myDelegate = new DelegateHelper2(ff);
// invoke asynchronyously
IAsyncResult result = myDelegate.BeginInvoke(..parameters..., CallBackEmpty, null);
....
private void CallBackEmpty(IAsyncResult iasync)
{
if (iasync != null)
{
string typeName = "";
try
{
System.Runtime.Remoting.Messaging.AsyncResult aresult =
(System.Runtime.Remoting.Messaging.AsyncResult)iasync;
object action1 = aresult.AsyncDelegate;
Type actionType = action1.GetType();
typeName = actionType.ToString();
if (action1 != null)
{
//action1.EndInvoke(iasync);
actionType.InvokeMember("EndInvoke",
System.Reflection.BindingFlags.InvokeMethod, null,
action1, new object[] { iasync });
}
}
catch (Exception ex)
{
string msg = "CallBackEmpty; for type: " + typeName +
" ;Exception: " + ex.ToString();
Setup_TraceExceptions(msg);
}
}
}
So, it seems people are confused with tricks applied above. I will explain. Here is your regular solution, when using .BeginInvoke to spawn a thread and forget it:
private void ff(..parameters...);{}
DelegateHelper2 myDelegate = new DelegateHelper2(ff);
// invoke asynchronyously
IAsyncResult result = myDelegate.BeginInvoke(..parameters..., CallBack2, myDelegate);
private void CallBack2(IAsyncResult iasync)
{
if (iasync != null)
{
try
{
DelegateHelper2 action1 = (DelegateHelper2)iasync.AsyncState;
action1.EndInvoke(iasync);
}
catch (Exception ex)
{
//Trace exeption somehow
}
}
}
There are problems:
1) You need to pass separtely callBack delgate and delgate itself
2) If you are using this pattern offten, (spawning threads in this way), you need for each .BeginInvoke to write a new CallBack method, becous inside it you refer to specific delegate type(DelegateHelper2). ( I in my code have maybe 8 such calls, that would result in 8 different CallBack methods etc. )
Above example does trick and solves those problems, in a this way:
1) You pass only CallBack delegate, action1 is obtained from IAsyncResult
2) Only one CallBack method is needed, since it does not depend on delegate type (that is solved by reflection)

.NET error handling

I have been writing .NET applications and have been impressed with the error handling included in the framework.
When catching an error that has been throw by the processes or somewhere in the code I like to include the message (ex.Message, which is usually pretty general) but also the stacktrace (ex.stacktrace) which helps to trace the problem back to a specific spot.
For a simple example let's say for instance that we are recording numbers to a log in a method:
public void ExampleMethod(int number){
try{
int num = number
...open connection to file
...write number to file
}
catch(Exception ex){
.... deal with exception (ex.message,ex.stacktrace etc...)
}
finally{
...close file connection
}
}
Is there any way to see the method called (in this case ExampleMethod) with the specific number that was passed that potentially crashed the method call? I believe you could log this perhaps in the catch block but I am interested essentially in catching the method call and parameters that caused the system to throw the exception.
Any ideas?
I suggest stuffing the parameter values into the exception's Data dictionary, e.g.
public void ExampleMethod(int number) {
try {
int num = number
...open connection to file
...write number to file
}
catch(Exception ex) {
ex.Data["number"] = number;
//.... deal with exception (ex.message,ex.stacktrace etc...)
}
finally {
//...close file connection
}
Another advantage of this method is that you can stuff the parameters in the catch block, then re-throw the exception and log it somewhere else without losing the stack trace, e.g.
catch(Exception ex) {
ex.Data["number"] = number;
throw;
}
If you want to know the value of the parameters in your method, then there is only one way, IMO, to do it - you need to repackage the exception with data.
For example:
int param1 = 10;
string param2 = "Hello World";
try
{
SomeMethod(param1, param2)
}
catch(SomeExpectedException e)
{
throw new MyParameterSensitiveException(e, param1, param2);
}
You basically repackage the original exception as the inner exception of another exception, and additionally supply the parameters you used to call the method. Then you could inspect that in some way to figure out what went wrong.
The accepted answer and many of the solutions described will work fine but what you're doing is littering your source with a slightly different blob of code depending on what parameters are in your method signature.
When it comes time to add a new parameter you need to remember to update your handler to add that new parameter. Or if you remove a parameter then you need to remember to remove the parameter from your exception handler.
What if you have a two or more try..catch blocks? Then you now have two blocks of code to keep up to date. Definitely not refactor friendly.
Another approach is to remove the logging code use a technique called Aspect Oriented Programming.
One such tool to facilitate this is a product called PostSharp.
With PostSharp you can write a logger than is invoked whenever an exception is thrown without the need for messy method and parameter specific code. For example (using version 1.5 of PostSharp):
LoggerAttribute.cs -
[Serializable]
public class LoggerAttribute : OnExceptionAspect
{
public override void OnException(MethodExecutionEventArgs eventArgs)
{
Console.WriteLine(eventArgs.Method.DeclaringType.Name);
Console.WriteLine(eventArgs.Method.Name);
Console.WriteLine(eventArgs.Exception.StackTrace);
ParameterInfo[] parameterInfos = eventArgs.Method.GetParameters();
object[] paramValues = eventArgs.GetReadOnlyArgumentArray();
for (int i = 0; i < parameterInfos.Length; i++)
{
Console.WriteLine(parameterInfos[i].Name + "=" + paramValues[i]);
}
eventArgs.FlowBehavior = FlowBehavior.Default;
}
}
You then decorate your classes with the LoggerAttribute:
[Logger]
public class MyClass
{
public void MyMethod(int x, string name)
{
// Something that throws an exception
}
}
Anything that throws an exception in MyMethod will cause the OnException method to be executed.
There are two versions of PostSharp. Version 1.5 is free and open sourced under the GPL and is targeted at .NET 2.0. PostSharp 2.0 is not entirely free but its community edition will support the basic functionality described above.
In order to do this:
public void MyProblematicMethod(int id, string name)
{
try
{
object o = null;
int hash = o.GetHashCode(); // throws NullReferenceException
}
catch (Exception ex)
{
string errorMessage = SummarizeMethodCall(MethodBase.GetCurrentMethod(), id, name);
// TODO: do something with errorMessage
}
}
...and get this:
"MyProblematicMethod invoked: id = 1, name = Charlie"
...you could do something like this:
public static string SummarizeMethodCall(MethodBase method, params object[] values)
{
var output = new StringBuilder(method.Name + " invoked: ");
ParameterInfo[] parameters = method.GetParameters();
for (int i = 0; i < parameters.Length; i++)
{
output.AppendFormat("{0} = {1}",
parameters[i].Name,
i >= values.Length ? "<empty>" : values[i]
);
if (i < parameters.Length - 1)
output.Append(", ");
}
return output.ToString();
}
You could make a class that inherits Exception and add some arguments to it so you could pass the number to it.
You can get the method name and the parameters like this,
try
{
int a = 0;
int i = 1 / a;
}
catch (Exception exception)
{
StackTrace s = new StackTrace(exception);
StackFrame stackFrame = s.GetFrame(s.FrameCount - 1);
if (stackFrame != null)
{
StringBuilder stackBuilder = new StringBuilder();
MethodBase method = stackFrame.GetMethod();
stackBuilder.AppendFormat("Method Name = {0}{1}Parameters:{1}", method.Name, Environment.NewLine);
foreach (ParameterInfo parameter in method.GetParameters())
{
stackBuilder.AppendFormat("{0} {1}", parameter.ParameterType.FullName, parameter.Name);
stackBuilder.AppendLine();
}
// or use this to get the value
//stackBuilder.AppendLine("param1 = " + param1);
//stackBuilder.AppendLine("param2 = " + param2);
}
}
I am not sure whether you can get the parameter values directly off the stack like a debugger.
The Automatic Exception Handling from Crypto Obfuscator can do what you need.
The exception reports include all pertinent information including full stack trace info along with the values of all method arguments and local variables, plus the system information, the time of the exception, the build number, and optional developer defined custom data like log files, screenshots, etc.
DISCLAIMER: I work for LogicNP Software, the developer of Crypto Obfuscator.

Categories