Using Display/DisplayName attributes in MVC

Introduction

In this article I will post a small example of using Display and DisplayName attribute. Today when I saw a junior developer struggling with DisplayName attribute I thought it to blog it for others also.

What is Display/DisplayName Attribute?

It defines the text we want to show on UI as form fields and Validation Messages.

Why we need Display/DisplayName Attribute?

We will discuss this with an example. Lets assume we have a model with two properties FirstName and ListBoxValue.

public class Employee
{
public string FirstName { get; set; }
public string ListBoxValue { get; set; }
}

This is how our view looks like:

razorview

Now when this model will be rendered on the view as seen below, looks a bit ugly and unformated.

View

For such scenarios only we have two built in attributes: Display and DisplayName. Using these attributes we can control how the text is rendered on the view. As we can see in the below code snippet, I have added Display Attribute on property named “FirstName” and DisplayName attribute on property named ListBoxValue with the text which I want to be rendered on the view in place of property names.

public class Employee
{
[Display(Name = “First Name”)]
public string FirstName { get; set; }
[DisplayName(“List Box Value”)]
public string ListBoxValue { get; set; }
}

After applying the attributes to our property this is how our View is rendered, which looks good.

changedview

Suppose, If two different views are sharing the same model (for instance, maybe one is for mobile output and one is regular), it could be nice to have the string reside in a single place: as metadata on the ViewModel.

Additionally, if you had an inherited version of the model that necessitated a different display, it could be useful. For instance:

public class BaseViewModel
{
[Display(Name = “Basic Name”)]
public virtual string FirstName { get; set; }
}

public class Employee : BaseViewModel
{
[Display(Name = “First Name”)]
public string FirstName;
[DisplayName(“List Box Value”)]
public string ListBoxValue { get; set; }
}

 Difference between Display and DisplayName

Display attribute should be preferred over DisplayName attribute. The former one comes form DataAnnotations namespace and exposes more properties than the later one, ie. ShortName, Prompt, GroupName, Order, Description, which are used by DataAnnotationsMetadataProvider.

Most importantly, DisplayName accepts only literals, while Display accepts resource type and key, which can be used to provide translations using separate resource files (resx).

Point to remember

The correct way of using DisplayName is on properties with getters and setters because by design MVC Binding applies to properties, not fields.

[Display(Name = “First Name”)]
public string FirstName;

Hope this helps.

Advertisements

Select only one checkbox

Today I will detail a situation faced by one of my friend. I would call it a software design disaster, how? I will explain. He has to develop a page with two grids similar to below image. Capture

The functionality required was very unorthodox. In the grid (captioned Vertically), the user should be allowed to select only one Checkbox per year and in second grid (captioned Horizontally), the user should be allowed to select only one Checkbox per criteria/per row. Although both these situations could have been handled by using Radio Buttons, but he was adamant that he want it to be a Checkbox only, to which i suggested him to use radio button and by using CSS make it look like a Checkbox. But he wanted it to be a Checkbox only.

For him i wrote a JQuery function to get the desired results, which i am sharing.

$(document).ready(function () {
$(‘:checkbox’).on(‘change’,function(){
var th = $(this),
name = th.attr(‘name’);
if(th.is(‘:checked’)){
$(‘:checkbox[name=”‘ + name + ‘”]’).not(th).prop(‘checked’,false);
}
});
});

The above function is very simple and works on name attribute. On click of a Checkbox it UnSelect all Checkboxes with the same name except the current Checkbox.

jquery

Dynamic query for Parent/Child

Often new developers gets tasks to create dynamic menus from database and the first thing they stuck is how to query the data from database.  I am not writing anything new; its just I want to write assuming it will help somebody someday.

To begin with I will create a new SQL Table first. The below table consists of four columns:

  1. MenuId
  2. MenuName
  3. Description
  4. ParentId

GO

