Archive for the ‘ASP.Net MVC’ Category

AngularJS provides powerful data binding features. In many scenarios, we would need to change DOM elements’ status depending on user actions or data updates in controllers/ the back end.

Few simple examples:

  • The “continue” button is enabled only if user clicks on “agree to terms and conditions” check-box.
  • Show a particular message on the View, if the ‘flag’ value is true which is received from an external server/database.

There are many other different scenarios, where we would need data-binding.

Bindings are of two types:

  • One-way ($scope → View)
  • Two-way ($scope → View and View → $scope)

By default, the bindings are one-way. For example if we use ‘ng-bind’ then it is one-way, whereas ‘ng-model’ is a two-way binding.

Here, we will take a very simple example; However it covers most of the scenarios. And in the end, I would add couple of points to debug issues with data binding. In our example, we add a toggle button, a Text Box and a text area. At any point of time, either Text box or Text area is visible. When user starts typing in text box and then if he clicks on toggle button, Text box will be hidden and Text area will be visible with already typed text, so that user can continue typing. Here is the code for our view. Defined a button, an input and textarea. To control the Text Box and Text Area’s visibility, we are using ‘ng-show’. If ng-show value is evaluated as true then control will be visible, otherwise it will be collapsed. Input and textarea are bounded with myText property.

<div ng-app="myTestApp">
    <div ng-controller="nameController">
        <button ng-click="onBttnClick()">Toggle</button>
        <br/>
        <br/>
        <br/>
        <input ng-show="isVisible"  ng-model="myText"> </input>
        <textarea ng-show="!isVisible" ng-model= "myText"></textarea>
    </div>
</div>

Below is the code for AngularJs controller. myTestApp is added as a new module. Defined a controller with name ‘nameController’. Inside the controller, we have defined two variables isVisible and myText. onBttnClick method works as toggle function. The method has simple logic for inverting the flag value.

var myTestApp= angular.module(myTestApp, []);

myTestApp.controller('nameController', ['$scope',  function nameController($scope){
    $scope.isVisible = true;
    $scope.myText = "";

    $scope.onBttnClick = function onBttnClick(){
        $scope.isVisible = !$scope.isVisible;
    }
}]);

Few points to note for resolving binding issues:

Sometimes, though the variables are updated in the controller, the changes won’t be reflected on View. There could be multiple reasons for that.
It could be an issue with nested directives (parent child) hierarchy in the DOM structure. In this case angularjs creates parent/child scopes.

<div ng-if=”isVisible==’true’”>
		<input ng-model=”myText” />
</div>

To resolve this issue, observe the value of $scope.$parent variable and look at $watchers. Then appropriate $scope can be used in the view.

Other alternate for this is to use $rootScope which is global.
$rootScope.isVisible = true;

In the View, use ng-show=”$root.IsVisible”.

Other reasons could be,- single controller may be used in multiple places on the view. Hence different controller instances are created.

Introduction: The most common scenario in any application development (desktop/web/mobile) is to build Authentication/Authorization. In Role based authorization, we define set of roles and each role is authorized to do some actions.  It tightly couples application security with business logic.  Number of roles would be needed if there are complex rules depending on business need. The alternative is Claims based Authorization.  In this method we define claims as Resource and Operation pairs.   Each user is assigned different claims and based on claims, we authorize user actions. Creation of Claims: When a new user is created, set of claims would be added to the user. WIF comes with a table called AspNetUserClaims for storing claims. UserId column is a foreign key to Id column in AspNetUsers table. In a typical application, claims can be created in following ways:

  • Populated using back end jobs based on details from Organization’s internal database/sources
  • Inserted inside application during/after user Registration/Signup process.

The creation of claims is a one time job and may be updated based on changes in business rules. Claim Example:

ClaimType: "http://abc.com/identity/claims/Account"

ClaimValue: "Update"

Loading Claims: Now, we have the claims saved in database for each user.   When a user logs into the system, we have to read/load those claims and associate them with User Identity.  We would perform this by implementing a custom http module and subscribe to PostAuthenticationRequest event in Init method.

public class CustomClaimsBasedAuthorization : IHttpModule, IDisposable
{
	public void Init(HttpApplication context)
	{
		context.PostAuthenticateRequest += PostAuthenticateRequestEvent;
	}

	void PostAuthenticateRequestEvent(object sender, EventArgs e)
	{
		var sessionAuthModule = FederatedAuthentication.SessionAuthenticationModule;
		if (sessionAuthModule.ContainsSessionTokenCookie(HttpContext.Current.Request.Cookies) &&
		sessionAuthModule.ContextSessionSecurityToken != null)
		{
			var ck = sessionAuthModule.ContextSessionSecurityToken;
			sessionAuthModule.AuthenticateSessionSecurityToken(ck, false);
		}
		else
		if (HttpContext.Current != null && HttpContext.Current.User != null && HttpContext.Current.User.Identity.IsAuthenticated)
		{
			ClaimsPrincipal cp = CreateClaimsedBasedPrincipal();

			var sstoken = new SessionSecurityToken(cp);
			sessionAuthModule.WriteSessionTokenToCookie(sstoken);
		}
	}

