I'm developing a MVC4 Website with a SQL Server database. I want to register people with their email address.
However if email address contains the character i
, WebSecurity.CreateUserAndAccount
method throws an exception says :
The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.
I researched a lot and find a few posts about it but there is no solution.
http://forums.asp.net/t/1862233.aspx/1?How+can+i+use+email+address+for+username+in+MVC4+Membership
http://aspnetwebstack.codeplex.com/workitem/714
Your fundamental problem is that you are trying to input non-ASCII characters as an e-mail address.
The "ASCII character set" limits you to the US-English alphabet, which happens to be the latin alphabet.
I don't speak turkish, but as pointed out in http://aspnetwebstack.codeplex.com/workitem/714
In Turkish, 'i' is lowercase, while 'İ' is upper of "i".
In the latin alphabet, which you (and me) happen to not have IT-wise, 'i' is lowercase, while 'I' is uppercase of i.
So you have a character which is not a member of the EN-US ASCII character set.
Therefore, the collation setting prevents you from inputting non-ASCII characters into your database, hence the error.
And hence the comment that you shall NOT change the collation setting (which would allow for invalid mail addresses).
As pointed out, ToUpper (which should be ToUpperInvariant) is to blame, because it behind the scenes changes the 'i' to 'İ', which is not a valid ASCII character.
This is a common problem with the ToUpper method of a string/character.
For example the German alphabet contains the letter ß (Unicode U+00DF), also known as "double s", which has no corresponding uppercase character in the first place, therefore if you try to compare strings using toUpper, it will always fail, which is why you should always use ToLower() to compare strings - another Microsoft fail.
A similar thing happens here with ToUpper.
What you need to do in the first place is to ensure your users input ASCII characters.
This is not possible since they have a turkish keyboard and locale, and while the small i will look similar to the ASCII small i, it has a different numerical representation, and therefore a different uppercase character (and lowercase as well btw).
So what you need to do is to "latinize/romanize" your input string, prior to calling the membership method.
I had similar problems with ASCII-only capable software from a third party, which failed on umlauts and French accent characters, and used the below method to resolve this.
You might want to check if the Turkish äöü doesn't have a different numerical representation than the (Swiss) German äöü that I used here.
For risks and side-effects, read the package leaflets and ask your doctor or pharmacist.
// string str = ApertureSucks.Latinize("(æøå âôû?aè");
public static string Latinize(string stIn)
{
// Special treatment for German Umlauts
stIn = stIn.Replace("ä", "ae");
stIn = stIn.Replace("ö", "oe");
stIn = stIn.Replace("ü", "ue");
stIn = stIn.Replace("Ä", "Ae");
stIn = stIn.Replace("Ö", "Oe");
stIn = stIn.Replace("Ü", "Ue");
// End special treatment for German Umlauts
string stFormD = stIn.Normalize(System.Text.NormalizationForm.FormD);
System.Text.StringBuilder sb = new System.Text.StringBuilder();
for (int ich = 0; ich < stFormD.Length; ich++)
{
System.Globalization.UnicodeCategory uc = System.Globalization.CharUnicodeInfo.GetUnicodeCategory(stFormD[ich]);
if (uc != System.Globalization.UnicodeCategory.NonSpacingMark)
{
sb.Append(stFormD[ich]);
} // End if (uc != System.Globalization.UnicodeCategory.NonSpacingMark)
} // Next ich
//return (sb.ToString().Normalize(System.Text.NormalizationForm.FormC));
return (sb.ToString().Normalize(System.Text.NormalizationForm.FormKC));
} // End Function Latinize
And last but not least, I would not use the built-in ASP.NET membership provider, because it joins tables via username + applicationname to rolename, instead of using a unique id. This means you will not be able to change a user or group/role name without changing all the mapping tables.
I think doing that this way is highly undesirable, and definitely stupid and careless, if not outright hazardous from Microsoft's part.
I would go as far as calling it impudent to release such garbage into the wild.
The below "thing" demonstrates the problem's utter stupidity and should not ever be used
CREATE TABLE [dbo].[UsersInRoles](
[Username] [varchar](255) NOT NULL,
[Rolename] [varchar](255) NOT NULL,
[ApplicationName] [varchar](255) NOT NULL,
CONSTRAINT [usersinroles_pkey] PRIMARY KEY CLUSTERED
(
[Username] ASC,
[Rolename] ASC,
[ApplicationName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
for the following reasons:
and I am sure there are a lot more problems with the MS-supplied membership-provider fiasco. For example using a fast hash algorithm (MD5), which is an antipattern for this case, because that allows for rainbow table attack, especially if the hash is not salted. If the MS membership provider demonstrates one thing, then this is how NOT to design a membership provider.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With