F# Giraffe simple model validation based on attributes - f#

F# Giraffe provides it own validation mechanism different from standard ASP.net attributed based one.
So how can I use attribute based validation in Giraffe if it possible ?

Here answer from github
https://github.com/giraffe-fsharp/Giraffe/issues/436
open System.ComponentModel.DataAnnotations;
open System.Collections.Generic;
let validateDataAnnotations (object:obj) =
let ctx = new ValidationContext(object)
let errors = new List<ValidationResult>()
if Validator.TryValidateObject(object, ctx, errors, true) then None
else Some errors

Related

Why does Odata can't parse JSON when using Extend?

I'm using OData v4 in my project Web Api (.Net Core 3.1). I'm using Devart Linqconnect to generate my model.
When I want to use "Extend" I'm getting message "can't parse JSON. Raw value".
"Select" and "Filter" working good. I'm wondering why "Extend" not working properly.
[EnableQuery(PageSize = 2)]
[HttpGet]
public IActionResult Get(ODataQueryOptions<Tasks_Object> query)
{
var items = query.ApplyTo(DBContext.Tasks_Objects.Where(i => i.Delete== null));
return Ok(items);
}
configuration of my controller/action in EDMModel.
var tasks_object = builder.EntitySet<Tasks_Object>("Task").EntityType.HasKey(e => e.ZAD_ID);
var task = builder.EntityType<Task>().HasKey(a=>a.ZAD_ID);
The problem is solved.
"Extend" not working with LinqConnect because LQ using property EntitySet<> as a relation to other table, but we can change it.
There isn't problem with EF Core because EF Core using properties as a List<> not EntityRef.

Server side data table in asp.net mvc

I have a server side Data Table without any attribute searching or sorting. And now I want to add these attribute.
According to the searches I have, I have to define variables in my controller like this:
public int Start = Convert.ToInt32(Request["start"]);
But my controller does not understand the word Request and gives an error
How can I resolve this error?
Have you included the System.Web assembly in the application?
using System.Web;
If not, try specifying the System.Web namespace, for example:
public int Start = Convert.ToInt32(System.Web.HttpContext.Request["start"]);

.NET Web API issues with deserializing JSON to object

