Saturday, December 21, 2013

Custom Model Validation Provider for enabling ASP.NET MVC 3 client side validation.


Implementing Custom Model Validation Provider to enable client side MVC 3 validation 

The Validation framework of ASP.NET MVC 3 is designed for extensibility and customization.  It supports validation model using attributes, or by implementing IValidatableObject or unobtrusive javascript based client side validation. It supports both property based or model based validation.

But, again ASP.Net MVC 3 assumes your solution has view models defined in a simple, flat & non hierarchical fashion to make things work. Sometimes, in applications we need to apply or perform validation rather in different ways to comply with existing legacy code, architectural style and culture.

Update: Following solution is applicable to ASP.NET MVC 3 FRAMEWORK ON VS 2010

One last word!! we assume you have in place all necessary jquery /javascript /css files for the MVC client side validation to work

Use case for Implementing Custom ModelValidatorProvider:

In my case, I did not have the pleasure to have view models exclusively defined for the mvc project.

Domain model classes are directly applied to MVC views. I cannot litter domain classes with validation attributes. They are shared components. They derive from some base classes. So, I couldn't really force annotation based validation working directly using this convoluted & hierarchical model classes as shown below:





















Binding JuniorEngineer model to mvc view and enabling property level client side validation declaratively using attributes/annotations seemed difficult for me.

Inject the validation attributes at Run time on the model:

So, we decided to inject validation attributes on model at the run time dynamically. In this case, we have to go for implementing custom validation solution which means we have to create a custom ModelValidatorProvider that allows to inject validation rules on the fly into the model.

Implementing Custom DataAnnotationsModelValidatorProvider:

MVC provides hook to plug in your custom implementation of ModelValidatorProvider. The purpose is to bind validation attributes dynamically to model to enable client side validation.

 public class JuniorEmployeeModelValidator : DataAnnotationsModelValidatorProvider
    {
        protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
        {
            if (metadata.ContainerType != typeof(JuniorEngineer))
                return base.GetValidators(metadata, context, attributes);
            //enable client side validation for name prop for junior engineer model. Name property is inherited from base abstract employee class.
            if (!string.IsNullOrWhiteSpace(metadata.PropertyName) && metadata.PropertyName == "Name")
            {
                //injecting required attribute to name /salary properties.
                attributes = new List<Attribute>()
                {
                    new RequiredAttribute()
                    {
                        ErrorMessage = "Hey babe, we just need a human name."
                    }
                };
            }
            if (!string.IsNullOrWhiteSpace(metadata.PropertyName) && metadata.PropertyName == "Salary")
            {
                attributes = new List<Attribute>()
                {
                    new RequiredAttribute()
                    {
                        ErrorMessage = "No one works for free!! Give him some money."
                    }
                };
            }
            return base.GetValidators(metadata, context, attributes);
        }

      
    }




Register in Global.asax:
Any customization or extension should be registered. Or You get no cookie!!












Saturday, December 14, 2013

Generic TryParse handler for generic .Net Lists



Following C# code sample is a Generic TryParse handler for generic value type 
lists in .Net.  Any character delimited list can be split and use safe TryParse against split list 
to ensure you have valid data.




