Some of the new things in C# and .NET 4.0

29. September 2009

Just thought I should share some thoughts and information about some of the new things that I think are a bit interesting. This is in no way a complete list of new things.

Language

 

Optional and named arguments

I feel VB6 coming back to me when I see this and I guess that this is something the VB.NET people already have? Optional arguments simply let’s you omit argument values and named arguments let’s you enter them in any order you’d like.

public int Test(int a, int b = 1, int c = 2, int d = 3) {
return a + b + c + d;
}

public string Hello(string name = "World") {
return "Hello, " + name + "!";
}

public void Main() {
Test(0); //Test(0,1,2,3)

Test(0, c: 5); //Test(0,1,5,3)

Test(d: 5, a: 0); //Test(0,1,2,5)

Hello(); //Hello("World");
}

I think this is something I will use for saving some lines of code where I earlier wrote several method/constructor overloads.

Note that both functions will work not only in methods but also in constructors and indexers.

Variance

Oh dear… Let’s see if I can make this one justice.

Everybody knows that you can write this:

//No problem!
string s = "Hello";
object o = s;

It works because string is a subclass of System.Object and you can always cast to a less derived object.

The following however does not work.

IList<string> strings = new List<string>();
IList<object> objects = strings;
// And if you think of if it kind of makes sense:
objects[0] = 1000.0;
var whatAmI = strings[0]; //Would contain a string representation of 1000.0

The thing is that the above code should be fine if the collection objects where “readonly”, say, IEnumerable<T> but in C# pre 4.0 you wouldn’t have any luck there either. But now!

//Will work in C# 4.0 since IEnumerable is a readonly collection
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;

Let’s try and make a “real” example. The following code will not compile in C# 3.0 but in 4.0 it’s party time. The reason is the last line of code. Only with C# 4.0 is it possible to cast apples and bananas to IEnumerable<Fruit>.

public class Fruit { }
public class Apple : Fruit { }
public class Banana : Fruit { }

public class Varicance
{
public static void Main()
{
//Bag of apples
var apples = new List<Apple>() {
new Apple(),
new Apple()
};

//Bag of bananas
var bananas = new List<Banana>() {
new Banana(),
new Banana()
};

//Let's put them together
IList<Fruit> fruitBasket = apples.AsEnumerable<Fruit>()
.Concat(bananas).ToList();
}
}

For a deeper explanation of variance I recommend watching the following video with Anders Hejlsberg. Expert to Expert: Erik Meijer and Anders Hejlsberg - The Future of C#

Dynamic

This is probably one of the biggest news in C# 4.0 and it’s also the one I will write least about. But this is what it is:

C# 4.0 introduces a new static type called dynamic and if you declare an object dynamic the properties and methods of that objects won’t be resolved until runtime. This is useful when communicating with other dynamic languages and COM objects.

Framework

 

Code Contracts

This is a way for you to more easily declare and visualize the contracts that a method must fulfill. Not only is it more easy for you as a developer to understand what the “rules” for a method is the compiler can also pre-check the conditions and find code that will break your contracts.

public object GetObject(string id)
{
Contract.Requires(!string.IsNullOrEmpty(id));
Contract.Ensures(Contract.Result<object>() != null);

return Repository.Get(id);
}

The contract will ensure that the id argument is not null or empty and also that the returned object is not null.

Parallel Extensions

Quite a lot of work has been done to add better multi core support to .NET, better as in easier to use. There is a improved ThreadPool, two new types: Task and Task<T> that you can think of as a lighter, easier to use Thread type and Parallel LINQ(PLINQ).

public void PLINQ()
{
//.AsParallel is all you need...
var data = GetData();
var q = from x in data.AsParallel()
where someFunc1(x)
orderby x.SomePropery
select x;
}

BigInteger

For when you need does reeeally big numbers… In theory the BigInteger has no maximum but eventually you will run out of memory.

//1e+100. One followed by one hundred zeros.
BigInteger googol = BigInteger.Parse("10000000000000000000000000" +
"0000000000000000000000000" +
"0000000000000000000000000" +
"0000000000000000000000000");

//(1e+100)^1000. That's one followed by 100 000 zeros!!
//(That is 27 pages in Word with nothing but zeros....)
BigInteger reallyBig = BigInteger.Pow(googol, 1000);