I overtook a project which was developed by a company for us, unfortunately we do not get much support and in the long term, we should accomplish maintainence by ourselves for it. The application consists of a simple Web client (HTTP, JavaScript, Knockout Framework) and a REST API Service (.NET 4.5, ASP.NET MVC I guess).
Currently I am only modifiying the client, so the Server should still work as expected.
On the clientside I modified the Knockout View Model a little bit (added some computables and optimized presentation of some values). The View Model consists of 'Issues' and 'Comments' (as an array on issues, its an Bug tracker in fact). If I create a new issue, description is added to a first comment, the whole Model is JSON.stringified and the send to the .NET API Service. I prooved with Firebug, that the JSON that gets posted looks like this:
{
"Id":0,
"Title":"THis is a title",
"Comments":[
{
"Id":1,
"Text":"this is the first comment"
}
]
}
On the client side, I have a "IssueController":
[HttpPost]
public HttpResponseMessage PostIssues( Issue issue ) {
//issue should already hold the deserialized content of the JSON here,
//but it only contains 'Id' and 'Title' not the 'Comments' (empty List)
...
}
The issue domain model object also has an array for holding comments, but on this end its empty already. The .NET code doesn't have any part which explicitely parses the JSON, as far as I understood it, the MVC Framework does this implicitely by equal property names (Is that right?).
The deserialization already worked as expected, so the .NET Code should be fine, but I looks like that I have modified the JSON in a way, that this implicit mapping of comments does not work anymore. Unfortunately I dont have much experiences with the .NET MVC Framework (or is it just the .NET WebAPI Framework, cannot even tell you that).
These are my questions:
What kind of .NET REST API Framework is that? How can I distinguish?
How is this implicit JSON deserialization working, and what are its pitfalls, for example when portions of the JSON doesn't get deserialized as expected? Especially on the client side (as I said, I didn't modify the server code)
Any ideas about what I could have done to the JSON, that the server doesn't like it anymore? ;)
EDIT
Issue.cs looks like this (simplified for sure):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Bo;
using Projects.DomainObjects;
namespace Projects.Models {
public class Issue : DomainObject {
public Issue() {
this.Comments = new List<Comment>();
}
public long Id { get; set; }
private string _Title;
public string Title { get { return _Title; } set { _Title = value; NotifyChanged(); } }
public List<Comment> Comments { get; set; }
}
Comment.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Common;
using Projects.DomainObjects;
namespace Projects.Models {
public class Comment : DomainObject {
public Comment() {
}
public long Id { get; set; }
public string Text { get; set; }
}
I just tried to your code straight from your post and it worked for me.
So there are a few things that may be going wrong on your side:
When you post the object to the server, make sure you are converting back from Knockout observable to a json object. So in your ajax request, make sure it looks like: data: ko.toJSON(issue) and not just data: issue.
When you post the object to the server make sure you sent header content-type: application/json
Here are the answers to your other questions:
What kind of .NET REST API Framework is that? How can I distinguish?
This doesn't look like anything custom (at least, what you posted) it is just straight Web API in .NET.
How is this implicit JSON deserialization working, and what are its pitfalls, for example when portions of the JSON doesn't get deserialized as expected? Especially on the client side (as I said, I didn't modify the server code)
Deserialization on the server uses the collection of formatters that work based on the content-type set by the client. This can get complex if you want to customize it but there is information here
Any ideas about what I could have done to the JSON, that the server doesn't like it anymore? ;)
As I said your code worked for me!
Solved it, the Problem was a computed that returns a sorted array of the comments. So my knockout model contains an
self.Comments = ko.observableArray([]); //...which gets filled with the comments of an issue
and a
self.CommentsSorted = ko.computed(function() {...}); //...which simply returns a sorted Comments array
So when I serialize this model, the posted JSON now represents the Comments Array, but also the CommentsSorted Array. Only when I do
var i = ko.toJS(issue);
delete i.CommentsSorted;
before I post i as data, .NET is able to deserialize Comments correctly.
The mysterious thing about this is, that there were always other computed fields in my knockout model, which get ignored completely by .NET and do not disturb deserialization in any way. So it seems that it depends mainly on the name and type of the fields in the model (perhaps if the first letters are equal?).
The good thing: it works now
The bad thing: it isn't really deterministic how .NET does the deserialization of JSON data and I am also not able to debug if it doesn't behave as expected.

Manually trigger foolproof validation

I'm using Foolproof Validation so I can use [RequiredIf] attributes on my view model. The problem is that I'd like to trigger validation within my code using the same logic outside a controller.
I've tried creating my own validation context and using Validatior.TryValidateObject; however, it fails with Foolproof's custom RequiredIf validator. Is there a way to take my model and validate it other than passing it to a controller?
Am I using the wrong approach?
Here is my code:
var draftModel = _draftHelper.LoadDraft(draftId);
var validationResults = new List<ValidationResult>();
var vc = new ValidationContext(draftModel, null, null);
var isValidDraft = Validator.TryValidateObject(draftModel, vc,
validationResults, true);
And the error I get is on the TryValidateObject line
System.NotImplementedException: The method or operation is not
implemented.
I think a better approach would be to use FluentValidation, not foolproof validation. I personally think Fluent is nicer than attributes too :).
Using FluentValidation, you are also able to validate your model without the use of a Controller.
DraftVM draft = draftRepository.Get(draftId);
var DraftValidator validator = new DraftVMValidator();
ValidationResult results = validator.Validate(draft);
public class DraftVMValidator : AbstractValidator<DraftViewModel>
{
public DraftVMValidator()
{
RuleFor(vm => vm.OptionalField)
.Must(BeFilledIfNameNotEmpty)
.WithMessage("Optional Field required because you filled out Name field");
}
public bool BeFilledIfNameNotEmpty(DraftVM viewModel)
{
return !string.IsNullOrWhiteSpace(viewModel.Name);
}
}
This will NOT give you a System.NotImplemented exception.
This validator is DRY because you can also plug it into ASP.NET MVC Validation.
You can simply call the following code in Global.asax or App_Start etc. One validator for all, bind it to MVC Model Validation or use it in any normal application.
FluentValidationModelValidatorProvider.Configure(); // This will bind it for you
If you use Inversion of Control container like Ninject, FluentValidation also has a plugin to work with that. More available on their documentation in link provided above.
I have a pretty big project example in my Github if you want to see more examples of this Validator instead of FoolProof. Example Validators with ASP.NET MVC 4
You need to let the MVC framework provide your Validator instead of using the Validator.TryValidateObject as below:
var modelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => viewModelToValidate, viewModelToValidate.GetType());
var compositeValidator = ModelValidator.GetModelValidator(modelMetadata, controller.ControllerContext);
foreach (ModelValidationResult result in compositeValidator.Validate(null))
{
validationResults.Add(new ValidationResult(result.Message, new List<string> { result.MemberName }));
}

