retrieving all forms from my project - c#

I know this question has been asked before. I have the code to do this but i am getting an error and I think I know why but I am just really getting into .Net Reflection so I wish to get confirmation on whether I am correct or not.
Here is the code. I want to retrieve all the forms from my project that have a basetype of "BaseEditForm" and then all of those that end with "EditForm" I want to put in a List to populate a ListBox.
public void LoadAllEditForms()
{
formsList = new List<string>();
try
{
Assembly project = Assembly.Load("UnionAdministrator");
foreach (Type t in project.GetTypes())
{
if (t.BaseType == typeof (BaseEditForm))
{
var emptyCtor = t.GetConstructor(Type.EmptyTypes);
if (emptyCtor != null)
{
var f = (Form) emptyCtor.Invoke(new object[] {});
if (f.Name.EndsWith("EditForm"))
formsList.Add(f.Name);
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
I am getting the error message "Object reference not set to an instance of an object." on the line
var f = (Form) emptyCtor.Invoke(new object[] {});
emptyCtor is not null and besides there is no way for emptyCtor to get to this point if it is null. So I am confused about the error message. So here is my question. For this to work properly do all my forms have to have a default constructor? Almost all my forms have a constructor that takes one or more parameters. Is that my problem?

Your code works fine.
It must be one of your constructors that throw the exception.
Check all of your derived Forms to see if any of them (those that does not take any ctor parameters) could throw a NullReferenceException if invoked.

I'm not sure why you're going through the trouble of trying to execute the constructor of every form. You could simplify your code (and avoid the whole issue) by just looking at the type names.
public void LoadAllEditForms()
{
Assembly project = Assembly.Load("UnionAdministrator");
var formsList = project.GetTypes()
.Where (t => t.BaseType == typeof(BaseEditForm) && t.Name.EndsWith("EditForm"))
.ToList();
}

Related

C# lambda null runtime binding

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 ...);
}
}

Update only works in debug mode

I'm new to using entity as a data layer between MVC and SQL Server, so I apologize up front if what I'm doing is bad practice.
Let me start by sharing the code that is handling the update.
Update Delivery:
public bool One(Delivery toUpdate)
{
using (var dbContext = new FDb())
{
try
{
var deliveryInDb = this.dbTable(dbContext).Single(x => x.DeliveryId == toUpdate.DeliveryId);
dbContext.Entry(deliveryInDb).CurrentValues.SetValues(toUpdate);
//removal first
List<DeliveryDay> currentDays = FEngineCore.DeliveryDay.Get.ForValue((x => x.DeliveryId), toUpdate.DeliveryId);
List<DeliveryTime> currentTimes = FEngineCore.DeliveryTime.Get.ForValue((x => x.DeliveryId), toUpdate.DeliveryId);
//remove delivery days that are not needed
foreach (var curDay in currentDays)
{
if (!toUpdate.DeliveryDays.Select(x => x.DeliveryDayId).Contains(curDay.DeliveryDayId))
{
FEngineCore.DeliveryDay.Delete.One((x => x.DeliveryDayId), curDay.DeliveryDayId);
deliveryInDb.DeliveryDays.Remove(curDay);
}
}
//remove delivery times that are not needed
foreach (var curTime in currentTimes)
{
if (!toUpdate.DeliveryTimes.Select(x => x.DeliveryTimeId).Contains(curTime.DeliveryTimeId))
{
FEngineCore.DeliveryTime.Delete.One((x => x.DeliveryTimeId), curTime.DeliveryTimeId);
deliveryInDb.DeliveryTimes.Remove(curTime);
}
}
foreach (var day in toUpdate.DeliveryDays)
{
if (day.DeliveryDayId == 0)
{
dbContext.DeliveryDays.Add(day);
}
else
{
if (dbContext.DeliveryDays.Local.Any(e => e.DeliveryDayId == day.DeliveryDayId))
{
dbContext.Entry(dbContext.DeliveryDays.Local.First(e => e.DeliveryDayId == day.DeliveryDayId)).CurrentValues.SetValues(day);
dbContext.Entry(dbContext.DeliveryDays.Local.First(e => e.DeliveryDayId == day.DeliveryDayId)).State = EntityState.Modified;
}
else
{
DeliveryDay modDay = new DeliveryDay
{
DayOfWeek = day.DayOfWeek,
DeliveryDayId = day.DeliveryDayId,
DeliveryId = day.DeliveryId,
Interval = day.Interval
};
dbContext.DeliveryDays.Attach(modDay);
dbContext.Entry(modDay).State = EntityState.Modified;
}
deliveryInDb.DeliveryDays.Add(day);
}
}
foreach (var time in toUpdate.DeliveryTimes)
{
if (time.DeliveryTimeId == 0)
{
dbContext.DeliveryTimes.Add(time);
}
else
{
if (dbContext.DeliveryTimes.Local.Any(e => e.DeliveryTimeId == time.DeliveryTimeId))
{
dbContext.Entry(dbContext.DeliveryTimes.Local.First(e => e.DeliveryTimeId == time.DeliveryTimeId)).CurrentValues.SetValues(time);
dbContext.Entry(dbContext.DeliveryTimes.Local.First(e => e.DeliveryTimeId == time.DeliveryTimeId)).State = EntityState.Modified;
}
else
{
DeliveryTime modTime = new DeliveryTime
{
DeliveryId = time.DeliveryId,
DeliveryLocationId = time.DeliveryLocationId,
DeliveryTimeId = time.DeliveryTimeId,
DropoffTime = time.DropoffTime
};
dbContext.DeliveryTimes.Attach(modTime);
dbContext.Entry(modTime).State = EntityState.Modified;
}
deliveryInDb.DeliveryTimes.Add(time);
}
}
dbContext.SaveChanges();
dbContext.Entry(deliveryInDb).State = EntityState.Detached;
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
return false;
}
}
}
Let me continue by explaining that the delivery object has 2 children; DeliveryTime and DeliveryDay. The issue that arises happens when I try to remove one deliveryTime and modify nothing else. The end result of running the code normally (not in debug) is that the deliveryTime is in fact not removed. Here's the interesting thing guys, when I debug it and go through the break points, everything works as expected!
Let me continue by posting the code that is running behind the removal method of the deliveryTime (actually all entity objects in my system).
public bool One<V>(Expression<Func<T, V>> property, V value) where V : IComparable
{
using (var dbContext = new FoodsbyDb())
{
try
{
T toDelete;
//get the body as a property that represents the property of the entity object
MemberExpression entityPropertyExpression = property.Body as MemberExpression;
//get the parameter that is representing the entity object
ParameterExpression entityObjectExpression = (ParameterExpression)entityPropertyExpression.Expression;
//represent the value being checked against as an expression constant
Expression valueAsExpression = Expression.Constant(value);
//check the equality of the property and the value
Expression equalsExpression = Expression.Equal(entityPropertyExpression, valueAsExpression);
//create an expression that takes the entity object as a parameter, and checks the equality using the equalsExpression variable
Expression<Func<T, bool>> filterLambda = Expression.Lambda<Func<T, bool>>(equalsExpression, entityObjectExpression);
toDelete = this.dbTable(dbContext)
.SingleOrDefault(filterLambda);
if (toDelete != null)
{
this.dbTable(dbContext)
.Remove(toDelete);
dbContext.SaveChanges();
return true;
}
return false;
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
return false;
}
}
}
The code above is obviously generic, and it handles all my entity objects. I have tested it in and out and know for sure the problem does not lie in there. I thought it would be helpful to post it so you all can have a full understanding of what's going on.
Here's my best guess as to what's going on:
The reference to the removed deliveryTime still exists when the database context is saved, but when I debug, the system has enough time to remove the context.
Here was one of my attempted solutions:
Remove all references to the children objects immediately after setting currentDays and currentTimes and then proceeding to add them back to deliveryInDb as you enumerate through them.
Because I am new to all of this, if you see some bad practice along with the solution, I wouldn't mind constructive criticism to improve my programming method.
I actually encountered this issue in a project at work. The project is an older MVC4 project using EF 6.1.
In our situation, a simple update attempting to set a related entity property to null was failing to actually set it to null while running the web app normally (in debug mode). When setting a break point on the line of code that sets the property to null the database would be updated as expected, though. So, the update was working when a break point was in place but not working when allowed to run normally.
Using an EF interceptor, we could see that, with the break point in place, the update query was going through as expected.
Now, in our situation the related entity was using the virtual keyword to allow for lazy loading. I think this is the root of the issue. When a break point is present, EF has enough time to both lazily load that related entity and evaluate whatever it needs to evaluate and finally set it to null. When running without a break point, I think EF gets caught up trying to lazily load that entity and therefore fails to think it needs to be updated. To be clear, I was both accessing the related entity property for the first time and setting it null using a one-liner of code.
foo.Bar = null;
I resolved this issue, in our scenario, by accessing that property at least once prior to setting it to null so that EF is forced to load it. With it loaded, setting it to null seems to work as intended now. So again, to be clear, I think the issue is a combo of lazy loading and the one-liner of code both accessing that property for the first time and assigning it to null.
It appears that you're using multiple instances of your DbContext, which are not synchronized.
The solution would be to use a single instance, and pass that instance between your methods.

Issues with Nancy Framework for MVC (and NewRelic)

I just took over a bunch of C# code from another company, and I'm having big trouble getting the first build to work. The code uses a framework called Nancy, instead of MVC. I have never used this framework before, and there might be a real simply answer to my question, and I apllogize if I missed some basic understanding of Nancy, before posting here.
The problem is boiled down to a single class, handling the initialization of the application (I THINK) From what I've read, it's pretty standard Nancy:
using System;
using Nancy;
using NewRelicAgent = NewRelic.Api.Agent.NewRelic;
using Nancy.Bootstrapper;
using Nancy.Routing;
public class NewRelicStartup : IApplicationStartup
{
private readonly IRouteResolver routeResolver;
public NewRelicStartup (IRouteResolver routeResolver)
{
this.routeResolver = routeResolver;
}
public void Initialize(IPipelines pipelines)
{
pipelines.BeforeRequest.AddItemToStartOfPipeline(
context =>
{
var route = routeResolver.Resolve(context);
if (route == null || route.Item1 == null || route.Item1.Description == null) // probably not necessary but don't want the chance of losing visibility on anything
{
NewRelicAgent.SetTransactionName(
context.Request.Method,
context.Request.Url.ToString());
}
else
{
NewRelicAgent.SetTransactionName(
route.Item1.Description.Method,
route.Item1.Description.Path);
}
return null;
});
pipelines.OnError.AddItemToEndOfPipeline(
(context, ex) => {
NewRelicAgent.NoticeError(ex);
return null;
}
);
}
}
When this code is being build, I get several errors, some of which being:
Delegate 'System.Func<Nancy.NancyContext,System.Threading.CancellationToken,System.Threading.Tasks.Task<Nancy.Response>>' does not take 1 arguments
Cannot convert lambda expression to type 'Nancy.PipelineItem<System.Func<Nancy.NancyContext,System.Threading.CancellationToken,System.Threading.Tasks.Task<Nancy.Response>>>' because it is not a delegate type
Here is a screenshot of the kind of error I get:
https://www.dropbox.com/s/cigcfc4sfj8batg/Nancy%20Error.PNG
I am 100 % certain, that this is some kind of interpretation issue from Visual Studio's side, since the code is live atm. I just can't build it in VS.
Do any of you have any idea what I am missing, or doing wrong? Remember; the code is working and live atm.
Try changing "return null;" to "return (Nancy.Response)null;"
Edit: Sorry, just looked at the screenshot - it's using some properties that have changed in 0.20, so you will either have to manually fix up the code (it's now async at the core), or roll back to 0.19 for now, and re-write that bit of code at a later date.
Edit again: Give this ago:
pipelines.BeforeRequest.AddItemToStartOfPipeline(
context =>
{
var route = routeResolver.Resolve(context);
if (route == null || route.Route == null || route.Route.Description == null) // probably not necessary but don't want the chance of losing visibility on anything
{
NewRelicAgent.SetTransactionName(
context.Request.Method,
context.Request.Url.ToString());
}
else
{
NewRelicAgent.SetTransactionName(
route.Route.Description.Method,
route.Route.Description.Path);
}
return null;
});

Using Reflection to get the field/property that is being null compared?

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].

casting delegate using errorbox returns fault

Im completely stumped on where to go from here.
heres my line of code that i cant get past.
if (error.GetReaction(ErrorReaction.InformUser) == null)
{
error.SetReaction(new ErrorReactionClass(ErrorReaction.InformUser, (CachedAnonymousMethodDelegate1 != null) ? CachedAnonymousMethodDelegate1 : (CachedAnonymousMethodDelegate1 = new Method(ErrorMessageBox.ShowDialog)), "OK", ""));
}
i get the following errors from this
Error 30 'System.Windows.Forms.DialogResult System.Windows.Forms.Form.ShowDialog()' has the wrong return type
Error 31 An object reference is required for the non-static field, method, or property 'System.Windows.Forms.Form.ShowDialog()'
There are two errors here.
The call to ShowDialog doesn't have the return type your delegate is expecting.
You can't call "ShowDialog" on a type, since it's not a static method. You need to provide an actual instance.
I suspect that this may do what you need:
// Not sure how many arguments your "Method" delegate gets
Method showDialog = (arg1, arg2) =>
{
var form = new ErrorMessageBox();
// Setup form with arg1/arg2/etc
form.ShowDialog();
// return appropriate return type here...
};
error.SetReaction(
new ErrorReactionClass(
ErrorReaction.InformUser,
(CachedAnonymousMethodDelegate1 != null)
? CachedAnonymousMethodDelegate1
: (CachedAnonymousMethodDelegate1 = showDialog)
, "OK", ""));

Categories

Resources