Contacting database from within data validation attribute - c#

I have a clientside typeahead that pulls back a json list and presents options to the user for a specific list of places that they can enter for an input field.
On the server I want to make sure that the submitted form data matches one of these places. Realistically it should unless someone was being malicious and posting data from fiddler or something like that.
I supply the data to the typeahead from a list stored in Redis. I've read that it's bad practice to contact a database from within an attribute but I would like to check for the existence of the place in the redis list before allowing the logic flow to continue.
I could cache the list statically on startup in each webserver instance however this now means that if the list changes at all then all the servers would have to be restarted to get the changes.
Perhaps instead of using Validation Attributes I should be using a fluent validator?
http://fluentvalidation.codeplex.com/wikipage?title=ValidatorFactory&referringTitle=Documentation

I've read that it's bad practice to contact a database from within an
attribute [...]
Your attribute does not need to know about any database or anything of that matter. What your attribute needs to do is to call a Service to do the job. The implementation of the Service will be hidden from your Attribute's point of view.
interface IValidationService
{
bool DoesPlaceExist(Place place);
}
class RedisValidationService : IValidationService
{
bool DoesPlaceExist(Place place)
{
// crazy redis magic ...
}
}
class PlaceValidationAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var validationService = new RedisValidationService(); // ideally use IoC
var isValid = validationService.DoesPlaceExists(new Place(value));
// ... this is over simplified to just show the idea
// return blah blah
}

Related

.Net 6.0 Blazor Server: Proper approach to checking IsUnique against the backend DB for Email / Phone number on Blazor form

I have a .net 6.0 Blazor Server web application that is essentially a basic registration form (contact information: First Name, Last Name, Email, Phone, etc).
I'm trying to create a custom ValidationAttribute (EmailUniqueAttribute) that will check for uniqueness of the form's email field against the backend database. If it exists already IsValid returns false , else if it doesn't it returns true.
The problem I'm encountering is that it appears that you can only pass constant arguments into a custom ValidationAttribute? In this case the argument that would need to be used in the validation is a boolean value that is determined at runtime based on user input to the email field and the result of a database query to check for its existence (IsUnique).
I thought about injecting my service to the back end calls into the custom ValidationAttribute and checking for uniqueness at the time of validation (anti pattern debates aside) but it looks like support for DI into a ValidationAttribute isn't available until .Net 7.1 preview based on other articles and questions I've read on this topic here.
How exactly should I go about this?
Well there are several ways to solve it:
A first one would be to setup the email-column inside your database with a unique constraint (you can do this for every solution/way). Duplicate entries will then throw an error on save. Simply catch the save-error and show them to your frontend.
Another way would be to handle errors a bit earlier by using the OnSubmit method of your EditForm. Inject a Service that reads all mail-entries from your database and check them against the entered email address. It should be sufficient to call the service once at OnInitialized to prevent multiple database selections for probably the same list.
A more convenient way for the user would be to use the above mentioned service to check the mail uniqueness while typing into the InputText field. You can hook up to several events there like #oninput.
You could also use some custom Validation packages like FluentValidation that extend the validation system by a more complex system which allows more complicated conditions to check against.
EDIT:
You can still make use of a custom attribute if desired:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
public class EmailUniquenessAttribute : DataTypeAttribute
{
private EmailService _service;
public EmailUniquenessAttribute() : base(DataType.EmailAddress)
{
// You can use your DI system to get the desired service here
_service = new EmailService();
}
public override bool IsValid(object value)
{
if (value == null)
{
return true;
}
if (value is not string valueAsString)
{
return false;
}
return _service.EmailAlreadyExistsInDatabase(valueAsString);
}
}

Fhir validate structure definition does not seem to work

I have some custom code which creates a structure definition based on some user inputs. The way it works is to set up a differential by getting structure definition requirements from user, generates the snapshot and finally I persist it into local storage on Fhir Server.
I tried the following code snippet to validate the StructureDefinition before persisting it to database, but the validationResult is always null no matter what the structureDefinition I will pass to it.
Could anyone let me know of the correct way to validate a customized StructureDefinition?
var structureDefinition = ...
ICollection<ValidationResult> validationResult = null;
DotNetAttributeValidation.TryValidate(structureDefinition, validationResult);
There's a third (optional) parameter to TryValidate that is called 'recurse', you should try setting that to "true", otherwise the validate will only do the direct elements of the structuredefinition, not the data inside the types etc.

What does [Required] do?