using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericTryParsehandler
{
    /// <summary>
    /// Generic TryParsehandler to split and parse generic value type lists.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value"></param>
    /// <param name="result"></param>
    /// <returns></returns>
    public delegate bool TryParseHandler<T>(string value, out T result);
    class Program
    {
        static void Main(string[] args)
        {
            var semiColonDelimitedDateInput = "01/01/2001;2/02/2012;05/31/2013;05/05/1992";
            var commaDelimitedIntInput = "3,4,5,6";
            var intresult = commaDelimitedIntInput.TryParseList<int>(new[] { ',' }, int.TryParse);
            var dateresult = semiColonDelimitedDateInput.TryParseList<DateTime>(new[] { ';' }, DateTime.TryParse);
            
            if (dateresult.Count > 0)
            {
                foreach (var element in dateresult)
                {
                    Console.WriteLine(element);
                }
            }
            else
            {
                Console.WriteLine("Your semiColonDelimitedDateInput cannot be parsed.");
            }
            Console.WriteLine("*******************************************************************");
            if (intresult.Count > 0)
            {
                foreach (var element in intresult)
                {
                    Console.WriteLine(element);
                }
            }
            else
            {
                Console.WriteLine("Your commaDelimitedIntInput cannot be parsed.");
            }
            Console.ReadLine();
        }
    }


    /// <summary>
    /// 
    /// </summary>

    public static class ExtensionMethods
{
        /// <summary>
        /// Generic handler to split and TryParse each item in the list. Handler supports value types.. 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="separator"></param>
        /// <param name="handler"></param>
        /// <returns></returns>
    public static List<T> TryParseList<T>(this string source, char[] separator, TryParseHandler<T> handler)
        where T : struct

    {
        var splitList = new List<T>();
        if (string.IsNullOrEmpty(source)) return splitList;

        var parsedString = source.Split(separator, StringSplitOptions.RemoveEmptyEntries).ToList();

        parsedString.ForEach(x =>
        {
            T result;
            if (handler(x, out result))
            {
                splitList.Add(result);
            }
        });

        return splitList.Count == parsedString.Count ? splitList : new List<T>();
    }
}
}

10 Practical ASP.Net MVC 4 Interview Questions



10  Practical ASP.Net MVC 4 Interview Questions:


1)  Do you think following is valid route definition for ASP.NET MVC solution?






Answer: YES. Variable length routes are valid. This route will match any URL, irrespective of number of placeholders it contains.

_________________________________________________________________________________

2)  Is the following route definition a valid one? If so please explain? 




Answer: This route is constrained using Regular expression. Only numeric values are accepted for the id parameter 

_________________________________________________________________

3)  What is the primary difference between these two Html Helpers for Validation?





Answer: Latter displays only model level validation errors NOT the property level errors. Former displays both model and property level errors

__________________________________________________________

4)   Does this Action Method compiles and redirects the user to another view?

Answer: YES. It is a valid redirect.

_______________________________________________________________________

5) What is the difference between these Html Helpers?



Answer: Latter is destroyed after you read it while former preserves it for next request.

___________________________________________________________

6) What is the difference between two techniques? Which one to prefer?











Answer:  They are one and same. We prefer second approach. It is built in helper method for controller to return 404 code

________________________________________________________________________

7) Can you override MVC convention and define controller name without ending in "Controller" as shown below?







Answer: YES. We can override default MVC convention to define controller name with out ending in "Controller". But, we have to implement our own custom controller factory.

________________________________________________________________________

8) What the result of this view? Will it be a runtime exception or just works fine?








Answer: Session Disabled controller has no impact on ViewBag. View Just renders fine with message: "My Controller has no session".

________________________________________________________________________

9) What is difference between @Url.Action and @Url.RouteUrl?











Answer: Semantically, they are same. 
  •  Url.RouteUrl allows you to specify a particular route by name. 
  • Url.Action will simply pick the first route that matches the criteria.
________________________________________________________________________________

10) List out filters available in MVC world if you can please specify their order of precedence?

Answer: Exception filter can kick in at any time.
  1.  Authorization filter
  2. Action filter
  3. Result filter
  4. Exception filter

Sunday, December 8, 2013

Automated asp.net web application testing using Selenium


ASP.Net Web Application Integration testing using Selenium 2.0


Selenium primarily used for automating web applications for testing purposes. You can create browser based regression tests using Selenium WebDriver. 

Selenium WebDriver provides a concise programming interface. It drives the browser much more effectively. Selenium WebDriver makes direct calls to browser using each browser's native support for automation. 

This articles deals with running tests against the application all running on the same machine. WebDriver will run the browser directly. *This article doesn't cover test distribution over multiple machine*. The article covers running tests for IE browser.

Setup:

To create and run Selenium tests using IE or chrome browser, we need to set up and reference few things before we hit the ground running.

Note: Following instructions are specific to IE browser.

DriverServer Setup:

1) Based on your computer architecture, please download 32bit or 64 bit IEDriverServer from here.
2) UnZip the contents of download and you can run the Driver in the two ways
                       a) Designate Driver.exe as part of your Test project test settings as deployable item so it                                    copied to test project output every time you run the tests
                        b) Instead, set the IEDriverServer.Exe path as part of PATH environment variable.


 3) The point is IEDriverServer should be running when executing tests using selenium

Assembly References in VS2012:

1) Please download the latest version of Selenium-dotnet-(version).zip which includes .Net bindings and            WebDriver programming API from here
2) UnZip the contents of download and reference the "WebDriver.dll" based on your target .net Framework      to your testing project as shown below.


3) You're all set now

Running the tests:

Following are the simple tests designed for a pseudo website with two pages. First test automates the login function and second test automates user details on the home page.

When you run the tests, you'll see IEDriverServer console running up and your sample site being run by Selenium in the web browser as shown below:


    first test results


 second test results

Code Sample:


using System;
using System.ComponentModel;
using System.Data;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.IE;


namespace SeleniumAutomatedTests
{
    [TestClass]
    public class SeleniumUnitTests
    {
        private static InternetExplorerDriver _webDriver;

        [TestMethod]
        public void TestSiteLoginFunction()
        {
            //initialize internet explorer driver and you can set up options for driver 
            _webDriver = new InternetExplorerDriver(new InternetExplorerOptions()
            {
                InitialBrowserUrl = "http://localhost/TestSite/Login.aspx",
                
            });
            //find the desired elements by id, css class or name, xpath 
            _webDriver.FindElement((By.Id("userNameTxtBox"))).SendKeys("Selenium");
            _webDriver.FindElement(By.Id("passwordTxtBox")).SendKeys("selenium");

            var logInButton = _webDriver.FindElement(By.Id("signInBtn"));
            //simulating the button click
            logInButton.Click();

            //wait for 5 seconds for the page to load
            _webDriver.Manage().Timeouts().ImplicitlyWait(new TimeSpan(0, 0, 5));

            var welcomeLabel = _webDriver.FindElement(By.Id("WelcomeLabel"));
            //interface to execute javascript code on the host page
            var js = (IJavaScriptExecutor) _webDriver;
            //you can also execute on fly javascript code or predefined javascript functions attached to host page.
            js.ExecuteScript("alert('you successfully signed in.')");
            //finally, some asserting
            Assert.IsNotNull(welcomeLabel.Text);
           
        }

        [TestMethod]
        public void TestHomePageSubmitFunction()
        {
            _webDriver = new InternetExplorerDriver();
            _webDriver.Navigate().GoToUrl("http://localhost/TestSite/Home.aspx");
            _webDriver.FindElement((By.Id("ageTxtBox"))).SendKeys("29");
            _webDriver.FindElement(By.Id("cityTxtBox")).SendKeys("Los Angeles");
            //submitting the form using selenium
            var form = _webDriver.FindElement(By.Id("detailsForm"));
           form.Submit();

            _webDriver.Manage().Timeouts().ImplicitlyWait(new TimeSpan(0, 0, 5));
            var welcomeLabel = _webDriver.FindElement(By.Id("WelcomeLabel"));
            Assert.IsTrue(welcomeLabel.Text.Contains("Los Angeles") && welcomeLabel.Text.Contains("29"));
        }


    }

   
}

Hope this helps..

Thursday, November 21, 2013

C# code snippet to Consume Google StreetViewImage API




The Google Street View Image API lets you embed a static(non-interactive) Street View panorama or thumbnail into your web page, without the use of JavaScript. The viewport is defined with URL parameters sent through a standard HTTP request, and is returned as a static image.

Following is c# sample to connect with Google StreetViewImage API (Non-interactive, static street view image) which doesn't involve any javascript. Code utilizes simple WebClient class over HttpWebRequest class and also provides asynchronous operations.

Both classes are from System.Net namespace. WebClient is a nice helper class that provides simpler way to download resource from web like files, images in synchronous or asynchronous fashion. If you need more fine grained control over web requests and responses, better use HttpWebRequest/HttpWebResponse.

WebClient.DownloadDataTaskAsync - Downloads the resource as a Byte array from the URI specified as an asynchronous operation. These methods do not block the calling thread.

BTW, You might ask why did I use Task.wait().. In my case, my task is synchronous in nature. it will block synchronously until the task is complete. Instead, if you want to make it truly asynchronous, make the method async and use await keyword to wait asynchronously while keeping your calling thread unblocked.

All the required/optional parameters are documented below in comments.

Following is the typical HTTP request we need to consume street view image

http://maps.googleapis.com/maps/api/streetview?size=400x400&location=40.720032,%20-73.988354&fov=90&heading=235&pitch=10&sensor=false

/// location can be either text string (such as "Nuevo San Juan Parangaricutiro" or lat/lng values(40.457375,-80.009353)

///  specifies the output size of the image in pixels. Size is specified as {width} x {height} 

/// - for ex: size=600x400 returns an image 600 pixels wide, and 400 high.

/// Street View images can be returned in any size up to 640 by 640 pixels.

/// /*******OPTIONAL PARAMETERS: ************************/

/// ************************************************************************************************************

/// 1) HEADING

/// Indicates the compass heading of the camera. 

/// Accepted values are from 0 to 360 (both values indicating North, with 90 indicating East, and 180 South). 

/// If no heading is specified, a value will be calculated that directs the camera towards the specified location, 

/// from the point at which the closest photograph was taken.

/// *************************************************************************************************************

/// 2)FOV - field of view

/// fov (default is 90) determines the horizontal field of view of the image. The field of view is expressed in degrees, 

/// with a maximum allowed value of 120. When dealing with a fixed-size viewport, as with a Street View image of a set size, 

/// field of view in essence represents zoom, with smaller numbers indicating a higher level of zoom.

/// *************************************************************************************************************

/// 3)PITCH - (default is 0) specifies the up or down angle of the camera relative to the Street View vehicle. This is often, 

/// but not always, flat horizontal. Positive values angle the camera up (with 90 degrees indicating straight up); 

/// negative values angle the camera down (with -90 indicating straight down).

/// *****************************************************************************************************************

/// 4)KEY (optional) identifies your application for quota purposes, and enables reports in the APIs Console. 

/// ***********************************************************************************************************************

///5)SENSOR - indicates whether or not the request came from a device using a location sensor (e.g. a GPS) to determine the location sent in this request. This value must be either true or false.

/// 

public byte[] GetStreetViewImage(string location, string size =null)

{

try

{

var streetViewImageServiceUrl = "http://maps.googleapis.com/maps/api/streetview?size=400x400&location=40.720032,%20-73.988354&fov=90&heading=235&pitch=10&sensor=false"

if (string.IsNullOrEmpty(location))

 {

throw new ArgumentNullException(@"location argument is missing.");

}



var imageUrl  = !string.IsNullOrEmpty(size) ?

string.Format("{0}&size={1}", string.Format("{0}&location={1}", streetViewImageServiceUrl, location), size) :

string.Format("{0}&size={1}", string.Format("{0}&location={1}", streetViewImageServiceUrl, location), StreetViewImageSize);
using (var cli = new WebClient())

{

var task = cli.DownloadDataTaskAsync(imageUrl);

task.Wait();

return task.Result;

}



 }

catch {

}

}