Tuesday, March 27, 2012

ASP.Net MVC 3 : Why [DataType] is not validating email?

When we search for how to do validations in MVC 3 we normally get sites which tell to put a DataType attribute on the model property. It is pretty straight forward. Last week I was doing some customization to the thinktecture's identityserver to have users registration and used the same attributes for validation. The requirement is to have e-mail as username. So I just accept the email and used the same to pass to Membership as username while creating user.I didn't give much time for unit testing the validation as I am in an impression that it is from the framework and it should work.

When the app reached next stage an issue popped up related to sending the confirmation mail. I was using the framework classes for sending mails along with the mail server credentials in the web.config. That was an issue with the credential but it made me to unit test missed features too. It was a shock that the email validation is not happening. Its allowing users to register with non-email format as username.Below is the model for the user registration.

    public class RegisterUserModel
    {
        [Required]
        [DataType(DataType.Password)]
        [DisplayName("Password")]
        [StringLength(25,MinimumLength = 6,ErrorMessage ="Password length should be between 6-25")]
        public string Password { getset; }
 
        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { getset; }
 
        [Required]
        [DataType(DataType.EmailAddress, ErrorMessage = "Please enter valid email address")]
        [DisplayName("E-mail")]
        public string eMail { getset; }
 
        [Required]
        [DisplayName("Password question")]
        public string PasswordQuestion { getset; }
 
        [DataType(DataType.Password)]
        [Display(Name = "Password question answer")]
        public string PasswordQuestionAnswer { getset; }
    }

The google started from there. First suggestion was to enable the client side validation in web.config.It was already present

   <add key="ClientValidationEnabled" value="true"/>
   <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
 
Then people were suggesting to have the correct js files in the view.That too was there.

<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

Another suggestion was to put the type attribute forcefully. I tried as below but didn't give any positive result.
@Html.TextBoxFor(m => m.Email, new { type = "email" })


Finally there were suggestions to use ASP.Net MVC 3 futures which is coming through a nuget package. But I was not interested to add one more nuget package to the application as it is already flooded with nuget packs.So I decided to reflect the code of DataType attribute. It was another shock the DataAttribute.IsValid method is at all implemented.


Yes its time to install the MVC 3 futures which has the [EmailAddress] attribute which does the real validation.Below are the steps to install and get the email validation working in Asp.Net MVC 3
  1. Install the nuget package for MVC3 futures.
  2. Import the namespace Microsoft.Web.Mvc into our model.
  3. Add the EmailAddress attribute to the property which corresponds to email address.
[Required]
[EmailAddress(ErrorMessage = "Please enter valid email address")]
[DataType(DataType.EmailAddress, ErrorMessage = "Please enter valid email address")]
[DisplayName("E-mail")]
public string eMail { getset; }


This silly thing took my 3Hrs. I would have completed writing a validation class myself if the DataType attribute was not there with DataType.EmailAddress.

Saturday, March 24, 2012

Opening copied Android project in Eclipse

If you are working with the Eclipse tool for years, you will laugh at this .But this is for the developers like me who came to Eclipse from Visual Studio. In VSTS its very easy we have a .sln file and that cane be directly opened even if we port the project to a new machine or we got a new machine.

The things were not easy for me when I got new Win 7 machine. I backed up every project which were there in my vista machine. Then I setup the Android environment in new machine.Setting up is another big story. There are so many links 1 out there to setup the Android environment. After that when I tried to open my old project I was not able to find any option to open project through menu. ie it lacks File-> Open -> Project or File -> Open Project .Even I was not able to find what is the project file in the folder which I have. There are files with only extension such as .classpath and .project etc...I tried opening that but no chance.

While creating new project there is an option called "Create project from existing source" ie File -> New -> Android Project. I tried that but it said

"An Eclipse project already exists in this directory. Consider using File > Import > Existing Project instead"

Got another clue .I need to import old project. Then I tried that way .It first needed a workspace and when I created a workspace things started working.Thanks God...

Now I really understood why most of the Java training courses include more sessions on "How to use Eclipse?" where .Net teaches you about the language and framework without more importance to VS.

1 See the below links in order to setup environment.
http://developer.android.com/sdk/index.html
http://developer.android.com/resources/tutorials/hello-world.html
http://www.codeproject.com/Articles/102065/Android-A-beginner-s-guide

Monday, March 19, 2012

Poor developer's design tools

If you are working in a project where there is enough budget for purchasing design software or your product company have VSTS 2010 Ultimate or Enterprise architect to draw design diagrams, there is no need to read further .This is for poor developers and architects who have no access to designing software but need to draw the designs.

All these are web based where you can share your diagram with others and do collaborative design. Most of the times, I felt these are better in terms of user friendlies.

https://www.lucidchart.com
http://creately.com
http://flowchart.com
http://www.gliffy.com
http://www.dabbleboard.com/draw

The list will never get completed as new web apps are coming day by day. Hope I can update later...

Note : These diagrams reside in a third party company's database.So avoid if your design need to be secured.

Sites for UML tools info
http://modeling-languages.com/uml-tools/ 

Friday, March 16, 2012