I found nothing on the web what [Required] actually does. The msdn-article is not explorative at all.
static class Program
{
public static Main()
{
var vustomer = new CustomerClass();
}
}
public class CustomerClass
{
public string m_FirstName;
[Required]
public string m_LastName;
}
As far as i understand, that should throw an exception since m_LastName is required, but not set. But i don't get one. I don't get what it's good for and what this actually does.
RequiredAttribute, like all other attributes, does nothing by itself other than annotate something (in this case, a field of a type). It is entirely up to the application that consumes the type to detect the presence of the attribute and respond accordingly.
Your sample program does not do this, so the attribute does not have any visible effect. Certain frameworks such as ASP.NET MVC and WPF do check for and respond to the presence of the attribute.
This attribute is used by the Validator class to add validation errors based on any types that inherit from ValidationAttribute. This is used by MVC model validation, for example.
In C#, attributes are almost decoration to classes and properties.
Except for a few security related attributes, most do nothing. They are used by a higher-level framework to do something.
In the case of ASP.NET 4 MVC, only when the object is part of a request that attribute is used to generate an error.
If you want to use that attribute in any other environment, you must write code to inspect it.
It won't do anything from a plain old public static void Main()
Documentation on RequiredAttribute:
Specifies that a data field value is required.
However this validation is typically only performed in the UI layer. It is not "baked" into the constructor or other low-level usage. If you want to manually fire the validation you could do something like:
var customer = new CustomerClass();
var context = new ValidationContext(customer, serviceProvider: null, items: null);
var results = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(customer, context, results);
if (!isValid)
{
foreach (var validationResult in results)
{
Console.WriteLine(validationResult.ErrorMessage);
}
}
To add to the current answers, these are some of the practical uses I can think of out of my head:
Entity Framework use this to model the database as not nullable fields.
Javascript client side validation provides javascript libraries for checking if the input field has any data, else prevent the form submission avoiding unnecesary roundtrips to the server.
Server side validation (when doing model binding) also check when you are posting a model with that decorator that the attribute passed in is in the request. This determines if the model state should be set to an invalid state or not. (1)
There are also annotation for JSON.NET library that changes how the model is serialized/unserialized. I'm pretty confident (but not sure) that the Validate Schema of Json.net does take into consideration the 'Required' attribute when validating a schema.
Other attribute decorators are used on web services, but 'Required' is not one I know has it uses in this scenario.
Web api uses this attribute to mark the property as required on documentation help pages and model binding.
You can create your own application logic that can be aware of the 'Required' property. For example, on a view to mark the property with an * in the label if it's required.
This are some uses but you are not limited to them.
(1) Note: if your property is, for example, an int and you decorate it with Required, model state will never be on a invalid state. You should use Nullable properties for this use-cases.

Selectively Serialize and Deserialize

I have a User object in my Linq-To-Sql mapping. There is a password attribute on it that I want to deserialize when submitted by a user--for example, during login. I never want to pass this attribute back to the user, though, since it will contain the encrypted version of the actual password and I'd rather not expose any information about the password or the encryption method. Is there a way to object-wide tell Linq-To-Sql to never pass the Password attribute when returning a User object?
I use https for encryption, mostly because just in accessing the service, you by default enforce your encryption, which saves on client side code. You have a few possible answers though:
Blank out the password when you return the User Object from the WCF side. (You can change the value of the password of the object, and just not save the change.. then return the object to the client )
Use a custom object for your login response that returns only the necessary information for your client.
Implement a Data Transfer Object pattern, with a nuget package like AutoMapper.
If you aren't salting and hashing your passwords, please please please consider it.
In the case where I never want to serialize an object, it is best to hook into the OnSerializing event. Since I'm using Linq-To-Sql, the OnSerializing event has already been captured by my DataContext's designer.cs for tracking serialization state for lazing loading entity references. Adding another function decorated with [OnSerializing] throws an error in System.ServiceModel.Activation, so I had to find another route. Here's my solution:
Modify DataContext.designer.cs
In DataContext.designer.cs, I added
[global::System.Runtime.Serialization.OnSerializingAttribute()]
[global::System.ComponentModel.EditorBrowsableAttribute(EditorBrowsableState.Never)]
public void OnSerializing(StreamingContext context)
{
this.serializing = true;
// custom function to handle my logic
this.ClearPassword();
}
Add Method to my custom Class Definition
In my User.cs file, I have a partial class definition. Therefore, all I need to do is add the ClearPassword method to my partial class definition:
partial class User
{
private void ClearPassword()
{
this.Password = null;
}
//* OTHER CODE *//
}
Now, no matter how I'm interacting with User objects, passwords are never passed to the client, as desired.

How To Do Validation in Silverlight/RIA When A Call To Database Is Required?

I feel like there is a better way to do this than how I am doing it now.
I am using Silverlight 4, RIA and EF (with an Oracle adapter). I am inserting a record into a table and doing a lot of validation on it with Validation attributes, but I have one piece of validation that requires querying the DB to check existing records before the new one can be inserted (this seems like it should be common and easy requirement, no?)
Right now, I am doing this client-side with an Invoke method on the DomainService. This seems lame and dumb. But I can't figure out how to do this server-side where it really belongs.
It seems like there should be a way to handle all of this server-side and inform the client of a validation error, but I can't quite figure it out and hardly anyone seems to approach this one particular validation scenario.
WCF RIA provides a means to attach validation to entities on the serverside. You build a class as detailed below naming it Rules.
public static partial class FooRules
{
public static ValidationResult FooIDUnique(Foo foo, ValidationContext context)
{
bool check = false;
using (FooEntities fe = new FooEntities())
{
check = fe.Foo.Any(f => f.FooId == foo.fooId);
}
if (!check)
return ValidationResult.Success;
return new ValidationResult("FooID error msg,", new string[] { "FooID" });
}
}
I've put together an example app that shows adding validation client and server side with RIA.
You can download it here.
I don't know how to link to the specific entry but check out this thread....
http://forums.silverlight.net/forums/p/212555/502113.aspx

Categories