FileHelpers and data type exception - filehelpers

I'm using FileHelpers library to import a tab delimited file. I have enabled the ErrorMode.SaveAndContinue. The issue I'm facing is that when particular fields has invalid data type
[FieldConverter(ConverterKind.Decimal)]
public decimal? Price;
(e.g decimal? Price field has string value in it xxxxxx) in a single record, the library only checks against the first field value and throws internal exception which is logged into the ErrorManager.Errors.
I need to check the remaining fields as well on the same row and log their errors as well in the same cycle.
How can I do that?
** Please note that I have tried to writing CustomConverter but again I need to throw ConvertException so that it gets catched by ErrorManager and it just moves to next row.
The AfterReadRecord does not gets called because of the exception

That behavior is by design from the first versions of the library, the exception is throw when found the problem or the error is logged if ErrorManager is present
The best way to solve your problem is to use a string field for Price and later do the validations you need in the AfterReadRecord method
For example
public class YourClass: INotifyRead
{
[FieldConverter(ConverterKind.Decimal)]
public string Price;
void AfterReadRecord (...)
// Validate inside this method
}

Related

Why is my complex [FromBody] parameter null?

I am having trouble with the [FromBody] parameter of my method not binding.
example C#:
[Route("api/path")]
[HttpPost]
public void Post([FromBody] ComplexType param)
{
// param is null
}
public class ComplexType
{
public string name { get; set;}
}
I've checked the POST body content and content-type and it looks correct.
Why is it null despite throughly checking that the data being posted and content type all match what is expected?
N.B. This is a deliberatly vague question since I was having a lot of trouble diagnosing an issue and I couldn't find a suitable question and answer.
When I eventually found the problem I kicked myself for it, but I feel the need to share how I found the problem to hopefully spare others the pain.
As it happens there may well be nothing wrong with the example given.
In my case there was a problem with the definition of the complex type, I had a parameter marked as string while it should have been string[] and so the JSON parsed did not match the model.
The important part though is how I found this out:
When debugging any API method there is the magic ModelState property.
This property gives you information about any failures that occur while binding the data received to the expected parameters.
e.g:
here we can see the parameter (uploaded), and the property within that parameter which failed to bind correctly.
Check the definition of that property and you'll probably find an error.

How to create a custom validator in ASP.NET Core that fires for invalid input too?

I have created a custom validator for a DateTime field in ASP.NET Core 3.1 as shown below:
[CustomDate]
public DateTime DOB { get; set; }
public class CustomDate : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
//… some logic
}
}
However, my problem is that this custom validator fires only when I put a date value in the text box control. It does not fire for invalid inputs like e.g. when I put a string 'aaa' in the text box.
My question is how to make this custom validator fire even for invalid inputs like 'string', etc.
The reason is I want to make this custom validator replace [Required], [ReqularExpression], etc. A sort of 'One ring (validator) to rule them all'. How can I achieve that?
TL;DR: When you submit a value that can't be converted to DateTime, model binding fails. Since there is already a validation error associated with the property, subsequent validation—including your CustomDate validator—doesn't fire. Your property is still getting validated, however: If you enter a value of aaa, ModelState.IsValid will return false.
The code you had originally posted should be working fine—but I suspect it's not working the way you're expecting it to. Most notably, your confusion likely stems from the following statement:
"…this custom validator fires only when I put a date value in the text box control."
That is also true! Let me walk through the process.
Original Code
To help illustrate this, I hope you don't mind me resurrecting your original code sample, as it's useful to have concrete reference to work off of.
[CustomDate]
public DateTime DOB { get; set; }
public class CustomDate : Attribute, IModelValidator
{
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
{
if (Convert.ToDateTime(context.Model) > DateTime.Now)
return new List<ModelValidationResult> {
new ModelValidationResult("", "Invalid - future date")
};
else if (Convert.ToDateTime(context.Model) < new DateTime(1970, 1, 1))
return new List<ModelValidationResult> {
new ModelValidationResult("", "Invalid - date is less than 1970 year")
};
else
return Enumerable.Empty<ModelValidationResult>();
}
}
Validation Process
Before I walk through the process, there are four underlying considerations that are important to be aware of here:
Model binding occurs before model validation.
Model binding will raise its own validation errors if binding fails.
Validation attributes are only evaluated on properties that remain IsValid.
The ModelValidationContext.Model property is typed to the validated property—so, in this case, a DateTime value.
Use Case #1: Invalid Value
Given these considerations, here's what's happening when you submit a value of e.g. aaa in the field mapped to your validated DOB property:
The model binder attempts to bind a value of aaa to a DateTime property.
The model binder fails, adding a ModelError to your ModelStateDictionary.
Your CustomDate validator never fires because the field has already failed validation.
Use Case #2: Missing Value
It's instructive to look at another test case. Instead of putting in aaa, just don't put a value in at all. In this case, the process looks a bit different:
The model binder doesn't find a value for your DateTime property, so no binding occurs.
Your model's property initializes to DateTime's default value of 0001-01-01 00:00:00.
Your CustomDate validator fires, adding a ModelError because "Invalid - date is less than 1970 year".
Analysis
As you can see above, it is true that your CustomDate validator isn't firing when a bogus date is submitted. But that doesn't mean that validation isn't occurring. Instead, validation has already happened and failed. If you enter a valid date—or don't enter a date at all—then a model binding error won't occur, and your CustomDate validator will be executed as expected.
Revisiting Your Question
"How to make this custom validator to fire even for invalid inputs like 'string' etc."
Ultimately, I haven't answered that question. But I think my answer will explain why that's happening, and why your input is still getting validated despite that. Keep in mind that even if your CustomDate validator did fire, it would act the same as if you hadn't submitted a value at all, since the context.Model value would have defaulted to 0001-01-01 00:00:00. The main difference is that you're not getting the same error message, since the error is coming from a different source.
Forcing Validation
I don't recommend this, but if you really wanted your CustomDate validator to fire, you could apply it to a string property instead. In that case, model binding wouldn't fail and your CustomDate validator would still get called. If you pursue this, you'll need to put in additional validation to ensure that the date is in the correct format (e.g., by preempting or handling InvalidFormatExceptions). But, of course, your date would be stored as a string, which likely isn't what you want.
Code Suggestions
This is a bit outside the scope of your original question, but while I'm here I'd recommend the following:
You won't need to do a Convert.ToDateTime() in your validator; your context.Model field is already a DateTime. You just need to cast it back to a DateTime object (e.g., (DateTime)context.Model) so your code knows that.
At minimum, you should consider using <input type="date" /> (reference) which, on most browsers, will restrict input to a correct date while also providing a basic date picker.
Alternatively, there are a number of more sophisticated date/time controls written in JavaScript that you might consider implementing if you require more control over the presentation and client-side validation.