        private static ClaimsPrincipal CreateClaimsedBasedPrincipal()
	{
		string userName = Thread.CurrentPrincipal.Identity.Name;
                //Load claims from Database/Service
		var claims = LoadClaims(userName);

		var cp = new RmsClaimsPrincipal(userName, claims);

		Thread.CurrentPrincipal = cp;
		if (HttpContext.Current != null)
		{
			HttpContext.Current.User = cp;
		}
		return cp;
	}
}

internal sealed class CustomClaimsPrincipal : ClaimsPrincipal
{
	public CustomClaimsPrincipal (string userName, IEnumerable<RmsUserClaim> userRoles)
	{
		var gIdentity = new GenericIdentity(userName, "RMS custom authentication");
		var cIdentity = new ClaimsIdentity(gIdentity);

		foreach (var claim in userRoles)
		{
			cIdentity.AddClaim(new Claim(claim.ClaimType, claim.ClaimValue));
		}
		AddIdentity(cIdentity);
	}
}

In the above example, we create ClaimsPrincipal and add claims to the Identity. However, the ClaimsPrincipal creation process will be executed for each and every request to the web application which could be potential performance issue.  To improve the performance, .Net Framework 4.5 supports writing ClaimsPrincipal with all of its claims to a Cookie.  To enable this, following web.config changes are required. Add following config section:

<configSections>
  <section name="system.identityModel.services"
   type="System.IdentityModel.Services.Configuration.
                SystemIdentityModelServicesSection,
 System.IdentityModel.Services, Version=4.0.0.0,
 Culture=neutral, PublicKeyToken=B77A5C561934E089" />

Add following Config elements to support creation of Cookie

<system.identityModel.services>
  <federationConfiguration>
    <cookieHandler requireSsl="false" />
  </federationConfiguration>
</system.identityModel.services>

Configure module that handles reading and writing the cookie.

<modules>
  <add name="SessionAuth"
       type="System.IdentityModel.Services.SessionAuthenticationModule,
             System.IdentityModel.Services, Version=4.0.0.0,
             Culture=neutral, PublicKeyToken=b77a5c561934e089"/>

Restricting actions based on claims: We have claims in place and we would want to restrict controller actions based on claims. For this, we could apply PricipalPermissionAttribute or ClaimsPrincipalPermissionAttribute. For example:

[ClaimsPrincipalPermission(SecurityAction.Demand, Resource = "Account", Operation = "Update")]
public void UpdateDetails()
{
//Update logic
}

These attributes serve the purpose, as we could specify required resource and type of action. However, these attributes are invoked by CLR. If the role check fails it throws a Securityexception. Instead we want to show login page so that user could login to appropriate role. Alternately, we could use Authorize attribute. However it doesn’t support Resource/Action out of box. So, we want to write our own custom attribute by extending AuthorizeAttirbute.

internal class CustomAuthorizeAttribute : AuthorizeAttribute
{
	public string Resource { get; set; }

	public string Operation { get; set; }

	protected override bool AuthorizeCore(HttpContextBase httpContext)
	{
		var cPrincipal = (ClaimsPrincipal)httpContext.User;
		var resourceClaim = string.Format("{0}/{1}", "http://abc.com/identity/claims", Resource);
		return cPrincipal != null && cPrincipal.HasClaim(resourceClaim, Operation);
	}
}

Once we define custom attribute, it could be used as below:

[CustomAuthorize(Resource = "Account", Operation = "Update")]
public void UpdateDetails()
{
//Update logic
}

Please provide your valuable feedback/comments/suggestions that would help me improve my writing.

Introduction:

In this article I would like to discuss about displaying a modal dialog or popup using Kendo UI Window.  There are tons of articles on net on similar topic, however here I would like to do it using ASP.Net MVC so we use MVC partial view to render contents on Kendo Window.  We also use Kendo Grid to populate the data dynamically.   We would also cover how to refresh the Grid data using AJAX calls and how to pass a MVC model from Java script/client to MVC server controller action.

Here are the things we would like to do for the demo purposes:

Displaying a search button on a view.  Upon clicking on search button, a modal dialog will be displayed with two input fields for First and Last Names.  When user clicks on Search button after entering the data in the text boxes, we would display matching records in a grid on the same window.

Capture3

Install Kendo UI

First step to install Kendo UI.  Follow the steps as mentioned in below article:

http://docs.telerik.com/kendo-ui/aspnet-mvc/asp-net-mvc-5

Note: The above instructions talk about installing Kendo UI separately and then integrating it with our application.  If you had installed Kendo UI code using Nuget package and then used Telerik upgrade wizard visual studio extension to upgrade to professional version then you may have to do couple of changes in BundleConfig.cs to work Kendo UI properly.

bundles.Add(new ScriptBundle("~/bundles/kendo").Include(
			"~/Scripts/kendo/2014.3.1119/kendo.all.min.js",
				// "~/Scripts/kendo/kendo.timezones.min.js", // uncomment if using the Scheduler
			"~/Scripts/kendo/2014.3.1119/kendo.aspnetmvc.min.js"));