ASP.Net MVC 3 : T4 Text templates for generating dynamic mail body

Actually there is no relation between ASP.Net MVC 3 and T4 Text templates. I added MVC in title as I learned template feature while working on registration module of an ASP.Net MVC 3 project. You can even have T4 Templates in console application.

The problem

As part of Azure ACS service our client wants to have our own custom identity provider which should stand with google and facebook. The specialty of our identity provider is, it can provide role details through claims as it uses simple ASP.Net membership. We selected thinktecture's IdentityServer and hosted in Azure. Initially we were hard coding the users and after successful implementation we started to think about registration. The target product is a mobile application and initial thought was to have a registration page in the website of the mobile app. But there are chances that a user may need to register from the mobile app when he finds it interesting . It is little difficult for him to go to the website and come back with his credentials. So decided to extend identity server to have registration.

As it is in agile model we started to write the module where we were able to complete registration with in hours. But when we talk to people we came to remember the normal registration process followed in other sites. ie a confirmation mail with code should be send and once confirmed a welcome mail.

How that confirmation code is generated is another story which I can tell in a future post. But that was one day job to complete and got it tested in Azure quickly. The system just sends a mail with confirmation link .When we opened the mail it never looked that much stylish like a production app. What is wrong with that ? Oh the contents. It's my English which sometime even I cannot understand .

Yes.Its not a developer's task to write stylish English and format the communication with colors and other stuff. Client has no ready made format for the mail at that point. But I needed to complete the module and switch to another important one. So how to give a customizable solution to this mailing problem where the developer will be free from changes in the mail content and style?


The proposals


There are so many solutions available to have customizable template based mailing solution such as
The solution - T4 Templates

The first 2 options needs one more nuget package into our application which we don't wan't as it is already flooded with nuget packages. They offer really sophisticated features in sending mails but we decided to go with the T4 templates method which don't want any new library to be added / installed.

Implementing T4 Templates for dynamic mails

It involves mainly 2 steps. Creating T4 template and render to get the actual text to be sent.

Creating T4 templates

It is easy as adding a .cs file. Right click on the project in solution explorer and select Add => New Item. In the dialog select C# => General => Preprocessed Text Template .The extension of the file will be '.tt'. It also generate a .cs along with that like a xaml or aspx file. You can have some thing as follows inside the template.


<#@ output extension=".txt" #>
<#@ template language="C#" #>
 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
 <head>
  <title>Welcome to your site!</title>
 </head>
 <body>
  <strong>Welcome to your site !!</strong><br/>
  <br />
  Your confirmation code is : <i><#= this.ConfirmationCode #> </i>.
  <br /><br />
  You may use the above code in the confirmation screen or click on the below link to confirm your registration.
  <br/><br />
  Your confirmation link : <a href="<#= this.ConfirmLink + this.ConfirmationCode #>"><#= this.ConfirmLink + this.ConfirmationCode #></a> 
 </body>
</html>


You can see some inline code in the template what are they ? They are nothing but properties of the ConfirmMail class.Is there a class generated? How to add properties to the class > Is it by editing the design   er generated cs file? No.

Adding partial class for template & properties

If you want to add properties or methods to the T4 template you need to first add a partial class as new cs file. The challenge here is to have 2 files with same name. That is any way not possible.So have the naming convention as ConfirmMail.partial.cs. Add those properties there.

Code - ConfirmMail.partial.cs

    public partial class ConfirmMail
    {
        public string ConfirmationCode { getprivate set; }
        public string ConfirmLink { getprivate set; }
        public ConfirmMail(string confirmationCode, string confirmLink)
        {
            this.ConfirmationCode = confirmationCode;
            this.ConfirmLink = confirmLink;
        }
    }


NB: Don't add the properties in the generated file because each time the editor refresh those properties will be deleted

Rendering template

Now you have the template and the place holders to replace to values. The remaining task is to render the template with actual values. Its simple as creating an object of the class and calling the TransformText() method.


            var template = new ConfirmMail(confirmCode, confirmLink);
            return template.TransformText();

The method TransformText is not coming from any base class.Its just a virtual method in the generated ConfirmMail class.

IntelliSense support in editing T4 Templates

By default Visual studio don't have support for editing T4 templates. But you can install VSTS 2010 extensions such as VisualT4 to edit the templates with intelli sense support.

Please don't think that the application of T4 templates are only in sending mail. You can even generate dynamic code, views and so many other things. Hope you had a spike in your brain which initiated thoughts on application of T4 Templates


The code support doesn't stop with some property substitutions . You can have loops inside the T4 template like MVC RAZOR views. More details can be obtained from below links


Links
http://msdn.microsoft.com/en-us/library/ee844259.aspx

Monday, March 12, 2012

Deploying ASP.Net MVC 3 to Azure - Could not load System.Web.WebPages

"Could not load file or assembly 'System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)"