Which MVC Validation Framework

I have been evaluating xVal as framework for validating Entities in the ASP.Net MVC Framework. I have recently discovered that each time a validation rule is broken, xVal cause an excpetion to be thrown. To me is seems incorrect. For example, when a user fills in a form, and forgets to fill three required fields , three exceptions will be thrown. Is this good practice? ( Edit: I also read this, so I guess its not good practice)
What are your experiences of using xVal? Is there good alternative validation framework that does not throw exceptions?
Thanks
(PS: I notice that lots of people are reading this, just to let you know I am using Fluent Validation now)
Have you looked at validation in Beta 2?
http://blogs.msdn.com/rickandy/archive/2009/10/03/client-side-validation-for-mvc-2-p2.aspx
No it's not a good practice to show exceptions instead of some simple messages because nothing seriously has been going wrong... You should instead populate ModelState with these errors and display them on the form using
Html.ValidationMessage("EntityPropertyName");
xVal supports all these. As well as validating on the client side before the form gets posted back.
Some code
When you set DataAnnotations attributes to your entity classes (or their Metadata companion classes) you will most likely also implement Validate() method. the best way would be to use T4 that will auto generate those for you, so you don't have to repeate the same code over and over...
public IEnumerable<ErrorInfo> Validate()
{
IList<ErrorInfo> errors = DataAnnotationsValidationRunner.GetErrors(this).ToList<ErrorInfo>();
return errors.AsEnumerable();
}
All you have to do then is to call this:
IEnumerable<ErrorInfo> errors = entityObjectInstance.Validate();
if (errors.Any())
{
new RulesException(errors).AddModelStateErrors(filterContext.Controller.ViewData.ModelState, entityPropertyName);
}
And to automate this even further, you can implement this in an action filter, so validation will be automatic for your entity objects that get passed into controller action. Controller actions would only need to check whether ModelState.IsValid() then.
One more class you'll need here is (and is taken from the web somewhere):
public static class DataAnnotationsValidationRunner
{
public static IEnumerable<ErrorInfo> GetErrors(object instance)
{
var metadataAttribute = instance.GetType().GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType<MetadataTypeAttribute>().FirstOrDefault();
var metaClass = metadataAttribute != null ? metadataAttribute.MetadataClassType : instance.GetType();
var metaClassProperties = TypeDescriptor.GetProperties(metaClass).Cast<PropertyDescriptor>();
var modelClassProperties = TypeDescriptor.GetProperties(instance.GetType()).Cast<PropertyDescriptor>();
return from metaProp in metaClassProperties
join modelProp in modelClassProperties on metaProp.Name equals modelProp.Name
from attribute in metaProp.Attributes.OfType<ValidationAttribute>()
where !attribute.IsValid(modelProp.GetValue(instance))
select new ErrorInfo(metaProp.Name, attribute.FormatErrorMessage(string.Empty), instance);
}
}
MVC 2
Validation in Asp.net MVC 2 Beta 2 is similar to what xVal does. So if you're not too far into the project and you can consider using code in development progress as your foundation, maybe that is the way to go for you.
I think xVal is great, I've been using it with Castle Validators and it works perfectly. Just catch the RulesException whenever you're running validation and add the errors to your ModelState, e.g.
try
{
// execute validation runner
}
catch (RulesException ex)
{
ex.AddModelStateErrors(ModelState, "prefix");
}
ASP.NET MVC v2 will introduce its own validation framework.

Resources