bundles.Add(new StyleBundle("~/Content/kendo/2014.3.1119/css").Include(
			"~/Content/kendo/2014.3.1119/kendo.common-bootstrap.min.css",
			"~/Content/kendo/2014.3.1119/kendo.bootstrap.min.css"));

Observe that there is a version number folder2014.3.11 in the path.  This is basically the kendo UI version you had installed.  Make sure to add correct version number and path.

Kendo Window

We use Kendo HtmlHelper extension for creating the modal window.  The kendo window is assigned with a name “window” and with a caption “Search Names”.   We use LoadContentFrom method to load the contents by calling MVC controller action.  The first parameter is action name and the second one is controller name.  We also set Modal as true so that the dialog would be a modal dialog.  HtmlAttributes method is used for styling purposes.   An OnClose event handler is attached to the window.   Here is the code snippet:

<div id="UserForm">
    <span id="SearchButton" class="k-button">Search Names</span>
</div>

<div >
    @(Html.Kendo().Window()
          .Name("window")
          .Title("Search Names")
          .LoadContentFrom("Search", "Home")
          .Draggable()
          .Actions(actions => actions.Close())
          .Modal(true).Visible(false)
          .HtmlAttributes(new { style = "margin: 10px" })
          .Events(ev => ev.Close("onClose"))
          )
</div>

We also need to add a reference to Kendo MVC UI.

@using Kendo.Mvc.UI

In java script, subscribe to search button click event handler.   Inside click method open kendo window and place it in the center.   We have also added kendoValidation so that we can validate model state before opening modal window.

<script>
    $(document).ready(function () {
        var validator = $("#UserForm").kendoValidator().data("kendoValidator");

        $("#SearchButton").bind("click", function () {

            if (validator.validate()) {
                $("#window").data("kendoWindow").open().center(true);
            }
        });
    });
</script>

In the Controller, add an action for Search functionality.  Define a class called UserDetails with First Name and Last Name fields.  Add a partial view with UserDetails model and select “Create Scaffold template” option to display First Name and Last Name fields.

[HttpGet]
public ActionResult Search()
{
	return PartialView();
}

public class UserDetails
{
	public string FirstName { get; set; }

	public string LastName { get; set; }
}

The Serach partial view code looks like below:

@using ExchangeAdda.Models
@model ExchangeAdda.Models.UserDetails

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>UserDetails</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.FirstName, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.LastName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.LastName, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input id ="FindBtn" type="submit" value="Search" class="btn btn-default" />
            </div>
        </div>
    </div>
}

Kendo Grid

Now we need add a kendo grid to the Search view which displays the search results.  Bind the Grid to UserDetails model and add columns for First and Last names.

<div>
    <div>
        @(Html.Kendo().Grid<UserDetails>()
              .Name("AssociateSearch")
              .HtmlAttributes(new { style = "max-height: 50px; border:0px" })
              .Columns(columns =>
              {
                  columns.Bound(x => x.FirstName);
                  columns.Bound(x => x.LastName);
              })
              .Selectable()
              .Resizable(resizing => resizing.Columns(true))
              .DataSource(dataSource => dataSource
                  .Ajax())
        )

    </div>
</div>

Now, add a click event in java script to make an AJAX request to load the data.  Here, we are creating client side model which is equal to server side UserDetails model.  The properties are populated using document getElementById method.  Specify the action name as Url.  Make sure to add content type as application/json.  The data parameter is assigned with earlier created model.  Add an event handler for success and refresh grid data upon success.

<script>
    $('#FindBtn').click(function (e) {
        e.preventDefault();
        var UserDetails =
        {
            "FirstName": document.getElementById('FirstName').value,
            "LastName": document.getElementById('LastName').value,
        };
        $.ajax({
            url: "SearchJsonRequest",
            type: 'POST',
            contentType: "application/json;charset=utf-8",
            data: JSON.stringify(UserDetails),
            dataType: "json",
            success: function (data) {
                var grid = $('#AssociateSearch').getKendoGrid();
                grid.dataSource.data(data);
                grid.refresh();
            }
        });
        return false;
    });
</script>

The final step is to add an action in the controller for search functionality. I have added some dummy data to create a collection and return to the client for demo purpose. In reality there might be another service/BLL/DB call to fetch data based on search criteria.  The important thing to note is the method should return JsonResult.  The method accepts the UserDetails model data which is a better way for passing data from client to server.

[HttpPost]
public JsonResult SearchJsonRequest(UserDetails details)
{
	//Implement your search logic here

	var list = new List<UserDetails>()
	{
		new UserDetails{ FirstName = "Test 1 First Name", LastName = "Test 1 Last Name" },
		new UserDetails{ FirstName = "Test 2 First Name", LastName = "Test 2 Last Name" },
		new UserDetails{ FirstName = "Test 3 First Name", LastName = "Test 3 Last Name" },
	};

	return Json(list);
}