Monday, December 15, 2014

Editor Template for Boolean Property in Razor

If you want to display 2 radio buttons for a boolean property in Razor with Yes and No labels, this is how you could do it.

Create your own editor template and put it in the Shared/EditorTemplate folder.

Template code:

@model bool
@using System.Web.Mvc
@Html.RadioButtonFor(model=>model, false) No
@Html.RadioButtonFor(model => model, true) Yes

Thursday, October 23, 2014

Create Separate Dropdowns for Day, Month, Year in ASP.NET MVC

Create a structure that will hold the Month, Day and Year fields:

public struct DatePart
    {
        public static IEnumerable<int> DayItems
        {
            get
            {
                return Enumerable.Range(1, 31);
            }
        }

        public static IEnumerable<String> MonthItems
        {

            get
            {
                return new System.Globalization.DateTimeFormatInfo().MonthNames;
            }
        }

        public static IEnumerable<int> YearItems
        {
            get
            {
                return Enumerable.Range(DateTime.Now.Year - 30, 30 + 1);
            }
        }
    }
Your model class should contain the following properties;

public int Day { get; set; }
public int Month { get; set; }
public int Year { get; set; }

     Create SelectListItem Date, Month and Year collections and add them to the ViewBag.

ViewBag.Days = DatePart.DayItems.Select(d => new SelectListItem { Text = d.ToString() });

 ViewBag.Months = DatePart.MonthItems.Select((m, i) => new SelectListItem
 {
    Value = (i + 1).ToString(),
    Text = m
 });

 ViewBag.Years = DatePart.YearItems.Select(y => new SelectListItem { Text = y.ToString() });
In the view, create dropdowns and populate them with collections in the ViewBag.
@Html.DropDownList("Day", (IEnumerable<SelectListItem>) ViewBag.Days)
@Html.DropDownList("Month", (IEnumerable<SelectListItem>) ViewBag.Months)
@Html.DropDownList("Year", (IEnumerable<SelectListItem>) ViewBag.Years)
It is important that the select element names match the property names in the model.

Now, in your controller method you can access the selected values as follows:
var selectedTime = new DateTime(model.Year, model.Month, model.Day);

Thursday, February 27, 2014

Replace foreach with Extension Methods and Lambda Expressions

I suppose many of us use the foreach statement very often in our code. I'll show you how to replace simple foreach statements with new lambda expressions.

Suppose you want to create a List < string> of names of files residing in a directory. This is how you could do it.

Set up an array of FileInfo objects:

string filePath = @"C:\Temp";
DirectoryInfo dInfo = new DirectoryInfo(filePath);
FileInfo[] fileInfoArray = dInfo.GetFiles();

Create a string type List:

List<string> fileList = new List<string>();
foreach (FileInfo fi in fileInfoArray)
{
    fileList.Add(fi.Name);
}

Select

Using lambda expressions and the Select extension method it is possible to re-write the last 3 lines as follows:

var files = fileInfoArray.Select(fi => fi.Name);

That's one line instead of 3. But we still want a List <string> object to be used later in the code. We need to use the Enumerable.ToList <TSource> method to cast to a List. This is how we do it:

List<string> fileList2 = fileInfoArray.Select(fi => fi.Name).ToList (); 

This way you use one line of code instead of 4.

Modify Elements in a Collection

Use the Select method to modify elements in a collection. The important part is you need to return each element;

An example follows:

var plans = query.AsEnumerable().Select(it =>
                {
                    it.PlanYears = Enumerable.Range(it.Plan.StartDate.Year, (DateTime.Now.Year - it.Plan.StartDate.Year) + 1);                  
                    return it;
                });

How to get an ordinal position of an item in the list.
Example:

var mm = new System.Globalization.DateTimeFormatInfo().MonthNames.Select( (a, i) => new
                    {
                        Item = a,
                        Position = i
                    });

Where

Now, what if we add only those file names to the List that meet certain criteria, e.g:

foreach (FileInfo fi in fileInfoArray)
{
    if (fi.Length > 10000000)
    {
        largeFiles.Add(fi.Name);
    }
}

Which equivalent extension method can we use to achieve the same result? We need to use the Where extension method of the IEnumerable <T> interface first, and then append the earlier Select method to the statement:

var varLargeFiles =  fileInfoArray.Where (fi => fi.Length > 1000000).Select(fi=>fi.Name);


-->

FindAll

If you need to filter your collection and iterate through the result, use the FindAll extension:

IncomeSourceList.FindAll(item => item.ItemSourceType == SourceType.PERM).ForEach(
         
                item => Debug.WriteLine(item.ItemSourceType)
                  );

This code selects only those collection items whose ItemSourceType equals to PERM type, and then loops through the result.

LINQ

Now, to complete the example, I'll show the way to obtain a similar list using the LINQ:

var q = from fi in fileInfoArray
        where fi.Length > 1000000
        select fi.Name;

List<string> largeFiles2 = q.ToList();

Query operator ToList() forces immediate query evaluation.

Boolean Methods


What if you have a method that loops through an array and returns a bool type depending on some condition inside the loop. Can we use query operators instead? It is slightly more difficult but still possible.

Suppose you have the following methods that compares each character in a string array to each character in another string array and returns false when a character in the second array is not found in the first array:


public static bool IsAnagram(string word, string input)
{
    char[] inputArray = input.ToCharArray();
    foreach (char ch in word.ToCharArray())
    {
        if (!inputArray.Contains(ch))
              return false;
    }
    return true;
}

To emulate similar statements, first we need to find the first non-matching character:

char c =  word.ToCharArray().FirstOrDefault (x => !inputArray.Contains(x));    
      
 We use the FirstOrDefault  operator instead of First because otherwise we may have "Sequence contains no matching element" error if the expression does not returns any characters.

Now we can return a bool value depending on the result of the previous statement:
return (c != 0) ? false: true;

For sheer fun you can rewrite those two statements as follows: 
return (word.ToCharArray().FirstOrDefault(x => !inputArray.Contains(x))) == 0;

Grouping

Grouping allows us to group the result into distinct groups using a field or several fields as group criteria. Each group will have a key property that you can use to refer to the field(s) grouped on.

Example:

 Let's say we have a Sales table with the following fields: Rep, SalesDate, RepEmail, etc. We want to know how many sales each Rep made each month.

First, let's build a query that counts the total number of sales per Rep:

from s in Sales
group s by s.Rep into gr
select new {
    Name = gr.Key,
    Count = gr.Count()
}



This query would translate into the following sql statement:

select Rep as Name, Count(*)
    from Sales
    Group By Rep

To group the result further by month, we would use the following query:

from s in Sales
group s by new {s.Rep, s.SalesDate.Month} 
into gr
select new {
    Name = gr.Key.Rep,
    SalesMonth = gr.Key.Month,
    Count = gr.Count()
}


Sorting

This does not really belong in this post, however, here is a quick way to sort a list of objects. Your object could be similar to this one:


class MyObject{
   public string Symbol {get;set;}
   public double Value {get;set;}
}

myList.Sort((a, b) => a.Symbol.CompareTo(b.Symbol));


Any

To find out if an element exists in a collection, use the extension method Any:
   if(userRoles.Any(role=> role.Equals("Admin")))
        ...


Some other posts you might find interesting:
Query Operator First
Easy Syntax to Print List Elements



Wednesday, September 4, 2013

Deploy ASP MVC on IIS 6

This post just complements information already available online.
There are certain steps you need to do first before your ASP MVC application can run in IIS 6.

In the Properties screen, on the Directory tab click Configuration.


On the Mappings tab, click Insert to insert a wildcard application map:


Browse to the location of the aspnet_isapi.dll file. Make sure that Verify that file exists check-box is clear.

Click OK to save your changes. That should be enough provided you have all the required dll files in the bin folder.

Thursday, July 18, 2013

Copy Property Values

If you have 2 objects that do not inherit from each other but have similar properties, here is a function you can use to copy property values from one object to the other:

    public static void CopyIdenticalProperties (this object source, object dest)
        {
            var plist = from prop in source.GetType().GetProperties()
                        where prop.CanRead && prop.CanWrite
                        select prop;

            foreach (PropertyInfo prop in plist)
            {
                var destProp = dest.GetType().GetProperty(prop.Name);              
                if (destProp != null)
                {
                    destProp.SetValue(dest, prop.GetValue(source, null), null);
                }
            }
        }

Wednesday, June 12, 2013

Format Phone Number

This is how you could format a phone number using a period as a separator:

String.Format("{0:###\\.###\\.####}", 1234567890);

The resulting string will look as follows: 123.456.7890.

Wednesday, November 28, 2012

Update WCF Service Site References

If you have a problem updating dll files in the bin folder of your Web Site deployment project, the following method may work: delete all dll files in your bin folder, and then add a reference to you Service project. All the other required dll files will be added automatically.