This was the error I got after hosting an ASP.Net MVC 3 application to Windows Azure. This seems straight forward.The bin folder don't have the mentioned dll. When I checked my web.config I was not able to see any reference to 1.0.0.0 version of System.Web.WebPages .The confusion started from there. Who is in need of the 1.0.0.0 version of system.web.webpages.dll. As debugging in Azure from local machine is difficult, I had to do remote desktop to Azure machine. Still no clues. In the web.config,I could see that I am referring the WebPages dll which is in version 2.0.0.0 and in the bin folder I have the right version.

I tried to locate the fusion log viewer in the Azure machine .But no luck. Not able to locate 1fuslogvw.exe there as it is available with sdk only.

Then I tried to create the registry entry2 to log the assembly binding .Due to some unknown reasons it was not working.Finally I had to check the references of each assembly which are present in the bin folder usnig reflector.

Luckily the first assembly I selected in the reflector was System.Web.MVC where it was referring 1.0.0.0 version of system.web.webpages.dll. Then I checked where from the webpages dll came ? it was interesting .There are 2 folders in my dev machine where the webpages dll is present in different versions.

C:\Program Files\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\Assemblies
C:\Program Files\Microsoft ASP.NET\ASP.NET Web Pages\v2.0\Assemblies

Now things became more clear. I had installed MVC 4 in my development machine and its  System,Web.MVC.dll needs webpages dll in 2.0.0.0. Some how that 2.0.0.0 version of webpages added to my MVC 3 project and took my half day.

1Location of fusionlogvw.exe - C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin
2HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fusion!EnableLog] (DWORD) to 1
3Location of System.Web.MVC.dll - C:\Program Files\Microsoft ASP.NET\ASP.NET MVC 4\Assemblies

Saturday, March 10, 2012

ASP.Net MVC 3 : Passing query string between view pages

There will be scenarios where we need to redirect back to a page after some operations in different controllers. Examples for such scenario are the login with registration. If you are developing a shopping site using ASP.Net MVC you need to allow users to browse through the site without authenticating. But when the user selects checkout you may need to show the authenticate page and redirect to the page from where the login started. Sometimes the users may not have the credentials in your site. In that case they may goto the registration page and upon validating the confirmation code you need to redirect them to the product page where they started the authentication process. It would be really difficult to do accomplish this without passing the query string among the pages. Lets see how we can do this.

Redirect to an action with query string
If you are in an action register belongs to AccountController and want to redirect to the confirm page.Try the below


this.RedirectToAction("confirm""account"new { returnUrl = returnUrl });

This will redirect to a page with URL as


/account/confirm?returnUrl=<value of returnUrl>

Showing action links with query string
You have a Login page and you need to redirect to the page from which this page is called after successful login you obviously use the query string. But how to handle if you need to provide the register link in the same login page where you need to redirect to the calling page after successful registration? \
Answer is simple you need to have the query string of login page propagated to the register link as well.Isn't it?

RAZOR page of login


RouteValueDictionary rvd = new RouteValueDictionary(ViewContext.RouteData.Values);
foreach (string key in Request.QueryString.Keys)
{
    rvd[key] = Request.QueryString[key].ToString();
}
@Html.ActionLink("[home]""index""home")
@: &nbsp;
@Html.ActionLink("[register]""register""account", rvd, null)

This will transfer the query string values in the url to the action link.

Tuesday, March 6, 2012

Moving ASP.Net Membership tables to production

Recently we were migrating our development database from local to Azure production db. The database has both application specific tables and aspnet membership tables.As usual the person who moved ignored all the development data by generating the table creation script alone with application specific seed data.

The system uses Azure ACS to have federated authentication from 3 identity providers. Google,Yahoo and our own custom identity provider using claims. The standard providers such as google and yahoo worked perfectly but the custom identity provider didn't. The error message shown was

The 'System.Web.Security.SqlMembershipProvider' requires a database schema compatible with schema version '1'. However, the current database schema is not compatible with this version. You may need to either install a compatible schema with aspnet_regsql.exe (available in the framework installation directory), or upgrade the provider to a newer version.

This clearly says we are missing something in the AspNet membership schema level. Not at all any seed data. But actually the issue is with seed data.ie we need to enable the features in the asp.net membership database. When we enable the features aspnet membership uses a table called aspnet_SchemaVersions to store the settings. This schema is confused with table schema in the error message. If you want to have more details you can try running the below query on a working aspnetdb.mdf.

SELECT feature,
       compatibleschemaversion,
       iscurrentversion
FROM   aspnet_schemaversions 


This is not our focus. Our focus is to get the issue resolved. Its simple we need to register the features into the asp net membership database which is ported to Azure. Open the SSMS and connect to Azure database and run the below queries.

EXEC [dbo].Aspnet_registerschemaversion
  N'Common',
  N'1',
  1,
  1

EXEC [dbo].Aspnet_registerschemaversion
  N'Role Manager',
  N'1',
  1,
  1

EXEC [dbo].Aspnet_registerschemaversion
  N'Membership',
  N'1',
  1,
  1 


If you are getting any error executing this sps make sure you have all the aspnet membership related stored procedures in the database. If not available run the membership related scripts which are available in your machine. You can find the scripts here in the location.

[InstallDrive]:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallCommon.sql

If you don't want to take chance of running the scripts one by one use the tool aspnet_regsql