Better file system enumerations

The GetFiles and GetDirectories methods on System.IO.Directory and DirectoryInfo returns an array of objects. This is not always(when would it be?) ideal. A better solution would be if they returned IEnumerables and that the internally used yield return. And now they do! Or at least the new EnumerateXXXX methods do. This is far more efficient when writing code like this.

public FileInfo FindFile(string filename)
{
var directory = new DirectoryInfo(SOME_PATH);
foreach (var file in directory.EnumerateFiles())
if (file.Name.Equals(filename, StringComparison.InvariantCultureIgnoreCase))
return file;
}

There you go. Is I said, this is only a handful of the new things in C# and .NET 4.0 but it’s some of the coolest ;)

C#, .NET ,

Generate Excel reports with ASP.NET MVC

26. September 2009

There is very little ASP.NET MVC specific code in this post but since I love the framework so much I included it in the title anyway.

Say you have an online address book and you want your users to be able to download the content of this address book in a Microsoft Excel format.

I had a similar problem and wanted a light generic solution. What I came up with was a CSVExport ActionResult class. To export data to Excel all I have to do is:

public ActionResult Export()
{
//Fetch some data
var addressbook = Repository.GetAllPeople();
//Generate and return the csv file
return new CSVResult<Person>(addressbook );
}

I use Microsoft Excel but since the data returned is a CSV(Comma-separated values)-file it can be used by a lot of different applications.

So where’s the magic?

With the help of reflection I get a list of all the public properties defined on the T class. I then enumerate all object in the supplied IList of T and pulls the data from the properties reflected. All this data is added to a StringBuilder and the result is a CSV file.

To make things a little more customizable i created a CSVExportAttribute class that you can use to control what and how you want to export data to CSV-format.

[AttributeUsage(AttributeTargets.Class 
| AttributeTargets.Property, AllowMultiple=false)]
public class CSVExportAttribute : Attribute
{
//Let's you specify a custom header text
public string Header { get; set; }
//If true and set on a property that
//property will not be exported.
public bool Exclude { get; set; }
}

You can set this attribute on a class or/and on a property. When set on a class that means that all properties in that class, except if explicitly specified, will be exported.