/****** Object: Table [dbo].[tblMenu] Script Date: 03/09/2016 11:18:44 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[tblMenu](
[MenuID] [int] IDENTITY(1,1) NOT NULL,
[MenuName] [varchar](50) NULL,
[Description] [varchar](255) NULL,
[ParentID] [int] NULL,
CONSTRAINT [PK_Menu] PRIMARY KEY CLUSTERED
(
[MenuID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

I inserted somesample data using below query.

INSERT INTO [tblMenu]
Select ‘Product’,’A List of Products’, NULL
UNION ALL Select ‘Applications’,’Appliations’,NULL
UNION ALL Select ‘Document’,’Documentation’, NULL
UNION ALL Select ‘Support’,’Support’, NULL
UNION ALL Select ‘Download’,’Download’, NULL
UNION ALL Select ‘Background’,’ProductBackground’, 1
UNION ALL Select ‘Details’,’Product Details’, 1
UNION ALL Select ‘Mobile Device’,’Mobile DeviceApplications’, 2
UNION ALL Select ‘Portal’,’Portal Applications’,2
UNION ALL Select ‘Web Applicaitons’,’WebApplications’, 2
UNION ALL Select ‘Demo’,’Demo Applicaitons’, 2
UNION ALL Select ‘Performance Tests’,’ApplicationPerformance Tests’, 2
UNION ALL Select ‘Tutorials’,’TutorialDocumentation’, 3
UNION ALL Select ‘Programmers’,’ProgrammDocumentation’, 3
UNION ALL Select ‘FAQ’,’Frequently AskedQuestions’, 4
UNION ALL Select ‘Forum’,’Forum’, 4
UNION ALL Select ‘Contact Us’,’Contact Us’, 4
UNION ALL Select ‘InternetRestrictions’,’Internet Restrictions’, 6
UNION ALL Select ‘Speed Solution’,’Speed Solutions’,6
UNION ALL Select ‘Application Center Test’,’Application Center Test Results’, 12
UNION ALL Select ‘Modem Results’,’Modem Results’,12

After inserting the data this is how my data looks like

Sql Data

Then the final query to get the desired output.

SELECT
parent.MenuId ParentId,
parent.MenuName Menu,
child.MenuId ChildId,
child.MenuName as SubMenu
FROM dbo.tblMenu parent
INNER JOIN tblMenu child ON parent.MenuId = child.ParentId;

This is how data looks now.

final query

Hope it will help somebody.

 

Async/Await with Linq Extensions

We all have read and worked on Async/Await and that too many a times. I might not be describing something highly technical but would like to share my learning.

Today while working on one of my WPF application I encountered a strange, rather an unexpected, issue with async/await and Linq extensions where Async/Await didn’t worked with Linq extensions. Let us  try and understand the whole scenario in detail.

I am having a DataModel class in my Data Layer and by using the below asynchronous method I am  fetching data from database and populating a generic collection. It works on the basis of parameter project provided.

//DataModel.cs
public async Task<List<TClass>> PlotChart(string project)
{
	//Data Logic
}

In my View Model Dashboard.cs I am having another PlotChart  method which makes call to the PlotChart method of  DataModel.cs.  This View Model method applies some business logic and ultimately plots some charts on the dashboard.

//DashboardViewModel.cs 
private async Task PlotChart(MainWindow window, string project)
{
	var data = await _db.PlotChart(project);
	//Business Logic
}

In my Xaml i am using two boolean properties (IsBusyPie & IsBusyLine) to show/hide the progress bar and two string properties (BusyMessagePie & BusyMessageLine) two change the message at run time.

<xctk:BusyIndicator
IsBusy=”{Binding IsBusyPie}”
BusyContent=”{Binding BusyMessagePie}” >
<WrapPanel x:Name=”ProjectPanel”/>
</xctk:BusyIndicator>

<xctk:BusyIndicator
IsBusy=”{Binding IsBusyLine}”
BusyContent=”{Binding BusyMessageLine}” >
<WrapPanel x:Name=”BranchPanel”/>
</xctk:BusyIndicator>

There are three approaches which i tried to get the job done, which are described below and their pros and cons also.

Approach 1

Initially I tried calling my ViewModel PlotChart method in view model’s constructor itself using Array.ForEach linq extension.

//In Constructor of ViewModel
IsBusyPie = IsBusyLine = true;
Array.ForEach(projects, project => 
{
	PlotChart(window,project);	
});
IsBusyPie = IsBusyLine = false;

The issue with this approach was, two calls to the function plotchart was made by the Array.Foreach and the boolean values were assigned false. This made UI stuck and there was no progress bar.

Explanation: In this approach the array made asynchronous call and when it hits the await of PlotChart function, control returns. It does that twice (assuming the array has two values).The parent method comes out of that loop and sets

IsBusyPie = IsBusyLine = false;

And some time after when the result of the awaits is returned and it carries on inside the PlotCharts.

Approach 2

Then I changed my approach and I created another function named PlotChart and made calls to my asynchronous method using await keyword (As I could not use await in constructor i created another function). The issue still not resolved although I used await keyword with the calls.

//New Function
private async Task PlotChart(MainWindow window)
{
	IsBusyPie = IsBusyLine = true;
	Array.ForEach(projects, async project =>
		await PlotChart(window, project));
	IsBusyPie = IsBusyLine = false;
}

ExplanationList<T>.ForEach doesn’t play particularly well with async (neither does LINQ-to-objects, for the same reasons). Possibly the lambda is being seen by the compiler as an async void and the await does nothing.

Approach 3

After failing in the above two approaches i decided to iterate the array and make two conventional calls using foreach. And to my surprise it worked fine. My all progress bars showing properly, my UI is not stuck and my views gets updated simultaneously also.

//New Function 
private async Task PlotChart(MainWindow window)
{
	IsBusyPie = IsBusyLine = true;
	foreach (var project in projects)
	{
		await PlotChart(window, project);
	}
	IsBusyPie = IsBusyLine = false;
}

Explanation: This approach is a mix asynchronous and synchronous process. Here when the loop hits the first asynchronous method it awaits for its result and as soon as it gets the output, it updates the View and makes another asynchronous call to the method.

Conclusion: After working with different approaches, it suggests that you should use the foreach loop and await each call instead of using LINQ-to-objects.

 

How MVC maps HTTP request data to action method parameters and custom .NET objects

Introduction

ASP.NET MVC model binding allows you to map and bind HTTP request data with a model. Model binding makes it easy for you to work with form data because the request data (POST/GET) is automatically transferred into a data model you specify. ASP.NET MVC accomplishes this behind the scenes with the help of Default Binder.

In this article we will dicuss how MVC maps HTTP request data directly into action method parameters and custom .NET objects. We know this all is done by MVC automatically behind the scenes, but how? What’s the mechanism which is doing all this? Lets discuss it in detail with an example.

Lets assume we have a Employee Model like this:

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

We have a form like this.

@using (Html.BeginForm())
{
@Html.TextBoxFor(m=>m.FirstName, new { @class = “form-control” })
@Html.TextBox(“name”, new { @class = “form-control” })
@Html.TextBox(“lastname”, new { @class = “form-control” })
}

And an Action like this:

public ActionResult Index(Employee employee, string name)

Image showing how form looks like:

form

On click of the submit button, we can see in the below watch window how the values are automatically passed to action method.

employee

  • The Employee Model automatically gets populated with value of “FirstName”
  • The string parameter named “name” also gets populated with the value of textbox from our UI
  • By using Request.Form[“lastname”] we can get the value of lastname also.

So, the question is how did we got all these values, even though we didn’t wrote a single line of code for that. So, here is the black magic.

Now before the Index action gets called, there are two important components that do some tricks behind the scenes:

  • ValueProviderDictionary
  • DefaultModelBinder

.The ValueProviderDictionary pulls out the values from the HTTP request and stores them as strings. The fetching itself is done in the following order:

  • Request.Form[“name”], if it exists
  • Else, RouteData.Values[“name”], if it exists
  • Else, Request.QueryString[“name”], if it exists
  • Else returns null

Now that the ValueProviderDictionary has extracted the necessary strings from the incoming request, the DefaultModelBinder class takes on the responsibility of converting these strings into appropriate .NET objects.

When the DefaultModelBinder is required to supply an instance of some custom .NET type, Reflection comes for the rescue. Using reflection, all the public properties exposed by the custom type receive values based on what the ValueProviderDictionary class provided. Do bear in mind that there’s some kind of recursion happening here and that’s how all properties and its sub-properties get set with values.

That was all the magic which MVC does behind the scenes and I hope this explanation helps somebody in clearing their doubts.

Generate rows based on the values of a column

Recently while working on a module, I was asked to create data rows based on the column values of a SQL table. I needed to generate the rows in table B based on the values of column table A.

So we had a  SQL table with UserId and Quantity as column and below possible values.

UserId Quantity
ACC_xxx_003 1
ACC_xxx_004 4
ACC_xxx_005 1
ACC_xxx_006 3

The desired output was:

UserId Quantity
ACC_xxx_003 ACC_xxx_003-001
ACC_xxx_004 ACC_xxx_004-004
ACC_xxx_004 ACC_xxx_004-004
ACC_xxx_004 ACC_xxx_004-004
ACC_xxx_004 ACC_xxx_004-004
ACC_xxx_005 ACC_xxx_005-001
ACC_xxx_006 ACC_xxx_006-003
ACC_xxx_006 ACC_xxx_006-003
ACC_xxx_006 ACC_xxx_006-003

To get this working there were different approaches but I chose to use CTE for its simplicity and ease of use. Below is the code which I created.

CREATE TABLE UserMapping (
	UserId VARCHAR(50)
	,Quantity INT
	)
 
INSERT INTO UserMapping
VALUES 
	('ACC_xxx_003',1)
	,('ACC_xxx_004',4)
	,('ACC_xxx_005',1)
	,('ACC_xxx_006',3);
 
	--===== Create number table on-the-fly
WITH CTE (n)
AS (
	SELECT 1 AS n
	
	UNION ALL
	
	SELECT n + 1 AS n
	FROM CTE
	WHERE n < 101
	)
	,Num2 (n)
AS (
	SELECT 1
	FROM CTE AS X
		,CTE AS Y
	)
	,Nums (n)
AS (
	SELECT ROW_NUMBER() OVER (
			ORDER BY n
			)
	FROM Num2
	)
SELECT UserId
	,Quantity AS Serial
INTO FormattedTable
FROM UserMapping
CROSS APPLY (
	SELECT n
	FROM Nums
	) d
WHERE Quantity >= n
 
SELECT UserId
,UserId + '-' + right('000' + cast(Serial AS VARCHAR(50)), 3) AS Serial
FROM FormattedTable
ORDER BY UserId
 
DROP TABLE UserMapping
	,FormattedTable

Azure Diagnostics Configuration

Recently I was working on a task where I had to update the azure applications from Azure v2.1 to v2.7. I made the required changes to the application and when I tried to deploy the application on the Azure I faced many challenges and Issues. I will try and put as many as possible issues I faced during this transition phase, in this and coming write up’s to keep a log for myself and for others too.

During deployment I faced an error stating:

The element StorageAccount doesn’t match the storage account name provided in the cmdlet arguments. It is recommended to not use the element StorageAccount as it is automatically set by the cmdlet.

Initially I went with the words from the error message and removed the –StorageContext from my below command.

Write-Verbose 'Start Set-AzureServiceDiagnosticsExtension'

Set-AzureServiceDiagnosticsExtension -StorageContext $storageContext -DiagnosticsConfigurationPath $wadConfig-ServiceName $AzureServiceName -Slot $AzureSlot  -Role $role

To my surprise it didn’t threw any error but the code did not completed the deployment also. I waited for more than two hours but the Azure Management Console still showed “In Transition“ state.

Now it was clear that the error message is not depicting the actual problem. I started looking into the changes I made during the code transition from v2.1 to v2.7. After going through many files and many lines of code, I found out that the issue was because I was having an empty Storage Account tag in the Diagnostics Configuration file(.wadcfgx).

<StorageAccount />

I should not say this was the only reason which caused the error. In fact, in my .cscfg file I did not introduced the AccountName under diagnostics connection string. And as per the MSDN,

  • If a diagnostics connection string is specified in the .cscfg file, Visual Studio uses it to configure the diagnostics extension when publishing, and when generating the public configuration xml files during packaging.
  • If no diagnostics connection string is specified in the .cscfg file, then Visual Studio falls back to using the storage account specified in the .wadcfgx file to configure the diagnostics extension when publishing, and generating the public configuration xml files when packaging.
  • The diagnostics connection string in the .cscfg file takes precedence over the storage account in the .wadcfgx file. If a diagnostics connection string is specified in the .cscfg file, then Visual Studio uses that and ignores the storage account in .wadcfgx.

So, to fix the bug I made few changes to my code:

  • First, I introduced the storage account name in the connection string of the “.cscfg” file.
    <ConfigurationSettings>
    <Setting
    name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString"
    value="DefaultEndpointsProtocol=https;
    AccountName=TestAccount;
    AccountKey=HUKNuwWdLOKM1dOhFzqLZrUcHvtAbg==" />
  • Second, I removed the <StorageAccount /> tag from my configuration file

After making the above two changes everything started working fine and my changes got deployed.