I have to create a bunch of methods that look like this. The things that change will be the method name, the return type and the lines marked in the middle - the rest will be the same. Is there a clean way to refactor this so that I don't repeat myself?
private bool CanPerform(WindowsIdentity identity, string applicationName, int operation)
{
IAzApplication3 application = null;
IAzClientContext3 context = null;
try
{
application = this.store.OpenApplication(applicationName, null) as IAzApplication3;
ulong token = (ulong)identity.Token.ToInt64();
context = application.InitializeClientContextFromToken(token, null) as IAzClientContext3;
// lines that change go here
}
catch (COMException e)
{
throw new SecurityException(string.Format("Unable to check operation '{0}'", operation), e);
}
finally
{
Marshal.FinalReleaseComObject(context);
Marshal.FinalReleaseComObject(application);
}
}
I realise this is probably basic stuff but I work alone so there's no one else to ask.
It sounds like a delegate would be appropriate here, with a generic method to cover the return type changing:
private T ExecuteWithIdentity<T>(WindowsIdentity identity,
string applicationName, int operation,
Func<IAzApplication3, IAzClientContext3, T> action)
{
IAzApplication3 application = null;
IAzClientContext3 context = null;
try
{
application = this.store.OpenApplication(applicationName, null) as IAzApplication3;
ulong token = (ulong)identity.Token.ToInt64();
context = application.InitializeClientContextFromToken(token, null) as IAzClientContext3;
return action(application, context);
}
catch (COMException e)
{
throw new SecurityException(
string.Format("Unable to check operation '{0}'", operation), e);
}
finally
{
Marshal.FinalReleaseComObject(context);
Marshal.FinalReleaseComObject(application);
}
}
Then you put the code for each check in a separate method, or even just use a lambda expression:
bool check = ExecuteWithIdentity(identity, "Foo", 10,
(application, context) => context != null);
or
string check = ExecuteWithIdentity(identity, "Foo", 10, SomeComplexAction);
...
private static string SomeComplexAction(IAzApplication3 application,
IAzClientContext3 context)
{
// Do complex checks here, returning whether the user is allowed to
// perform the operation
}
You may want to change the delegate type of course - it's not clear what operation is meant to be used for, for example.
I would also strongly consider casting instead of using as. If the application or context is returned from OpenApplication/InitializeClientContextFromTokenas a non-null value which just isn't the right type, do you really want to handle that the same was as a null value being returned?
You could do your error handling slightly higher up the stack, so rather than catching and rethrowing the exception inside the method you could do it where the method is called?
If your method calls are all wrapped in a Manager class that might save a bit of time. If they're just ad-hoc called everywhere then naturally maybe not :)
I hope that might help.
Related
I'm running into an odd scenario that doesn't happen on my PC, but does for a coworkers.
I have this piece of code:
LoaderHelpers.SetStringValue<blah>(this, "x", $"x response in Header",
() => jsonData.x.response[0].value, false);
The problem is that sometimes, "jsonData.x" is null and, for my coworker a 'cannot bind to null at runtime exception' is thrown, but not for me there isn't. I have code to handle the null scenario, but it's like his code never gets to that point and fails at the call level.
jsonData is of type dynamic.
The method code that handles the null scenario:
public static void SetStringValue<T>(IValidate data, string propertyName,
string valuePath, Func<string> value, bool required)
{
if (data.GetType().GetProperty(propertyName) != null)
{
try
{
if (string.IsNullOrEmpty(value()))
{
if (required)
data.DataValidationErrors.Add($"{valuePath} can't be empty");
data.GetType().GetProperty(propertyName).SetValue(data, null);
}
else
{
data.GetType().GetProperty(propertyName).SetValue(data, value());
}
}
catch
{
//property doesn't exist
if (required)
data.DataValidationErrors.Add($"{valuePath} doesn't exist");
data.GetType().GetProperty(propertyName).SetValue(data, null);
}
}
else
{
throw new NullReferenceException($"In {data.GetType()} => SetStringValue. " +
$"Passed property {propertyName}, but property doesn't exist.");
}
}
Again. Works perfect for me, but not for him. I'm completely lost. Maybe I don't understand how the lamba/function parameters work 100%, but I thought it only got evaluated when value() is invoked.
I should also mention that when I debug this code, I can step into the Nuget package and when he hits the same line, he can't. This maybe a useful hint.
If jsonData (or jsonData.x) is null (as it seems to be at this point) it will crash and give you that error every time you call the method value().
You need to check why jsonData.x is null. Maybe it´s a race condition caused by another thread setting this value to null, maybe it´s because a bad jsonData initialization... Can´t say since that code is not here.
There are so many things wrong with your code, i can't resist.
First of all, instead of copy/pasting the same stuff over and over, you might want to use a variable:
var property = data.GetType().GetProperty(propertyName);
Second, you pass a Func<string> and execute it multiple times, why is it even a function then? Yet again, better only evaluate it once and use a variable...
var unwrapped = value();
That would solve the issue, that Roberto Vázquez' answer adresses.
Then you are misusing NullReferenceException, instead rather use a ArgumentException
Next issue, that valuePath is only used in the exception message, that is a poor design to my beliefs.
The generic T parameter isnt even used, so get rid of it.
Last but not least, that catch-block doing the exact thing that could possibily throw the exception again, i cant see any reason why you would do this.
Finnaly this whole thing becomes a little more clear but its still a mess.
public static void SetStringValue(IValidate data, string propertyName,
string valuePath, Func<string> value, bool required)
{
if(data == null)
throw new ArgumentNullException(nameof(data));
var property = data.GetType().GetProperty(propertyName);
if(property == null)
throw new ArgumentException($"In {data.GetType()} => SetStringValue. " +
$"Passed property {propertyName}, but property doesn't exist.");
var unwrapped = value();
try
{
if (string.IsNullOrEmpty(unwrapped))
{
if (required)
data.DataValidationErrors.Add($"{valuePath} can't be empty");
unwrapped = null; // this might be unecessary.
}
property.SetValue(data, unwrapped);
}
catch(Exception e)
{
// This is probably a bad idea.
property.SetValue(data, null);
if (required)
data.DataValidationErrors.Add(Atleast put a better message here. e.Message ...);
}
}
How do I know the log the last property that is null?
For example,
var a = "somevalue";
......
......
if(a == null)
{
Log.Error(MethodBase.GetCurrentMethod().Name + "Property : a is null");
//blah blah
}
Like how I use the reflection to get the current method name, there should be some means by which I can log the latest local variables (or a property or fields)
that is being compared ? I use, log4net by the way to log the errors.
1) Is there any method to achieve this or should we manually log it?
2) Is there any custom method that prints the class -> MethodName -> Propertyname(or FieldName) that is null?
Thanks for your time in advance.
As mentioned by #fsimonazzi, "a" would be a local variable.
That being said there is still no way to examine the current compare operation as in MSIL there is no formal concept of an IF block - only conditional jumps.
If you wanted to get really crazy with the reflection, you may be able to find the current executing instruction and look around near that for a variable, but even then, you will not find the name - only a reference - as names are only used prior to compilation.
Either way, reflection is not going to help you here.
Instead, try using Exceptions - specifically ArgumentNullException. This body of code would become:
void doStuff(string param1, int param2)
{
if (param == null)
throw new ArgumentNullException("param1", "param1 must not be null");
if (param2 < 0)
throw new ArgumentOutOfRangeException("param2", "param2 should be non-negative.");
//method body
}
then, when you call the method, you can catch the exception and log it - no matter what it may be.
public static void Main(string[] args)
{
try
{
doStuff(null, 3);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
Tools like FxCop can help make sure that you are properly validating each parameter.
Properties are actually implemented as methods, so reflection could help you there. If, for example, you were validating in a property and wanted to log the position automatically, you could.
private object _cachedObject = null;
public object CachedObject
{
get
{
if (_cachedObject == null)
{
log(MethodBase.GetCurrentMethod().Name, "creating cached object");
_cachedObject = createCachedObject();
}
return _cachedObject;
}
}
The .Net Framework 4.5 also brings with it a new attribute that can be used to replace the MethodBase.GetCurrentMethod().Name construct you are using to get the method name. See [CallerMemberNameAttribute][3].
I have a class that tries to get information from web service few times:
public TResult Try(Func<TResult> func, int maxRetries)
{
TResult returnValue = default(TResult);
int numTries = 0;
bool succeeded = false;
while (numTries < maxRetries)
{
try
{
returnValue = func();
succeeded = true;
}
catch (Exception ex)
{
Log(ex,numTries);
}
finally
{
numTries++;
}
if (succeeded)
{
return returnValue;
}
else
{
if (numTries == maxRetries)
{
//ask user what to do
}
}
}
Now after 'if (numTries == maxRetries)' user will be able to chose if he wants to continue trying to get data from web service or cancel.
I want to just open new form when user cancels and stop executing method that called above method. I can't just return null or new object because the method that run this retrier will continue to work and in many cases cause problems.
So basically this looks like this:
someValue = retry.Try(() => webService.method(),maxRetries));
//if user canceled after app wasn't able to get data stop execution as already another form is opened
I could of course check if returned value was null like:
someValue = retry.Try(()=>webService.method(),maxRetries));
if (someValue == null)
return;
But this would mean a lot of changes in the code and I want to avoid it and it would be best if I could do it from Try method.
I can think of two things. You could make sure that TResult is of an Interface type that has a Boolean field that represents a successful request (IsSuccessful or IsValid, etc). If you cannot modify TResult, the other option is to use an Out parameter on your try method to pass another value out.
There is no way to just stop the execution of a method. The first thing that comes to mind though is to throw an exception and catch it from the calling method.
Keep in mind though that you shouldn't ever rely on exceptions to control flow like that.. but if you really can't rewrite the calling method, this may be your only option.
The other option is perhaps having your returned result set a flag (via an interface) to notify the caller that it completed successfully.
I would like to use a COM object in my application.
How can I make sure the object is registered in the machine?
The only solution I found (also on SO) was to use a try-catch block around the initialization:
try {
Foo.Bar COM_oObject = new Foo.Bar();
} catch (Exception ee) {
// Something went wrong during init of COM object
}
Can I do it in any other way?
I feel its wrong to deal with an error by expecting it and reporting it, I would rather know I will fail and avoid it to begin with.
You are using exception handling the right way: to fail gracefully from a specific situation that you know how to recover from.
There's not a problem with using try-catch in this case, but you could at least catch more specifically : ComException.
"I feel its wrong to deal with an error by expecting it and reporting it"
Isn't it exactly the purpose of try-catch? BTW, an Exception occurs when something really bad has happened and since it is a pretty bad thing that the COM object you are referring to is not registered, therefore, an Exception is the perfect solution. And you can't handle an exception in any other way.
I think this is the right way to do it.
If you know your component's ProgId. You could try this trick
comType = Type.GetTypeFromProgID(progID,true/*throw on error*/);
If you're doing this a lot and wish you had a non-exception throwing equivalent, try:
public static class Catching<TException> where TException : Exception
{
public static bool Try<T>(Func<T> func, out T result)
{
try
{
result = func();
return true;
}
catch (TException x)
{
// log exception message (with call stacks
// and all InnerExceptions)
}
result = default(T);
return false;
}
public static T Try<T>(Func<T> func, T defaultValue)
{
T result;
if (Try(func, out result))
return result;
return defaultValue;
}
}
So now you can do this:
Foo.Bar newObj;
if (!Catching<ComException>.Try(() => new Foo.Bar(), out newObj))
{
// didn't work.
}
Or if you have a default object stored in defaultMyInterface you'd use to implement an interface if there's nothing better:
IMyInterface i = Catching<ComException>.Try(() => new Foo.Bar() as IMyInterface,
defaultMyInterface);
You can also do this, in a completely different scenario:
int queueSize = Catching<MyParsingException>
.Try(() => Parse(optionStr, "QueueSize"), 5);
If Parse throws a MyParsingException, queueSize will default to 5, otherwise the returned value from Parse is used (or any other exception will propagate normally, which is usually what you want with an unexpected exception).
This helps to avoid breaking up the flow of the code, and also centralises your logging policy.
I was writing some try-catch blocks for various methods today, and thought to myself it would be good to have utility method which would automatically call the method again for a number of times specified in a parameter, at a certain time.
However, I thought to myself, the method/property etc which will cause an exception will be at the top of the stacktrace (do property calls get put on the stacktrace?) in a single threaded application (so an application with no code relating to threading). So I can simply get the method name at the top and dynamically call it again.
So I would have code like:
string s = StackTrace.GetFrame(0).GetMethodName; (I can't remember the exact syntax).
With this method, I can execute it using an activator or one of several other ways.
But in a multi-threaded application, I could have several methods firing at once and I wouldn't know which one finishes first/last. So I can't expect a method for which I write a try-catch block to be at the top of the stack.
How would I go about achieving this?
Please don't do this. It's a really, really, really, really, really bad idea.
Maybe not as bad as deleting files randomly, if the hard drive runs out of room - but just about as bad.
While I question the need for an auto retrying mechanism (does randomly retrying really help you out in so many situations that you need a utility method?) - using StackTrace and Reflection is, at best, a terribly complicated solution.
Not that I suggest that anyone actually use this code, but I'd probably go with a delegate based approach to this particular problem:
public static class Extensions {
public static void Try(this Action a, int maxTries) {
new (Func<bool>(() => { a(); return true; })).Try(maxTries);
}
public static TResult Try<TResult>(this Func<TResult> f, int maxTries) {
Exception lastException = null;
for (int i = 0; i < maxTries; i++) {
try {
return f();
} catch (Exception ex) {
lastException = ex;
}
}
throw lastException;
}
}
Usage is a bit unorthodox, but fairly clear I think:
// Set a property
new Action(() => myObject.Property = 5).Try(5);
// With a return value
var count = new Func<int>(() => myList.Count).Try(3);
You can't inline a lambda to a method, but you could have a somewhat fluent interface:
Utilities.Try(
() => MyObject.Property = 5
).Repeat(5);
And multi line methods:
Utilities.Try(() => {
MyObject.Property1 = 5;
MyObject.Property2 = 6;
MyObject.Property3 = 7;
}).Repeat(5);
Mark's code is probably better, but here's mine...
If you really want to do something like this, I'd use code something like this. Yes, you still have to manually call it, but your idea of indiscriminately retrying ALL excepting methods is a really, really bad idea.
public class TryAgain
{
public delegate void CodeToTryAgain ();
public static void Repeat<E>(int count, CodeToTryAgain code) where E : Exception
{
while (count-- > 0)
{
try
{
code();
return;
}
catch (E ex)
{
Console.WriteLine("Caught an {0} : {1}", typeof(E).Name, ex.Message);
// ignoring it!
}
}
}
}
And then you'd call your failing method, ThrowTwice, or whatever you want to do, like this:
TryAgain.Repeat<MyException>(5, delegate()
{
ThrowTwice();
});
In this example, the Repeat method will ignore all exceptions of type MyException, trying to call ThrowTwice up to 5 times...
You can add your own sleeping and time-outs, and whatever.