Okay, lets look at the main code
public class CSVResult<T> : ActionResult
{
public string Filename { get; set; }
public char Delimiter { get; set; }
public IList<T> Data { get; set; }

public CSVResult(IList<T> data)
: this(data, null) { }
public CSVResult(IList<T> data, string filename)
{
this.Data = data;
this.Filename = filename;
this.Delimiter = ';';
}

The CSVResult<T> inherits ActionResult and takes a IList<T> in the constructor. Nothing crazy there. The important code is in the ExceuteResult method.

public override void ExecuteResult(ControllerContext context)
{
//The file name to display in the Open/Save-file dialog.
string filename = this.Filename ?? "CSV_" + DateTime.Now.ToString("yyyyMMddHHmmss");

//Set up headers
context.HttpContext.Response.ContentType = "text/csv";
context.HttpContext.Response.ContentEncoding = Encoding.Unicode;
context.HttpContext.Response.AppendHeader("Content-Disposition",
string.Format("filename=\"{0}.csv\";attachment", filename));

First we set up the response headers to make the browser understand that the response data is as a file and with that done we can finally get to the real code.

//Enumerate the list and output header + data
if (this.Data != null)
{
bool exportAll = false;

StringBuilder sb = new StringBuilder();
var exportProperties = new Dictionary<00ff">string, System.Reflection.PropertyInfo>();
var type = typeof(T);

//If the csv export attribute is set on the
//class we export data from all properties.
foreach (CSVExportAttribute attrib in type.GetCustomAttributes(typeof(CSVExportAttribute), false))
{
if (!attrib.Exclude)
{
exportAll = true;
break;
}
}

Make sure we have some data and then we look if the class has the CSVExport attribute, if so, we set a flag and moves on.

//Find properties with CSVExportAttribute
foreach (var prop in type.GetProperties(System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance))
{
bool hasAttribute = false;
foreach (CSVExportAttribute attrib in prop.GetCustomAttributes(typeof(CSVExportAttribute), false))
{
hasAttribute = true;
if (!attrib.Exclude)
{
//If we have a custom header lets use it;
//otherwise we go with the property name
string header = attrib.Header ?? prop.Name;
exportProperties.Add(header, prop);
}
}

//If the property doesn't have any ExportAttributes
//but the class has then we export the property anyway.
if (hasAttribute == false && exportAll)
{
exportProperties.Add(prop.Name, prop);
}
}

We enumerate all public properties and look for the CSVExport attribute. If we find it or the exportAll is true from before then we add the property to a properties-to-export collection. If we find the attribute and the Header value is set we use that value instead of the property name for our key that later will the the column header in the CSV-file.

We have all we need, let’s build the CSV
//Add headers to the csv data
foreach (var p in exportProperties)
sb.Append(p.Key).Append(this.Delimiter);

sb.Append(Environment.NewLine);

//Rows
foreach (var row in this.Data)
{
//Columns
foreach (var p in exportProperties)
{
try
{
sb.Append(RemoveInvalidCharacters(p.Value.GetValue(row, null)
.ToString())).Append(this.Delimiter);
}
catch (Exception)
{
//Unable to get value.
//Add delimiter to make sure columns are correct.
sb.Append(this.Delimiter);
}
}

sb.Append(Environment.NewLine);
}
//Write the data to the response stream
context.HttpContext.Response.Write(sb.ToString());

First me make a row with the headers each separated by a delimiter(; as default). We then enumerate all the rows in our list and for each row we get the value for each property found earlier.

The RemoveInvalidCharecters function does exactly what is says.

private string RemoveInvalidCharacters(string v)
{
string replaceWith = " ";

if (string.IsNullOrEmpty(v))
return v;

return v.Replace(this.Delimiter.ToString(), replaceWith)
.Replace(Environment.NewLine, replaceWith)
.Replace(((char)10).ToString(), replaceWith) //Carrige return char(10)
.Replace(((char)13).ToString(), replaceWith); //Line feed char(13)
}

With this done all we have to do is decorate the classes want to be able to export with the CSVExport attribute.

[CSVExport]
public class Person
{
[CSVExport(Header="First name")]
public string FirstName { get; set; }

[CSVExport(Header = "Last name")]
public string LastName { get; set; }

public string Telephone { get; set; }

[CSVExport(Exclude = true)]
public int Id { get; set; }
}

That’s all folks!

ASP.NET MVC , ,

Creating iCalendar events with ASP.NET MVC

26. September 2009

From Wikipedia: iCalendar is a computer file format which allows internet users to send meeting requests and tasks to other internet users, via email, or sharing files with an .ics extension. Recipients of the iCalendar data file (with supporting software, such as an email client or calendar application) can respond to the sender easily or counter propose another meeting date/time.

My goal for this solution was to allow the users of my web application to add events to their Microsoft Outlook calendar. Using the iCalendar format makes the solution work with a lot of calendar applications.

So what do we need to make this work?

First I created a two classes. An Event class that contains information about the event and an iCalendar class that contains information about the calendar and a list of Events.

public class iCalendar
{
private const string DEFAULT_DATEFORMAT = "yyyyMMdd\\THHmmss\\Z";
private const string ALLDAY_DATEFORMAT = "yyyyMMdd";

public iCalendar()
{
this.Events = new List<Event>();
}
public List<Event> Events { get; set; }

public string Name { get; set; }
public string Description { get; set; }

//Helper methods to format the DateTime values.
//These are used from the MVC view.
public string GetTimeString(DateTime time)
{
return GetTimeString(time, false);
}
public string GetTimeString(DateTime time, bool allDay)
{
if (allDay)
return ";VALUE=DATE:" + time.ToUniversalTime().ToString(ALLDAY_DATEFORMAT);
else
return ":" + time.ToUniversalTime().ToString(DEFAULT_DATEFORMAT);
}
}

public class Event
{
public DateTime StartTime { get; set; }
public DateTime EndTime {get; set; }

public string Title { get; set; }
public string Location { get; set; }
public string Description { get; set; }
public string HtmlDescription { get; set; }

public bool AllDay { get; set; }
public bool Reminder { get; set; }

//A unique identifier for the event.
//If it's not set we return a new Guid value.
public string UID
{
get
{
if (string.IsNullOrEmpty(this.uid))
return Guid.NewGuid().ToString();
else
return this.uid;
}
set { this.uid = value; }
}
private string uid;
}

As you can see these classes are simple property containers without any real logic. To save space i removed some logic that returned default values if a property was not set. Similar to the UID property.

The View

Now we almost have our full implementation. All we need is a ASP.NET MVC View that renders the iCalendar data.

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<iCalendar>"%>BEGIN:VCALENDAR
PRODID:-//jpalm.se//iCalendar example with ASP.NET MVC//EN
VERSION:2.0<%if (Model.Events.Count > 1){%>
X-WR-CALNAME:<%=Model.Name%>
X-WR-CALDESC:<%=Model.Description%>
CALSCALE:GREGORIAN
METHOD:PUBLISH<%}%><%foreach(var evnt in Model.Events){%>
X-MS-OLK-FORCEINSPECTOROPEN:TRUE
BEGIN:VEVENT
DTSTART<%=Model.GetTimeString(evnt.StartTime,evnt.AllDay)%>
DTEND<%=Model.GetTimeString(evnt.EndTime,evnt.AllDay)%>
LOCATION:<%=evnt.Location%>
TRANSP:OPAQUE
SEQUENCE:0
UID:<%=evnt.UID%>
DTSTAMP<%=Model.GetTimeString(evnt.StartTime)%>
CREATED<%=Model.GetTimeString(DateTime.Now)%>
LAST-MODIFIED<%=Model.GetTimeString(DateTime.Now)%>
DESCRIPTION:<%=evnt.Description%>
X-ALT-DESC;FMTTYPE=text/html:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//E
N"
>\n<HTML>\n<HEAD>\n<TITLE></TITLE>\n</HEAD>\n<BODY><%=evnt.HtmlDescription%></BODY>\n</HTML>
SUMMARY:<%=evnt.Title%><%if(evnt.Reminder){%>
BEGIN:VALARM
TRIGGER:-PT15M
ACTION:DISPLAY
DESCRIPTION:Reminder
PRIORITY:5
END:VALARM<%}%>
END:VEVENT<%}%>
END:VCALENDAR

The X-?? fields are extensions to the iCalendar standard that works with Microsoft Outlook.

Okay, so what do we have here? A strongly typed view based on our iCalendar object. As you can see the inline server tags are not on their own lines. This is because we don’t want any extra line breaks in our output.

Microsoft Outlook behaves a bit differently depending on whether the iCalendar file contains one or several events. If there’s only one event Outlook will prompt the user with a ‘New appointment’-dialog that will be populated with the data from the file. All the user has to do is press save and the event is saved the user’s default calendar. If there are several events in the file Outlook will add a new calendar and all the events are displayed in that. This is why we only set a calendar name and description if the Model.Events.Count is larger then 1.

Other than that we don’t do anything funky. All the fields are defined in the iCalendar format.

So, last step. How do we use this?
public ActionResult Calendar()
{
var icalendar = new iCalendar();
icalendar.Events.Add(new Event
{
StartTime = DateTime.Now.AddHours(1),
EndTime = DateTime.Now.AddHours(2),
Title = "iCalendar blog post",
Description = "Write a blog post about using iCalendar in ASP.NET MVC",
Location= "@ Home"
});

//The file name to display in the Open/Save-file dialog.
string filename = icalendar.Events[0].Title;
//IE want's you to url encode the file name. Other browsers don't like this.
if (Request.UserAgent.ToLower().Contains("msie"))
filename = Server.UrlEncode(filename).Replace("+", " ");

//Set a content type
this.Response.ContentType = "text/calendar";
//Make the browser display the Open/Save-file dialog.
this.Response.AddHeader("Content-disposition", "attachment; filename=\"" + filename + ".ics\"");

//Render the view
return View("iCalendar", icalendar);
}

You probably should wrap the file name and header set up into a new ActionResult based class and then use that instead of setting this directly in the action method.

If the user presses a link that executes the Action above a save file dialog will appear and if Microsoft Outlook is installed the Create Appointment-dialog will display when the file is opened.

Save_Dialog Outlook_Dialog

And that’s how I added iCalendar support with ASP.NET MVC.

ASP.NET MVC ,

Clicky Web Analytics