-
Notifications
You must be signed in to change notification settings - Fork 86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Limited exception information ... stuck ... #60
Comments
Oh one other thing ... this is how I setup the "assignContext" which is a ZZZ EvalContext that i'm using for this call ...
... all the types I care about are in assemblies named "Core.*.dll" so this is a targeted fetch that pulls all the things it could possibly need. |
Thank you @TehWardy for reporting, We have not been able to reproduce it but we might have missed something. Do you think you could provide a standalone version with only this code that fails? |
New project > net core console app, then drop this in ...
My understanding is that this should work as i'm only trying to compile the function at this time and not actually run it. |
@JonathanMagnan random question ... I use discord a lot and we have a discord server for the company, it's real easy to share code samples and discuss problems on. |
Thank you, We are currently looking at it. |
Hello @TehWardy , You do not register class in your project which causes the issue. Here is a way to do it by registering a namespace: ctx.RegisterNamespace(typeof(Program).Assembly, "ExpressionThing"); |
Oh ... that's new ... I didn't have to do that before under .Net 4 ... is this a .Net Core thing? |
Given my original example source the last line of code had ...
.... Is it possible to have an override of this that auto registers all namespaces in the given assmeblies? |
Hello @TehWardy , No, that's not new to .NET Core. You had to do it also before.
I'm not sure to understand what exactly you want. You just need to call the |
My understanding is that if I do this ...
I'm constructing the context then telling it what types I want it to know about as a collection of assemblies that contain them. What I think you're saying is that In addition to providing the assemblies I also need to tell it what namespaces from those assemblies I want to use. What's the purpose of the RegisterNamespace call beyond what I would hope is default behaviour based on what I have described? |
Not at all, The You do not have to use the |
Oh i see what you're saying ... yeh my bad ... Having checked in my code and the expression used when I put a breakpoint on the last line in the original question example I find that the assembly collection passed in contains the assembly with both types I'm using in the expression ... do I also need to provide thing's like System or is the framework automatically included? I'm thinking the smart way to go about this is to simply load all assemblies I care about in to the app domain then just give that last line the full set like this ...
... Would you expect that to behave as expected? Is there some way to query the context to ask it for a list of types it knows about so I can watch window it and double check that I have everything setup as expected? |
Hello @TehWardy , Just to let you know, my developer started to work on something that will tell you which types are missing. He almost completed the code so we should be able to provide you something probably on Monday. |
Awesome :) you guys are on overtime bashing this out on a bank holiday weekend I love the dedication :) |
Hello @TehWardy , Just to confirm we made the right thing, how do you expect this functionality to work?
|
For the above ...
... which lists all registered types that the parser can consume (including ideally, empty generic types). Ideally I would write my expressions, give them to the parser and then the parser would give me back (in the event of an axception) saying something like "unknown type used for cast" or "cannot resolve a property on the type in expression where expected type is {type name}". Something along those lines. Also having the ability to say to the parsers context "Get me this type({some string like a cast expression string})" to see if it can resolve a given type would be really helpful. |
Hello @TehWardy , We added Here is an example: var context = new EvalContext();
context.UnregisterAll();
context.RetryAndFindMissingTypes = true;
var compiled = context.Compile<Func<object>>("new SqlConnection()");
var usedTypes = context.UsedTypes;
var missingTypes = context.MissingTypes; Let me know if that's what you were looking for. Best Regards, Jonathan |
sweet so if I do this will it tell me where I messed up ... var context = new EvalContext();
try
{
var compiled = context.Compile<Func<object>>("new SqlConnection()");
}
catch(Exception ex)
{
var usedTypes = context.UsedTypes;
var missingTypes = context.MissingTypes;
} This would be perfect to help me report back to my logs / UI what exactly went wrong. ... Also I think I managed to fix the initial problem I was having with pure luck which was related to this so I can definitely see this saving time. As always, Love your work man !!! |
Thank you for your good word ;) In fact, if we success to compile when the option var context = new EvalContext();
context.RetryAndFindMissingTypes = true;
var compiled = context.Compile<Func<object>>("new SqlConnection()");
if(context.MissingTypes != null)
{
var usedTypes = context.UsedTypes;
var missingTypes = context.MissingTypes;
} |
oh I c ... enabling that function does a sort of "safe compile" so it'll succeed but produce null in the variable "compiled" in the event that types are missing. Ok I can work with that :) |
Almost... In actually return the compiled version (but doesn't cache it), so you can actually execute it. However, you know that the code was retried with all domain assemblies when the variable Perhaps we should have raised an error instead as you did with the try/catch! |
Yeh so my way assumes that it tries, fails internally, sets up the collections exposed then throws a "Z.EvalException" or something. That's a more "typical best practice" way of handling this kind of scenario (i think) |
Since the feature is pretty fresh and outside of you, none know about it, we will think about it tomorrow and maybe do it this way ;) |
Sounds good :) |
Some further thoughts i've had over night on this ... I'm thinking the other up side here is that if anything at all goes wrong the context internally should catch that and attempt to provide some explanation / extended information. In this situation where we know the failure is due to Missing types when I do this ...
... So key changes I'm "suggesting" here ...
... so for example The stack trace for the above code might look something like this (ideally) ...
The first line here is a stack trace line from my string to be compiled. ... This request about stack traces is probably a big ask and I have no idea how achievable it is as I don't know what level control / detials you have at the point an exception occurs. My thinking is that "EvalContextException" could derive from something like AggregateException so would typically contain the exceptions we currently get as an inner exception but then extend it with whatever helpful hints you guys are able to throw in on top. This would give a more "rounded and typical" .Net experience, and give the caller the option to gather more information by catching the exception without it being always there as a property on the EvelContext bloating the object definition on your end. |
Thank you TehWardy for this additional research. I will think about the exception. We usually try to avoid custom exceptions in our library but I must admit that sometimes it could be the best way to handle this. |
Fair enough ... it might be enough to throw an Aggregate exception, but I thought the use of a custom exception type would allow you to extend it with additional information ... consider this (in your code)...
This way the EvalException would contain the Context that was at fault, and you could "over time", as more tickets come in extend the EvalException class without having to make changes to the EvalContext. In theory at least. |
Hello @TehWardy , Sorry for the late answer, I have been sick for a few days and was unable to review & release change made by my developer (had to catch up after 100+ email and still trying to catch up...) The v2.9.51 has been released. The option has been renamed to and now throw an exception var context = new EvalContext();
context.RetryAndThrowMissingTypes = true;
try
{
var compiled = context.Compile<Func<object>>("var x = new SqlConnection()");
}
catch(Exceptionex)
{
var reason = ex.Message;
var missingTypes = context.MissingTypes;
var stack = ex.StackTrace;
} RetryAndThrowMissingTypesTurning on this option is required since retrying the code to find missing type have a performance cost so we cannot enable it by default Custom ExceptionWe though a lot about your proposition on custom exception. Unfortunately, we choose to keep it this way. One major reason is that currently, almost every time this exception would have been thrown, no additional information would have been provided since only the missing types would have added some additional information. There are some other reasons (honestly, I don't remember all what we said) but the final decision was to keep it simple and just throw a normal exception. |
Hey @JonathanMagnan , Sorry to hear you were ill, hope you're back to 100% again soon, i know the feeling of coming back to a long list of emails lol. ... Ok sounds reasonable. Have the context run with the option turned off and in the event of a failure auto turn it on and run again to grab the extra details. This would negate the need for the user to set the extra flag which could then purely be an internal implementation detail for what I think is going to be a pretty standard need any time there's an input issue to the context. From the description you implied that you weren't using a custom exception type but in the code sample you do ... can I assume the code sample is right as this looks pretty user friendly to me? |
Yup, going great now ;) Oh damn, you are right about the example. I just edited it, it looks like I copied your text instead to create a real example. There is not custom exception, unfortunately.
If I understand correctly, this is what we want to avoid exactly. Image the following code Eval.Execute("1+"); The expression is invalid, but if we automatically check for missing types, it will takes way longer to report the error. When looking for missing types, we register all domains types (and there is a lot!) |
Yeh I completely agree:
I'm sure there's tons more going on but the basic idea behind this is that I could then do ...
Context for my use ... I have a web based UI that builds a json blob that represents a "piece" of a workflow. The key complexity here is that I do this with many expressions at different points then build a new code tree that puts them all together and dynamically execute that. The proposed fix will provide the answer to the most "common problem" but if I understand your explanation correctly I need to set this flag on the context "RetryAndThrowMissingTypes" which comes with a performance overhead to compute the extra information. I think I can safely say that the key difference is that the when new option is turned on by the context "as needed" but is otherwise turned off that's the best performance point I can reasonably achieve. The net result is that if this (as i'm proposing above / similar) isn't the implementation i'm always going to turn the option on by default as I don't actually know when it will be needed due to the dynamic nature of the code i'm sitting on top of these calls, meaning i'm always going to take that performance hit as I understand it. Whilst your proposal does give me the required information it falls on me to know when to enable the option. Am I making sense here? |
Hey guys,
I got everything running under .Net 4.x and then it turned out for M$ reasons the only way everything was going to work the way I wanted was to upgrade to .Net Core 2.2 so here I am.
This code works perfectly under .Net 4.x but for some reason under .Net Core I can't seem to get it to behave and the exception is giving me literally nothing.
So here's the code ....
At runtime I have a collection of Activities that derive from this base type ...
... I have a "Flow" object that contains a collection of activities and a collection of "Links" which contain the expressions that I need to compile.
After constructing each activity as it's concrete type and assigning each of the previous and next arrays shown in the base type above I run the code that's failing in an attempt to build the AssignValues Action for each activity that has link information.
The exception information I'm getting looks like this ...
Message
Value cannot be null.
Stack trace
Is there any obvious reason that this would fail as this seems pretty straightforward for the code I have?
The text was updated successfully, but these errors were encountered: