Saturday, April 25, 2015

MVC & WebAPI - Model Binder

There are some specific cases in order to use model binder to MVC and WebAPI in same project.

Here i will explain step by step to implement MVC and WebAPI Model Binders

What is Model Binder?

In some cases, we should do common operations for all actions inside controller. So in that case we can add model binder and pass as parameter to actions. In below example UserModel class sent as Model Binder

public ActionResult Index([ModelBinder]UserModel model)

{
...
}

Implementing Model Binder for MVC

MVC uses different namespace such as System.Web.Mvc. So Model Binder class also should use the same.

Step 1:

Create UserModel class as required. Here we can add our required properties. In this example, i am going to display UserId and UserName

public class UserModel
    {
        public string UserId { get; set; }
        public string UserName { get; set; }

    }

Step 2:

Create custom ModelBinder class which can be implemented from System.Web.Mvc.IModelBinder as below. Here i created as partial for merging with WebAPI. If you dont need WebAPI then just have it as normal class


public partial class UserModelBinder : System.Web.Mvc.IModelBinder
    {
        public object BindModel(System.Web.Mvc.ControllerContext controllerContext, System.Web.Mvc.ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType != typeof(UserModel))
            {
                return null;
            }

            UserModel userModel = new UserModel();

            var userId = HttpContext.Current.User.Identity.GetUserId();

            if (!string.IsNullOrEmpty(userId))
            {
/// Create your custom logics to fill the other required details. In this example i can fill username
            }
            return userModel;
        }
    }

Step 3:

Register this Custom ModelBinder class into Global.asax.cs file

protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            //Model binder for MVC controller usermodel
            ModelBinders.Binders.Add(typeof(UserModel), new UserModelBinder());

        }

Step 4:

Use this custom model binder in action methods of MVC controller

public ActionResult Index([System.Web.Http.ModelBinding.ModelBinder]UserModel model)

{
...
 //Write your logic to do with UserModel class object
}


Thats all for MVC Model Binder.


Implementing Model Binder for WebAPI

WebAPI cannot be worked with MVC model binder. So we need to create differently. Step 1 to create UserModel is same. So i will go from Step 2

Step 2:

Create Custom Model Binder for WebAPI as follows. Here IModelBinder uses System.Web.Http.ModelBinding.

using Microsoft.AspNet.Identity;
using System.Web;
using System.Web.Http;
using System.Web.Http.ModelBinding;

public partial class UserModelBinder : IModelBinder
    {
        public bool BindModel(System.Web.Http.Controllers.HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType != typeof(UserModel))
            {
                return false;
            }

            UserModel userModel = new UserModel();

            var userId = HttpContext.Current.User.Identity.GetUserId();

            if (!string.IsNullOrEmpty(userId))
            {
               //Your logic to fill usermodel class and assign to binding context’s model
                bindingContext.Model = userModel;
                return true;
            }

            bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Error in model binding");
            return false;
        }

    }


Step 3:

Create ModelBinderProvider class as follows. It is going to be register with configuration. Here ModelBinderProvider uses namespace System.Web.Http.ModelBinding..

public class UserModelBinderProvider : ModelBinderProvider
    {
        private System.Type type;
        private UserModelBinder userModelBinder;

        public UserModelBinderProvider(System.Type type, UserModelBinder userModelBinder)
        {
            this.type = type;
            this.userModelBinder = userModelBinder;
        }

        public override IModelBinder GetBinder(HttpConfiguration configuration, System.Type modelType)
        {
            if (modelType == type)
            {
                return userModelBinder;
            }

            return null;
        }

    }


Step 4:

Register ModelBinderProvider in Global.asax.cs file under WebApiConfig register method

