DataAnnotation TextArea Multiple Emails - regex

I am using MVC 3.
I have a text area in which user can enter multiple emails addresses. Emails can be separated by a comma and a space. User may hit enter in the box as well.
Is there an attribute that can handle this scenario?
I am using regular expression to check for the characters and it is failing for "abc#abc.com, tyz#tyz.com"
Here is my regular expression:
[RegularExpression(#"([a-zA-Z0-9 .#-_\n\t\r]+)", ErrorMessage = ValidationMessageConstants.EmailAdressInvalid)]
What am i missing here? This regular expression is off the following post:
DataAnnotations validation (Regular Expression) in asp.net mvc 4 - razor view

Out of the box, .NET 4.5 has the System.ComponentModel.DataAnnotations.EmailAddressAttribute found in the System.ComponentModel.DataAnnotations assembly, but this is limited to validating just one email address. Hence, if you have a model that accepts delimitted email address and you decorate the property with this attribute, it will fail since it will treat the entire string as one email.
What I've done is create an extended emailaddress attribute that validates the delimited email addresses:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
public class EmailAddressExAttribute : DataTypeAttribute
{
#region privates
private readonly EmailAddressAttribute _emailAddressAttribute = new EmailAddressAttribute();
#endregion
#region ctor
public EmailAddressExAttribute() : base(DataType.EmailAddress){ }
#endregion
#region Overrides
/// <summary>
/// Checks if the value is valid
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public override bool IsValid(object value)
{
var emailAddr = Convert.ToString(value);
if (string.IsNullOrWhiteSpace(emailAddr)) return false;
//lets test for mulitple email addresses
var emails = emailAddr.Split(new[] {';', ' ', ','}, StringSplitOptions.RemoveEmptyEntries);
return emails.All(t => _emailAddressAttribute.IsValid(t));
}
#endregion
}
You can now decorate any string property with this new extended attribute to validate delimited email addresses. You can update the delimiters to include any special characters you want to use as well.
Hope this helps!

You not stating what the question is, so I will have to assume from your answer that data annotations aren't working as you would expect.
Having that assumption in mind, its very easy why is it not working: data annotation operates on the entire field, text area in your case. It will work as expected if you have only one email. Since you have multiple emails in that field, separated by comma or space, the field in its entirety doesn't reflect what data annotation for email prescribes and fails.
To answer your numbered questions:
No, there is no out of the box
The regular expression you using doesn't account for multiple emails, but one. The solution in your case will be either to
Data annotation using RegEx for multiple emails separated as you'd like or
Have custom validation attribute doing it for you
Following the links above you will see very good examples of "how to" and hopefully get you going in the right direction.
Hope this helps, please let me know if not.

Related

Replace variable names with actual class Properties - Regex? (C#)

I need to send a custom email message to every User of a list ( List < User > ) I have. (I'm using C# .NET)
What I would need to do is to replace all the expressions (that start with "[?&=" have "variableName" in the middle and then ends with "]") with the actual User property value.
So for example if I have a text like this:
"Hello, [?&=Name]. A gift will be sent to [?&=Address], [?&=Zipcode], [?&=Country].
If [?&=Email] is not your email address, please contact us."
I would like to get this for the user:
"Hello, Mary. A gift will be sent to Boulevard Spain 918, 11300, Uruguay.
If marytech#gmail.com is not your email address, please contact us."
Is there a practical and clean way to do this with Regex?
This is a good place to apply regex.
The regular expression you want looks like this /\[\?&=(\w*)\]/ example
You will need to do a replace on the input string using a method that allows you to use a custom function for replacement values. Then inside that function use the first capture value as the Key so to say and pull the correct corresponding value.
Since you did not specify what language you are using I will be nice and give you an example in C# and JS that I made for my own projects just recently.
Pseudo-Code
Loop through matches
Key is in first capture group
Check if replacements dict/obj/db/... has value for the Key
if Yes, return Value
else return ""
C#
email = Regex.Replace(email, #"\[\?&=(\w*)\]",
match => //match contains a Key & Replacements dict has value for that key
match?.Groups[1].Value != null
&& replacements.ContainsKey(match.Groups[1].Value)
? replacements[match.Groups[1].Value]
: "");
JS
var content = text.replace(/\[\?&=(\w*)\]/g,
function (match, p1) {
return replacements[p1] || "";
});

Use a view to get the same suffix like maindomain name

I have some documents, how can use a view to get the document which have the same domain name for their email address. like all the document with #gmail.com or #yahoo.com, if endkey can get that results?
Here is what I wrote a view on map, But I do not think this is good idea
function(doc) {
for (var i in doc.emails) {
if (doc.emails[i].emailAddress.toLowerCase().indexOf("#yahoo.ibm.com")!=-1) {
emit(doc.emails[i].emailAddress.toLowerCase(), doc);
}
}
}
}
To make things clear, the endkey parameter is not looking for a suffix. Startkey and endkey are like the limits of keys to get. For example, you could get the document with the id 1 to the id 10 startkey="1"&endkey="10" .
In your case, you want to make a view that will group your documents by their domain name. I created a design document with a byDomain view. The mapping function looks like this :
function(doc){
if(doc.email){ //I used the document's property email for my view.
//Now, we will emit an array key. The first value will be the domain.
//To get the domain, we split the string with the character '#' and we take what comes after.
//Feel free to add more validations
//The second key will be the document id. We don't emit any values. It's faster to simply add
//the includes_docs query parameter.
emit([doc.email.split('#')[1],doc._id]);
}
}
Let's query all my documents to show you what I have
Request : http://localhost:5984/test/_all_docs?include_docs=true
Response:
{"total_rows":4,"offset":0,"rows":[
{"id":"7f34ec3b9332ab4e555bfca202000e5f","key":"7f34ec3b9332ab4e555bfca202000e5f","value":{"rev":"1-c84cf3bf33e1d853f99a4a5cb0a4af74"},"doc":{"_id":"7f34ec3b9332ab4e555bfca202000e5f","_rev":"1-c84cf3bf33e1d853f99a4a5cb0a4af74","email":"steve#gmail.com"}},
{"id":"7f34ec3b9332ab4e555bfca202001101","key":"7f34ec3b9332ab4e555bfca202001101","value":{"rev":"1-53a8a9f2a24d812fe3c98ad0fe020197"},"doc":{"_id":"7f34ec3b9332ab4e555bfca202001101","_rev":"1-53a8a9f2a24d812fe3c98ad0fe020197","email":"foo#example.com"}},
{"id":"7f34ec3b9332ab4e555bfca202001b02","key":"7f34ec3b9332ab4e555bfca202001b02","value":{"rev":"1-cccec02fe7172fb637ac430f0dd25fa2"},"doc":{"_id":"7f34ec3b9332ab4e555bfca202001b02","_rev":"1-cccec02fe7172fb637ac430f0dd25fa2","email":"bar#gmail.com"}},
{"id":"_design/emails","key":"_design/emails","value":{"rev":"4-76785063c7dbeec96c495db76a8faded"},"doc":{"_id":"_design/emails","_rev":"4-76785063c7dbeec96c495db76a8faded","views":{"byDomain":{"map":"\t\tfunction(doc){\n\t\t\tif(doc.email){ //I used the document's property email for my view.\n\t\t\t\t//Now, we will emit an array key. The first value will be the domain.\n\t\t\t\t//To get the domain, we split the string with the character '#' and we take what comes after.\n\t\t\t\t//Feel free to add more validations\n\t\t\t\t//The second key will be the document id. We don't emit any values. It's faster to simply add\n\t\t\t\t//the includes_docs query parameter.\n\t\t\t\temit([doc.email.split('#')[1],doc._id]); \n\t\t\t}\n\t\t}"}},"language":"javascript"}}
]}
As you can see, I got few minimalist documents with the property "email" set.
Let's query my view without any parameters
Request : http://localhost:5984/test/_design/emails/_view/byDomain
Response :
{"total_rows":3,"offset":0,"rows":[
{"id":"7f34ec3b9332ab4e555bfca202001101","key":["example.com","7f34ec3b9332ab4e555bfca202001101"],"value":null},
{"id":"7f34ec3b9332ab4e555bfca202000e5f","key":["gmail.com","7f34ec3b9332ab4e555bfca202000e5f"],"value":null},
{"id":"7f34ec3b9332ab4e555bfca202001b02","key":["gmail.com","7f34ec3b9332ab4e555bfca202001b02"],"value":null}
]}
Let's query only documents with that have the gmail.com domain.
Request : http://localhost:5984/test/_design/emails/_view/byDomain?startkey=["gmail.com"]&endkey=["gmail.com","\ufff0"]
Result :
{"total_rows":3,"offset":1,"rows":[
{"id":"7f34ec3b9332ab4e555bfca202000e5f","key":["gmail.com","7f34ec3b9332ab4e555bfca202000e5f"],"value":null},
{"id":"7f34ec3b9332ab4e555bfca202001b02","key":["gmail.com","7f34ec3b9332ab4e555bfca202001b02"],"value":null}
]}
You can just use a simple map function for this:
function (doc) {
var domain = doc.email.split('#').pop();
// this logic is fairly hack-ish, you may want to be more sophisticated
emit(domain);
}
Then you can simply pass key=gmail.com to get the results you want from the view. I would also add include_docs=true instead of emitting the entire document as your value.
You can read more about views in the official CouchDB docs.

ASP.NET Web API 2 Model Validation with Regular Expression

In my web api 2 Controller i have a Create method that contains the following logic:
if (((assignment.type).ToLower() != "individual" && (assignment.type).ToLower() != "staff")) {
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "The Assignment Type
must be either 'individual' or 'staff'");
}
I am using model state validation. Is it possible to assign a regular expression to a property to eliminate the need to do the checking in the controller? If so, what would that reg ex look like to return valid only if the exact string (case insensitive) of "individual" or "staff" is passed by the user of the api?
Thanks to some guidance in the comments, I ended up with this, which works well:
[RegularExpression(#"^(?i)(individual|staff)$", ErrorMessage="...")]
public string type { get; set; }
If you want a Regex than use something like
new Regex(#"^(individual|staff)$", RegexOptions.IgnoreCase)
But, I would recommend to create an enum with corresponding values and make your model property of that enum.

What is ScaffoldColumn and RegularExpression attributes

I am trying to learn MVC4 and i've come to this chapter called validation.
I came to know about DataAnnotations and they have pretty neat attributes to do some server side validation. In book they have only explained about [Required] and [Datatype] attribute. However in asp.net website i saw something called ScaffoldColumn and RegularExpression.
Can someone explain what they are, even though I know little what RegularExpression does.
Also are there any other important validation attributes I should know?
Scaffold Column dictates if when adding a view based on that datamodel it should/not scaffold the column. So forexample your model's id field is a good candidate for you to specify ScaffoldColumn(false), and other foreign key fields etc.
I you specify a regular expression, then if you scaffold a new view for that model,edit customer for example, a regex or regular expression on field will enforce that entered data must match that format.
You can read about ScaffoldColumnAttribute Class here
[MetadataType(typeof(ProductMetadata))]
public partial class Product
{
}
public class ProductMetadata
{
[ScaffoldColumn(true)]
public object ProductID;
[ScaffoldColumn(false)]
public object ThumbnailPhotoFileName;
}
And about RegularExpressionAttribute Class you can read here.
using System;
using System.Web.DynamicData;
using System.ComponentModel.DataAnnotations;
[MetadataType(typeof(CustomerMetaData))]
public partial class Customer
{
}
public class CustomerMetaData
{
// Allow up to 40 uppercase and lowercase
// characters. Use custom error.
[RegularExpression(#"^[a-zA-Z''-'\s]{1,40}$",
ErrorMessage = "Characters are not allowed.")]
public object FirstName;
// Allow up to 40 uppercase and lowercase
// characters. Use standard error.
[RegularExpression(#"^[a-zA-Z''-'\s]{1,40}$")]
public object LastName;
}

How can I set a RegularExpression data annotation's regular expression argument at runtime?

We manage several ASP.NET MVC client web sites, which all use a data annotation like the following to validate customer email addresses (I haven't included the regex here, for readability):
[Required(ErrorMessage="Email is required")]
[RegularExpression(#"MYREGEX", ErrorMessage = "Email address is not valid")]
public string Email { get; set; }
What I would like to do is to centralise this regular expression, so that if we make a change to it, all of the sites immediately pick it up and we don't have to manually change it in each one.
The problem is that the regex argument of the data annotation must be a constant, so I cannot assign a value I've retrieved from a config file or database at runtime (which was my first thought).
Can anyone help me with a clever solution to this—or failing that, an alternative approach which will work to achieve the same goal? Or does this just require us to write a specialist custom validation attribute which will accept non-constant values?
The easiest way is to write a custom ValidationAttribute that inherits from RegularExpressionAttribute, so something like:
public class EmailAttribute : RegularExpressionAttribute
{
public EmailAttribute()
: base(GetRegex())
{ }
private static string GetRegex()
{
// TODO: Go off and get your RegEx here
return #"^[\w-]+(\.[\w-]+)*#([a-z0-9-]+(\.[a-z0-9-]+)*?\.[a-z]{2,6}|(\d{1,3}\.){3}\d{1,3})(:\d{4})?$";
}
}
That way, you still maintain use of the built in Regex validation but you can customise it. You'd just simply use it like:
[Email(ErrorMessage = "Please use a valid email address")]
Lastly, to get to client side validation to work, you would simply add the following in your Application_Start method within Global.asax, to tell MVC to use the normal regular expression validation for this validator:
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(EmailAttribute), typeof(RegularExpressionAttributeAdapter));
Checkout ScotGu's [Email] attribute (Step 4: Creating a Custom [Email] Validation Attribute).
Do you really want to put the regex in database/config file, or do you just want to centralise them? If you just want to put the regex together, you can just define and use constants like
public class ValidationRegularExpressions {
public const string Regex1 = "...";
public const string Regex2 = "...";
}
Maybe you want to manage the regexes in external files, you can write a MSBuild task to do the replacement when you build for production.
If you REALLY want to change the validation regex at runtime, define your own ValidationAttribute, like
[RegexByKey("MyKey", ErrorMessage = "Email address is not valid")]
public string Email { get; set; }
It's just a piece of code to write:
public class RegexByKeyAttribute : ValidationAttribute {
public RegexByKey(string key) {
...
}
// override some methods
public override bool IsValid(object value) {
...
}
}
Or even just:
public class RegexByKeyAttribute : RegularExpressionAttribute {
public RegexByKey(string key) : base(LoadRegex(key)) { }
// Be careful to cache the regex is this operation is expensive.
private static string LoadRegex(string key) { ... }
}
Hope it's helpful: http://msdn.microsoft.com/en-us/library/cc668224.aspx
Why not just write you own ValidationAttribute?
http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.validationattribute.aspx
Then you can configure that thing to pull the regex from a registry setting... config file... database... etc... etc..
How to: Customize Data Field Validation in the Data Model Using Custom