Web API Model Validation - Error Message is empty

I'm using standard model validation attributes (e.g. Required) as a first line of defense against invalid model, later on I have additional checks that can not be done by using standard model validation attributes.
I have one ActionFilterAttribute where I check for model state, null model properties and so on..
What is strange here is the following
in method OnActionExecuting we have HttpActionContext and there is ModelState property which has property IsValid indicating if model is valid or not (excluding cases when property of model is null, but that I cover later on...).
So, when the model is not valid, than actionContext.ModelState.First().Value.Errors (collection of ModelError) contains all model validation errors. So, ModelError contains ErrorMessage and Exception attributes, and when I check for each of them, ErrorMessage is not initialized but Exception property is initialized and contains details of validation failure. Further more, ModelError class has 3 constructors:
public ModelError(Exception exception);
public ModelError(string errorMessage);
public ModelError(Exception exception, string errorMessage);
So it seems that for some reason the first one is called by framework, instead of the last one.
Any ideas why this happens? What can I do in order to get ErrorMessage Initialized?
Regards,
Novak

how to insert tokens or contexts in my listener class in antlr4

I have an antlr4 grammar file that parses a BASIC language. Is there a way to insert more code in my extended baseListener class?
For example, if I am parsing this code:
10 print "hello world"
%include "moreCode.bas"
print "after include"
moreCode.bas could be something like:
for t% = 1% to 10%
print t%
next t%
I need to detect the include command and include the contents into the file being walked and continue walking it as a whole.
So I was thinking that in my enterIncludeCommand method in my listener class I would start a new parser for moreCode.bas and then somehow insert the tokens/contexts into my current one.
What is the correct way of doing this?
There is no one right pattern. That said, one effective way is to have your main initiate the parser by always calling through a constructor that takes a state object and a source path as parameters
public class BasicParser {
public static void main(String[] args) {
...
StateModel state = new StateModel()
RecurseParser rp = new RecurseParser(state, pathname);
...
}
}
public class RecurseParser {
public RecurseParser(StateModel state, String pathname) {
this.state = state;
this.pathname = pathname; // source text to parse
...
}
public StateModel getResults() {
return this.state
}
In your enterIncludeStatement method, create and run a new RecurseParser instance directly. In your exitIncludeStatement, retrieve the new current state and, as appropriate, validate/check for errors.
Since the state model encapsulates your symbol table, etc., you maintain continuity as you walk through the forest -- recursion is effectively free.
Should mention that, relative to the symbol table, treat executing an include essentially the same as calling a subroutine.
Related: Symbol Table
I have two solutions for this and I took the last one I am going to mention. Also GRosenBerg has a great idea too.
1) use the TokenStreamRewriter and in the enterIncludeStatement use the rewriter insertBefore, insertAfter and/or replace methods. At the end of the walk of that particular listener object, call the rewriter getText() and that will give you the combined string. You will have to reparse that text to go the next listener pass.
2) In the enterIncludeStatement method of the listener class, get the include file name, run the lexer/parser on it and then take the first StatementContext(in my case) and inject it into the current tree using the IncludeContext.AddChile(myStatement). Looping for each statement line in that include file. The tricky part is to include the statements in the correct place but you will end up with a complete tree that you can walk with the next listener class phase.
I used option 2 and its working for me so far however I'm not sure using the addChild method is the best way since I am really inserting siblings not children. Given this siblings/childrens issue then maybe grosenberg's recursive idea would be the best.

Is it possible to override the vb.net Resource Manager GetString function?

In the auto-generated resource designer file, there are properties for each resource. The property calls "GetString" which returns the string value. I would like to override this getstring function so I can do logic to see if I need to retrieve this value or a different value. I can't figure out how to do this because the designer file is auto-generated.
Public ReadOnly Property General() As String
Get
Return ResourceManager.GetString("General", resourceCulture)
End Get
End Property
For example, in my version of the GetString function, I would check the key passed in ("General") and see if there is a custom value for this key in a database. If the custom value exists, I would use that value. If the custom value does not exist, I would call the base GetString function to get the Resource value. I'd like to use the built in Resource class for this because then in my code I can just use "#Resources.General" and take advantage of the auto-complete functionality that already exists.
Refer to ASP.NET Resourcemanager to read local .resx. It's in C# but you can just convert it over. It isn't 100% of what you are looking for but shows a way of overriding in which you may be able to adjust to work with your needs.