I'm writing a class called Category which has 2 static methods for retreiving XML data from an external resource. In my example below I'm only going to show one because they're very similar.
What I'm trying to find out is whether this code is "Safe" in terms of invalid URLs, invalid data etc.. basically make it more robust. Here's teh codes
private static string XmlUri
{
get { return "path-to-xml-file"; }
}
private static XDocument XmlFile { get; set; }
public int ID { get; set; }
public string Name { get; set; }
public int Parent { get; set; }
/// <summary>
/// Gets a specific category
/// </summary>
/// <param name="id"></param>
/// <returns>A Category with the specified ID</returns>
public static Category Get(int id)
{
try
{
if (XmlFile == null)
XmlFile = XDocument.Load(XmlUri);
}
// Invalid URL or data
catch (Exception ex)
{
// TODO: Log exception
Console.WriteLine(ex.Message);
}
if (XmlFile == null)
return null;
var cat = from category in XmlFile.Descendants("Category")
where category.Attribute("id").Value.ParseSafe() == id
select new Category
{
ID = category.Attribute("id").Value.ParseSafe(),
Parent = category.Attribute("parent").Value.ParseSafe(),
Name = category.Value
};
return cat.SingleOrDefault();
}
Define 'safe'. Your code will produce null when something is wrong. I would consider a (re-)throw in the catch block after XDocument.Load(). To be safe in not ignoring an invalid URL.
And that puts the ParseSafe() and SingleOrDefault into question as well. What do you want to happen if an id is missing or malformed?
And, a small improvement: You could put the Load-on-Demand logic into the getter of XmlFile. Makes it easier if you also want other elements beside Category.
Not thread safe as ChaosPandion mentioned.
Confusing performance behavior - Get(int) looks like simple fast method, but actually involves non-trivial work. Use lazy initialization and read whole collection of categories onece into dictionary.
Should not catch Exception and swallow it - either use specific ones (I think IOException and XMLExcepetion in this case) or at least let fatal exceptions to be thrown normally.
Obviously if you don't contol XML file it can also cause slownes/hangs while loading insanely large files. Depending on behavior of reader and complexity of XML (if given to you by malicious party) could cause some other exceptions like StackOverflow killing your process.
Related
I would like check no null parameters are assigned to record fields and let the properties have comments. I have found out the following arrangement does the trick for comments, but I lack ideas to check for null parameters without turning this record into a class.
So, a question: Is it possible to check during runtime that nulls won't be assigned to record fields? If so, how could one do it while still using records?
public record Test(string TestString)
{
/// <summary>
/// This is one way to get a comment on record properties. Are there others?
/// </summary>
public string TestString { get; init; } = TestString;
}
The code is also as a gist here.
This is an addition, but maybe helps with the accepted answer and the comment of different code.
It was because the code in the gist did a null check like
public record Test(string TestString)
{
/// <summary>
/// This is one way to get a comment on record properties. Are there others?
/// </summary>
public string TestString { get; init; } = TestString ?? throw new ArgumentNullException();
}
For a reason or another, I didn't include this pondering in the original question if there's maybe a shorter way. :)
<edit: The .NET 6 ArgumentNullException.ThrowIfNull(obj) could be handy here (or ThrowHelper).
You have to handle checks during inline assignment, as you've already discovered in your gist.
One possibility is to call an extension method to wrap any behavior.
public record Test(string TestString)
{
/// <summary>
/// This is one way to get a comment on record properties. Are there others?
/// </summary>
public string TestString { get; init; } = ValidationExtensions.Validate(TestString);
}
public static class ValidationExtensions
{
public static string Validate(string input)
{
if (string.IsNullOrEmpty(input))
throw new NullReferenceException();
return input;
}
}
This will correctly throw during initialization of the record:
var x = new Test(null);
When I look at a method in the .NET Framework, it can throw several possible exceptions.
From a planning perspective, what do I need to ask to plan and handle these exceptions? I understand that depending on the impact of an exception, that would influence showing it in the UI layer. For example, if a process at the back end which is opaque to the user experience throws an exception, you would not want to show that to the user as s/he would have no idea what that is.
Thanks
I wanted to write it as a comment but it is to long for the comment textbox...
There are exceptions that are important to show the users because they can handle it by themselves, for example: file name is illegal.
There are exceptions that i find important to show the users because they (the users) will function as my QA team, for example: some method will not update the GUI and they probably will get to the conclusion that they should report that further on, they will show me the exception and i will discover that my array is out of bounds...
there are exceptions that promoting them to the user will just confuse them and like you said
"s/he would have no idea what that is"
for example, For example:
"if a process at the back end which is opaque throws an exception".
those exception i am saving for myself (in database..)..
I am always reminding myself that the end user has a different psychology compare to a developer (-:
I hope i understood your question in the right manner.
You'd normally have a business logic layer in your application, and you'd wrap the methods in that library in safe calls. Those methods may even say what exceptions they can throw, and you may want to handle those exceptions in a unique way if you so wish.
Here's an example of a couple of classes that can handle both unexpected and custom exceptions:
class Program
{
static void Main(string[] args)
{
MethodInvokationResult result = SafeActionInvokator.HandleSafely(() =>
{
MyFakeBusinessEngine.DivideTwoNumbers(5, 0);
});
if (result.Exception is System.DivideByZeroException)
{
Debug.WriteLine($"A divide by zerp exception was caught");
}
else if (!result.Success)
{
Debug.WriteLine($"An unknown error occured.");
}
}
}
^ You can see that you can wrap the calls and handle them in a sensible way.
public class MethodInvokationResult
{
public bool Success { get; set; }
public Exception Exception { get; set; }
}
^ A simple result class
public static class MyFakeBusinessEngine
{
/// <summary>
/// Divides two numbers
/// </summary>
/// <param name="a">numerator</param>
/// <param name="b">denominator</param>
/// <returns>the result</returns>
/// <exception cref="System.DivideByZeroException">When b is zero, divide by zero exception is thrown.</exception>
public static int DivideTwoNumbers(int a, int b)
{
return a / b;
}
}
^ A well documented method, that even tells other developers what exceptions it expects to throw
public static class SafeActionInvokator
{
/// <summary>
/// Executes a method, and if any exception is thrown, will log the error and swallow the exception.
/// </summary>
/// <param name="methodToExecute"></param>
public static MethodInvokationResult HandleSafely(Action methodToExecute)
{
try
{
methodToExecute.Invoke();
return new MethodInvokationResult()
{
Exception = null,
Success = true
};
}
catch (Exception ex)
{
Debug.WriteLine($"{ex}");
return new MethodInvokationResult()
{
Exception = ex,
Success = false
};
}
}
}
^ The wrapper for the method you call, wrapping this in a try catch allows you to handle all exceptions in the same way, or put any custom logic you'd like in there.
This can be expanded to be a call that can return any actual result value too. You could make a generic result class instead of the simple one I've shown.
FINALLY! As to your actual question, I'd create some of these layers throughout your application, and re-throw any exceptions with a severity rating included. These would propagate to your UI layer and you can chose what to do based on Severity.
Maybe even something like this!
public class MajorException : Exception { }
public class MediumException : Exception { }
public class MinorException : Exception { }
public class UserError : Exception { }
Hope this helps!
I have a class that has a string property for which I'd like to limit the possible values to a set defined dynamically (e.g. stored in the database, though we're using code-first EF6). Using an Enum is obviously out. I did some reading about Code Contracts and like the look of that, but don't know the first thing about establishing a Contract.Requires that pulls back a set of values. Lambda, maybe? I'm on the bleeding edge of my understanding here.
Here's some sample code:
public class Rule
{
/// <summary>The Conditions associated with this Rule
/// </summary>
public ICollection<Condition> Conditions { get; set; }
// ... some other stuff ...
/// <summary>The Status of the Rule.
/// </summary>
public string RuleStatus
{
get{}
set
{
// Here's where I want to dynamically determine values
Contract.Requires(value == "Inactive"||"Obsolete");
// Perhaps something like this,
// where GetValidRuleStatuses returns an array of string??
Contract.Requires(GetValidRuleStatuses().Contains(value));
}
}
One way to do this, is to write custom code to actually perform the check as and when you need to.
In terms of data structures, I'd recommend a HashSet<string> for fast lookups, which you will need to populate:
//Cache this somewhere, until the values change
var allowedValues = new HashSet<string>(stringValues);
if(!allowedValues.Contains(attemptedValue))
{
//Throw exception?
}
I am trying to get from State "A" to State "X".
There are transitions in place that prevent me from just going to X.
I can export the WorkItemType as XML and work on that, but before I do that, I thought I would ask if there is a way to get at the Transitions via the API.
Soooo.....
Not many people need the transitions for WorkItemTypes.
Well, I needed it so I wrote a method to do it. Here it is in case someone else ever needs this:
// Hold a list of all the transistions we have done. This will help us not have run them again If we already have.
private static Dictionary<WorkItemType, List<Transition>> _allTransistions = new Dictionary<WorkItemType, List<Transition>>();
/// <summary>
/// Get the transitions for this <see cref="WorkItemType"/>
/// </summary>
/// <param name="workItemType"></param>
/// <returns></returns>
private static List<Transition> GetTransistions(this WorkItemType workItemType)
{
List<Transition> currentTransistions;
// See if this WorkItemType has already had it's transistions figured out.
_allTransistions.TryGetValue(workItemType, out currentTransistions);
if (currentTransistions != null)
return currentTransistions;
// Get this worktype type as xml
XmlDocument workItemTypeXml = workItemType.Export(false);
// Create a dictionary to allow us to look up the "to" state using a "from" state.
var newTransistions = new List<Transition>();
// get the transistions node.
XmlNodeList transitionsList = workItemTypeXml.GetElementsByTagName("TRANSITIONS");
// As there is only one transistions item we can just get the first
XmlNode transitions = transitionsList[0];
// Iterate all the transitions
foreach (XmlNode transition in transitions)
{
// save off the transistion
newTransistions.Add(new Transition
{
From = transition.Attributes["from"].Value,
To = transition.Attributes["to"].Value
});
}
// Save off this transition so we don't do it again if it is needed.
_allTransistions.Add(workItemType, newTransistions);
return newTransistions;
}
public class Transition
{
public string To { get; set; }
public string From { get; set; }
}
Recently, I made a post about the developers I'm working with not using try catch blocks properly, and unfortuantely using try... catch blocks in critical situations and ignoring the exception error all together. causing me major heart ache. Here is an example of one of the several thousand sections of code that they did this (some code left out that doesn't particuarly matter:
public void AddLocations(BOLocation objBllLocations)
{
try
{
dbManager.Open();
if (objBllLocations.StateID != 0)
{
// about 20 Paramters added to dbManager here
}
else
{
// about 19 Paramters added here
}
dbManager.ExecuteNonQuery(CommandType.StoredProcedure, "ULOCATIONS.AddLocations");
}
catch (Exception ex)
{
}
finally
{
dbManager.Dispose();
}
}
This is absolutely discusting, in my eyes, and does not notify the user in case some potential problem occurred. I know many people say that OOP is evil, and that adding multiple layers adds to the number of lines of code and to the complexity of the program, leading to possible issues with code maintainence. Much of my programming background, I personally, have taken almost the same approach in this area. Below I have listed out a basic structure of the way I normally code in such a situation, and I've been doing this accross many languages in my career, but this particular code is in C#. But the code below is a good basic idea of how I use the Objects, it seems to work for me, but since this is a good source of some fairly inteligent programming mines, I'd like to know If I should re-evaluate this technique that I've used for so many years. Mainly, because, in the next few weeks, i'm going to be plunging into the not so good code from the outsourced developers and modifying huge sections of code. i'd like to do it as well as possible. sorry for the long code reference.
// *******************************************************************************************
/// <summary>
/// Summary description for BaseBusinessObject
/// </summary>
/// <remarks>
/// Base Class allowing me to do basic function on a Busines Object
/// </remarks>
public class BaseBusinessObject : Object, System.Runtime.Serialization.ISerializable
{
public enum DBCode
{ DBUnknownError,
DBNotSaved,
DBOK
}
// private fields, public properties
public int m_id = -1;
public int ID { get { return m_id; } set { m_id = value; } }
private int m_errorCode = 0;
public int ErrorCode { get { return m_errorCode; } set { m_errorCode = value; } }
private string m_errorMsg = "";
public string ErrorMessage { get { return m_errorMsg; } set { m_errorMsg = value; } }
private Exception m_LastException = null;
public Exception LastException { get { return m_LastException; } set { m_LastException = value;} }
//Constructors
public BaseBusinessObject()
{
Initialize();
}
public BaseBusinessObject(int iID)
{
Initialize();
FillByID(iID);
}
// methods
protected void Initialize()
{
Clear();
Object_OnInit();
// Other Initializable code here
}
public void ClearErrors()
{
m_errorCode = 0; m_errorMsg = ""; m_LastException = null;
}
void System.Runtime.Serialization.ISerializable.GetObjectData(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
{
//Serialization code for Object must be implemented here
}
// overrideable methods
protected virtual void Object_OnInit()
{
// User can override to add additional initialization stuff.
}
public virtual BaseBusinessObject FillByID(int iID)
{
throw new NotImplementedException("method FillByID Must be implemented");
}
public virtual void Clear()
{
throw new NotImplementedException("method Clear Must be implemented");
}
public virtual DBCode Save()
{
throw new NotImplementedException("method Save Must be implemented");
}
}
// *******************************************************************************************
/// <summary>
/// Example Class that might be based off of a Base Business Object
/// </summary>
/// <remarks>
/// Class for holding all the information about a Customer
/// </remarks>
public class BLLCustomer : BaseBusinessObject
{
// ***************************************
// put field members here other than the ID
private string m_name = "";
public string Name { get { return m_name; } set { m_name = value; } }
public override void Clear()
{
m_id = -1;
m_name = "";
}
public override BaseBusinessObject FillByID(int iID)
{
Clear();
try
{
// usually accessing a DataLayerObject,
//to select a database record
}
catch (Exception Ex)
{
Clear();
LastException = Ex;
// I can have many different exception, this is usually an enum
ErrorCode = 3;
ErrorMessage = "Customer couldn't be loaded";
}
return this;
}
public override DBCode Save()
{
DBCode ret = DBCode.DBUnknownError;
try
{
// usually accessing a DataLayerObject,
//to save a database record
ret = DBCode.DBOK;
}
catch (Exception Ex)
{
LastException = Ex;
// I can have many different exception, this is usually an enum
// i do not usually use just a General Exeption
ErrorCode = 3;
ErrorMessage = "some really weird error happened, customer not saved";
ret = DBCode.DBNotSaved;
}
return ret;
}
}
// *******************************************************************************************
// Example of how it's used on an asp page..
protected void Page_Load(object sender, EventArgs e)
{
// Simplifying this a bit, normally, I'd use something like,
// using some sort of static "factory" method
// BaseObject.NewBusinessObject(typeof(BLLCustomer)).FillByID(34);
BLLCustomer cust = ((BLLCustomer)new BLLCustomer()).FillByID(34);
if (cust.ErrorCode != 0)
{
// There was an error.. Error message is in
//cust.ErrorMessage
// some sort of internal error code is in
//cust.ErrorCode
// Give the users some sort of message through and asp:Label..
// probably based off of cust.ErrorMessage
//log can be handled in the data, business layer... or whatever
lab.ErrorText = cust.ErrorMessage;
}
else
{
// continue using the object, to fill in text boxes,
// literals or whatever.
this.labID = cust.ID.toString();
this.labCompName = cust.Name;
}
}
Bottom line, my question is, Am I over complicating things with the muliple layers, and the inherited classes or is my old concept illustrated still working good and stable? Is there a better way now a days to accomplish these things? Should I go to just making straight SQL calls from the asp.net page code behind pages as fellow work associate developer suggested (though that last solution makes me feel icky), instead of going through a business object, and data layer (data layer not shown, but basically holds all the stored proc calls). Yeah, another developer did ask me why i go through the effort of layering things, when you can just type what you need straight in a *.aspx.cs code behind page, and then I can have the joys of over 1k lines of code behind. What is some advice here?
Have you considered using an ORM like NHibernate? There's no point in re-inventing the wheel.
To me this is a code smell:
BLLCustomer cust = ((BLLCustomer)new BLLCustomer()).FillByID(34);
Too many brackets!
I've found that using the active record pattern in a language like C# always ends in tears because it's hard(er) to unit test.
The jump from the first bit of code to the next is huge. Whether a complicated business object layer is necessary will depend on the size of the app in question. At the very least though our policy is that exceptions are logged where they are handled. How you present to the user is up to you but having logs is essential so that developers can get more information if necessary.
Why not just catch the exception in the Page_Load event? Some exception you might expect and know how to deal with, other exceptions should be handled by a global exception handler.
My rule of thumb is to only catch errors that I can handle or give the user something useful so that if they do whatever it was they did again, it is likely to work for them. I catch database exceptions; but only to add some more information onto the error about the data being used; then I re-throw it. The best way to handle errors in general is to not catch them at all anywhere but at the top of the UI stack. Just having one page to handle the errors and using the global.asax to route to it handles almost all situations. Using status codes is definitely out of style all together. It is a remnant of COM.
Is it possible to use an abstract base class instead of a concrete class? this would force the implementation of your methods at development time rather than runtime exceptions.
The best comment here to agree with is from dances, where you should only handle exceptions you can recover from at that point. Catching others and rethrowing is the best method (although i think its rarely done). Also, make sure they are logged.... :)
YOur way of errorhandling seems very outdated. Just make a new exeption and inherit from exeption that way you have the callstack at least. Then you should log with something like nlog or log4net. And this is the year 2008 so use generics. You will have to do a lot less casting that way.
ANd use an ORM like someone said before. Don't try to reinvent the wheel.