public static class WebApiConfig

    {
    public static void Register(HttpConfiguration config)
        {
         var provider = new UserModelBinderProvider(typeof(UserModel), new UserModelBinder());

         config.Services.Insert(typeof(ModelBinderProvider), 0, provider);


Step 5:

Use in APIController action methods as follows

[HttpGet]
        public string GetUserName([ModelBinder]UserModel model)
        {
              return model.UserName;
  }

Thats all for WebAPI Model Binder.


Wednesday, April 22, 2015

JavaScript - Validate Multiple Email Address

To validate multiple email address text use below JavaScript Function

Valid :
"balajisrmv@gmail.com"


function isValidEmailAddress(emailAddresses) {
    var splitter = ' ';
    var isValid = true;
    if (emailAddresses.indexOf(',') != -1)
        splitter = ',';
    else if (emailAddresses.indexOf(';') != -1)
        splitter = ';';

    var emailCollection = emailAddresses.split(splitter);

    if (emailCollection != null && emailCollection.length > 0) {
        emailCollection.forEach(function (emailAddress, index) {
            var pattern = new RegExp(/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i);
            if (isValid)
                isValid = pattern.test(emailAddress.trim());
        });
    }
    return isValid;

};


Monday, April 20, 2015

JavaScript - Format URL's protocol

Formatting URL with protocol is required when we binding it to anchor tag.

For example below code anchor tag will redirect to relative path because it doesn't have protocol such as Http, Https etc.,

Below code will check protocol exist or not and add in anchor tag

function formatHttp(urlPath) {
    var urlPattern = new RegExp("^(?:f|ht)tps?://");
    if (!urlPattern.test(urlPath)) {
        urlPath = "http://" + urlPath;
    }
    return urlPath;

}



Below example shows in angularJS

HTML:

<a ng-href="{{formatHttp(someurl)}}" href="#" target="_blank"> {{someurl}} </a>

someurl is anything like without protocol "www.google.com" or with protocol "http://www.google.com", "https://www.google.com" etc.,


AngularJS Controller:

$scope.formatHttp = function (url) {
        return formatHttp(url);
};


JS File:

function formatHttp(urlPath) {
    var urlPattern = new RegExp("^(?:f|ht)tps?://");
    if (!urlPattern.test(urlPath)) {
        urlPath = "http://" + urlPath;
    }
    return urlPath;
}

Tuesday, March 24, 2015

MVC - HTML5 Appcache for offline MVC Razor application

I would like to create application which support offline mode using HTML5 appcache. Before get into MVC offline mode, just read about HTML5 application cache 

Steps to create MVC HTML5 Offline application

1) Create new MVC Web project


2) For example purpose, i am using views created by default with MVC project. I am adding new action for Manifest file



2) On created Manifest.cshtml add code as required to do cache in browser



 - Here i removed layout 
 - Also set the content type as 'text/cache-manifest', so that browser will understand this file
 - CACHE MANIFEST is required syntax for manifest file
 - #version added with assembly file name and date. This will help to update cache automatically whenever new build happens
 - NETWORK is *
 - Under CACHE we can do whatever required. Here JS files, CSS files, Images, CSHTML pages, Other site resources added
 - FALLBACK added to logoff, if there is no connection for logoff then it will return error page instead
- Code
@{
    Layout = null;
}

@{
    HttpContext.Current.Response.ContentType = "text/cache-manifest";
}CACHE MANIFEST

    #version @System.Reflection.Assembly.GetExecutingAssembly().GetName().Version - @File.GetCreationTime(System.Reflection.Assembly.GetExecutingAssembly().Location).ToString("MM/DD/YYYY")

    NETWORK:
    *

    CACHE:
    # JS files
    @Url.Content("~/Scripts/jquery-1.10.2.min.js")

    # CSS files
    @Url.Content("~/Content/bootstrap.min.css")
    @Url.Content("~/Content/site.css")
   

    #Images
    @*@Url.Content("~/Content/images/logo.png")*@

    #CSHTMLPages
    @Url.Content("~/Home/Index")
    @Url.Content("~/Home/About")
    @Url.Content("~/Home/Contact")

    #Other Site Resources
    @Url.Content("http://fonts.googleapis.com/css?family=Roboto:00,400,700,300")

    FALLBACK:
    @Url.Content("~/Account/LogOff") @Url.Content("~/Errors/Default.html")




3) Include this manifest file path in _Layout.cshtml page html tag section


4) If you run application we will get error then we should know what is that



5) So we can add appcache.js file under script folder add following code to verify error 




- Code

var appCache = window.applicationCache;

appCache.addEventListener('cached', function (event) {
    console.log('All files downloaded!');
}, false);

// Checking for an update. Always the first event fired in the sequence.
appCache.addEventListener('checking', function (event) {
    console.log('Checking for manifest!');
}, false);

// An update was found. The browser is fetching resources.
appCache.addEventListener('downloading', function (event) {
    console.log('Downloading cache!');
}, false);

// The manifest returns 404 or 410, the download failed,
// or the manifest changed while the download was in progress.
appCache.addEventListener('error', function (event) {
    console.log('An error occurred!');
}, false);

// Fired after the first download of the manifest.
appCache.addEventListener('noupdate', function (event) {
    console.log('No cache updates!');
}, false);

// Fired if the manifest file returns a 404 or 410.
// This results in the application cache being deleted.
appCache.addEventListener('obsolete', function (event) {
    console.log('Manifest cannot be found!');
}, false);

// Fired for each resource listed in the manifest as it is being fetched.
appCache.addEventListener('progress', function (e) {
    console.log('File downloaded!');
}, false);


// Fired when the manifest resources have been newly redownloaded.
appCache.addEventListener('updateready', function (e) {
    console.log('New cache available!');
    //appCache.swapCache();
}, false);



6) Include appcache.js in _layout.cshtml


7) If we run application and check in console of browser, we can see logs of this appcache and thats it.