:::: MENU ::::

Tuesday, August 7, 2012

I’ve picked something up where Yao Huang Lin of Microsoft left off. For preliminary material, check out his blog and check out his posts on generating documentation.

In one of his later posts, he suggested creating a help controller. This is where I’ve picked things up. In Yao’s solution, he’s rendering html-based views. While that works well and makes for a nice presentation, I wanted to remain within the mode of just returning data, whether it is JSON or XML. Before continuing on with this post, please be sure to read Yao’s posts on the topic as I will be picking up where he left off on this post where he talks about other implemenations.

The first thing we need is a help controller.  Here is the one I’ve created:

using System.Collections.Generic;

using System.Net;

using System.Web.Http;

using System.Web.Http.Description;

namespace WebAPI.Controllers

{

[ApiExplorerSettings(IgnoreApi = true)]

public class HelpController : ApiController

{

public List Get()

{

return APIDocumentationRepository.Get();

}

public APIEndPoint Get(string api)

{

return APIDocumentationRepository.Get(api);

}

}

}

Nothing all that complicated here. Like all good controllers, this one is thin – with just enough logic to expose and service the end points. I’ve created an APIDocumenationRepository Class to handle all of the data-related operations. One point to focus on is the attribute: [ApiExplorerSettings(IgnoreApi = true)]. We don’t want the help controller itself to appear in the documentation. No need to do that since in order to get to the help documentation, you need to know the help endpoint exists in the first place!

There are two endpoints: one to get all of the endpoints and another to get a specific endpoint. In my earlier posts, I was referencing a simple Products Controller. I’m continuing to use that same controller here. For review, here is the listing for that controller:

using System;

using System.Linq;

using System.Net.Http;

using System.Web.Http;

using WebApi.Models;

namespace WebApi.Controllers

{

public class ProductsController : ApiController

{

/// <summary>

/// Returns the Product Collection.

/// </summary>

/// <returns></returns>

[Queryable]

public IQueryable<Product> GetProducts()

{

return ProductsRepository.data.AsQueryable();

}

/// <summary>

/// Returns an individual Product.

/// </summary>

/// <param name="id">The Product id.</param>

/// <returns></returns>

public Product GetProduct(int id)

{

try

{

return ProductsRepository.get(id);

}

catch (NotFoundException)

{

throw new HttpResponseException(new HttpResponseMessage()

{

StatusCode = System.Net.HttpStatusCode.NotFound

});

}

}

/// <summary>

/// Deletes the Products Collection and reverts back to original state.

/// </summary>

/// <returns></returns>

[HttpDelete]

public void ResetProducts()

{

ProductsRepository.reset();

}

/// <summary>

/// Deletes an individual Product.

/// </summary>

/// <param name="id">The Product id.</param>

/// <returns></returns>

public void DeleteProduct(int id)

{

try

{

ProductsRepository.delete(id);

}

catch (NotFoundException)

{

throw new HttpResponseException(new HttpResponseMessage()

{

StatusCode = System.Net.HttpStatusCode.NotFound

});

}

}

/// <summary>

/// Updates an individual Product.

/// </summary>

/// <param name="product">The Product object.</param>

/// <returns></returns>

public void PutProduct(Product product)

{

ProductsRepository.update(product);

}

/// <summary>

/// Creates a new Product.

/// </summary>

/// <param name="product">The Product object.</param>

/// <returns></returns>

public void PostProduct(Product product)

{

ProductsRepository.add(product);

}

}

}

There are a few changes from the earlier versions of this controller. As you can see, I’m using the XML Documentation features Yao talks about in his post. I’ve simply employed the technique he describes.

The next thing to cover is the APIDocumenationRepository Class. Here is the code for that class:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Runtime.Serialization;

using System.Web;

using System.Web.Http;

using System.Web.Http.Description;

namespace WebAPI

{

public class APIDocumentationRepository

{

public static APIEndPoint Get(string apiName) {

return getAPIEndPoint(apiName);

}

public static List<APIEndPoint> Get()

{

var Controllers = GlobalConfiguration

.Configuration

.Services

.GetApiExplorer()

.ApiDescriptions

.GroupBy(x => x.ActionDescriptor.ControllerDescriptor.ControllerName)

.Select(x => x.First().ActionDescriptor.ControllerDescriptor.ControllerName)

.ToList();

var apiEndPoints = new List<APIEndPoint>();

foreach (var controller in Controllers) {

apiEndPoints.Add(getAPIEndPoint(controller));

}

return apiEndPoints;

}

static APIEndPoint getAPIEndPoint(string controller) {

var apis = GlobalConfiguration

.Configuration

.Services

.GetApiExplorer()

.ApiDescriptions

.Where(x => x.ActionDescriptor.ControllerDescriptor.ControllerName == controller);

List<APIEndPointDetail> apiEndPointDetails = null;

if (apis.ToList().Count > 0)

{

apiEndPointDetails = new List<APIEndPointDetail>();

foreach (var api in apis)

{

apiEndPointDetails.Add(getAPIEndPointDetail(api));

}

}

else

{

controller = string.Format("The {0} api does not exist.",controller);

}

return new APIEndPoint(controller,apiEndPointDetails);

}

static APIEndPointDetail getAPIEndPointDetail(ApiDescription api) {

if (api.ParameterDescriptions.Count > 0)

{

var parameters = new List<APIEndPointParameter>();

foreach (var parameter in api.ParameterDescriptions)

{

parameters.

Add(new APIEndPointParameter(parameter.Name, parameter.Documentation, parameter.Source.ToString()));

}

return new APIEndPointDetail(api.RelativePath, api.Documentation, api.HttpMethod.Method, parameters);

}

else

{

return new APIEndPointDetail(api.RelativePath, api.Documentation, api.HttpMethod.Method);

}

}

}

[DataContract]

public class APIEndPoint {

[DataMember] public string Name { get; private set; }

[DataMember] public List<APIEndPointDetail> APIEndPointDetails { get; private set; }

public APIEndPoint(string name, List<APIEndPointDetail> apiEndPointDetails)

{

Name = name;

APIEndPointDetails = apiEndPointDetails;

}

}

[DataContract]

public class APIEndPointDetail

{

[DataMember]

public string RelativePath { get; private set; }

[DataMember]

public string Documentation { get; private set; }

[DataMember]

public string Method { get; private set; }

[DataMember]

public List<APIEndPointParameter> Parameters { get; private set; }

public APIEndPointDetail(string relativePath, string documentation, string method,

List<APIEndPointParameter> parameters) : this(relativePath, documentation, method)

{

Parameters = parameters;

}

public APIEndPointDetail(string relativePath, string documentation, string method)

{

RelativePath = relativePath;

Documentation = documentation;

Method = method;

}

}

[DataContract]

public class APIEndPointParameter

{

[DataMember]

public string Name { get; set; }

[DataMember]

public string Documentation { get; private set; }

[DataMember]

public string Source { get; private set; }

public APIEndPointParameter(string name, string documentation, string source)

{

Name = name;

Documentation = documentation;

Source = source;

}

}

}

With the everything in place, including all of the things outlined in Yao’s post, with this url:
http://localhost:18950/api/help?api=Products – the following is the api documenation for the Products API:

{

"Name":"Products",

"APIEndPointDetails":[

{

"RelativePath":"api/Products",

"Documentation":"Returns the Product Collection.",

"Method":"GET"

},

{

"RelativePath":"api/Products/{id}",

"Documentation":"Returns an individual Product.",

"Method":"GET",

"Parameters":[

{

"Name":"id",

"Documentation":"The Product id.",

"Source":"FromUri"

}

]

},

{

"RelativePath":"api/Products",

"Documentation":"Deletes the Products Collection and reverts back to original state.",

"Method":"DELETE"

},

{

"RelativePath":"api/Products/{id}",

"Documentation":"Deletes an individual Product.",

"Method":"DELETE",

"Parameters":[

{

"Name":"id",

"Documentation":"The Product id.",

"Source":"FromUri"

}

]

},

{

"RelativePath":"api/Products",

"Documentation":"Updates an individual Product.",

"Method":"PUT",

"Parameters":[

{

"Name":"product",

"Documentation":"The Product object.",

"Source":"FromBody"

}

]

},

{

"RelativePath":"api/Products",

"Documentation":"Creates a new Product.",

"Method":"POST",

"Parameters":[

{

"Name":"product",

"Documentation":"The Product object.",

"Source":"FromBody"

}

]

}

]

}

And if XML is your thing, no problem. Simply set the content-type header to application/xml:

<APIEndPoint xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/WebAPI">

<APIEndPointDetails>

<APIEndPointDetail>

<Documentation>Returns the Product Collection.</Documentation>

<Method>GET</Method>

<Parameters i:nil="true" />

<RelativePath>api/Products</RelativePath>

</APIEndPointDetail>

<APIEndPointDetail>

<Documentation>Returns an individual Product.</Documentation>

<Method>GET</Method>

<Parameters>

<APIEndPointParameter>

<Documentation>The Product id.</Documentation>

<Name>id</Name>

<Source>FromUri</Source>

</APIEndPointParameter>

</Parameters>

<RelativePath>api/Products/{id}</RelativePath>

</APIEndPointDetail>

<APIEndPointDetail>

<Documentation>Deletes the Products Collection and reverts back to original state.</Documentation>

<Method>DELETE</Method>

<Parameters i:nil="true" />

<RelativePath>api/Products</RelativePath>

</APIEndPointDetail>

<APIEndPointDetail>

<Documentation>Deletes an individual Product.</Documentation>

<Method>DELETE</Method>

<Parameters>

<APIEndPointParameter>

<Documentation>The Product id.</Documentation>

<Name>id</Name>

<Source>FromUri</Source>

</APIEndPointParameter>

</Parameters>

<RelativePath>api/Products/{id}</RelativePath>

</APIEndPointDetail>

<APIEndPointDetail>

<Documentation>Updates an individual Product.</Documentation>

<Method>PUT</Method>

<Parameters>

<APIEndPointParameter>

<Documentation>The Product object.</Documentation>

<Name>product</Name>

<Source>FromBody</Source>

</APIEndPointParameter>

</Parameters>

<RelativePath>api/Products</RelativePath>

</APIEndPointDetail>

<APIEndPointDetail>

<Documentation>Creates a new Product.</Documentation>

<Method>POST</Method>

<Parameters>

<APIEndPointParameter>

<Documentation>The Product object.</Documentation>

<Name>product</Name>

<Source>FromBody</Source>

</APIEndPointParameter>

</Parameters>

<RelativePath>api/Products</RelativePath>

</APIEndPointDetail>

</APIEndPointDetails>

<Name>Products</Name>

</APIEndPoint>

Enjoy…

 

More

.NET Framework Cleanup Tool User's Guide

Introduction

This .NET Framework cleanup tool is designed to automatically perform a set of steps to remove selected versions of the .NET Framework from a computer.  It will remove files, directories, registry keys and values and Windows Installer product registration information for the .NET Framework.  The tool is intended primarily to return your system to a known (relatively clean) state in case you are encountering .NET Framework installation, uninstallation, repair or patching errors so that you can try to install again.

There are a couple of very important caveats that you should review before using this tool to remove any version of the .NET Framework from your system:

  • This tool is designed as a last resort for cases where install, uninstall, repair or patch installation did not succeed for unusual reasons.  It is not a substitute for the standard uninstall procedure.  You should try the steps listed in this blog post before using this cleanup tool.
  • This cleanup tool will delete shared files and registry keys used by other versions of the .NET Framework.  If you run the cleanup tool, you will need to perform a repair/re-install for all other versions of the .NET Framework that are on your computer or they will not work correctly afterwards.

Download location

The .NET Framework cleanup tool is available for download at the following locations:

The .zip file that contains the tool also contains a file named history.txt that lists when the most recent version of the tool was published and what changes have been made to the tool over time.

Supported products

The .NET Framework cleanup tool supports removing the following products:

  • .NET Framework - All Versions
  • .NET Framework - All Versions (Tablet PC and Media Center)
  • .NET Framework - All Versions (Windows Server 2003)
  • .NET Framework - All Versions (Windows Vista and Windows Server 2008)
  • .NET Framework - All Versions (Windows 7)
  • .NET Framework - All Versions (Windows 8)
  • .NET Framework 1.0
  • .NET Framework 1.1
  • .NET Framework 2.0
  • .NET Framework 3.0
  • .NET Framework 3.5
  • .NET Framework 4
  • .NET Framework 4.5

Not all of the above products will appear in the UI for the .NET Framework cleanup tool on every operating system.  The cleanup tool contains logic so that if it is run on an OS version that includes the .NET Framework as an OS component, it will not offer the option to clean it up.  This means that running the cleanup tool on Windows XP Media Center Edition or Tablet PC Edition will not offer the option to clean up the .NET Framework 1.0, running it on Windows Server 2003 will not offer the option to clean up the .NET Framework 1.1 and running it on Windows Vista or Windows Server 2008 will not offer the option to clean up the .NET Framework 2.0 or the .NET Framework 3.0.

When choosing to remove any of the above versions of the .NET Framework, the cleanup tool will also remove any associated hotfixes and service packs.  You do not need to run any separate steps to remove the service pack(s) for a version of the .NET Framework.

Silent installation mode

The .NET Framework cleanup tool supports running in silent mode.  In this mode, the tool will run without showing any UI, and the user must pass in a version of the .NET Framework to remove as a command line parameter.  To run the cleanup tool in silent mode, you need to download the cleanup tool, extract the file cleanup_tool.exe from the zip file, and then run it using syntax like the following:

cleanup_tool.exe /q:a /c:"cleanup.exe /p <name of product to remove>"

The value that you pass with the /p switch to replace <name of product to remove> in this example must exactly match one of the products listed in theSupported products section above.  For example, if you would like to run the cleanup tool in silent mode and remove the .NET Framework 1.1, you would use a command line like the following:

cleanup_tool.exe /q:a /c:"cleanup.exe /p .NET Framework 1.1"

One important note – as indicated above, the cleanup tool will not allow you to remove a version of the .NET Framework that is installed as part of the OS it is running on.  That means that even if you try this example command line on Windows Server 2003, the tool will exit with a failure return code and not allow you to remove the .NET Framework 1.1 because it is a part of that OS.

Similarly, you cannot use the cleanup tool to remove the .NET Framework 1.0 from Windows XP Media Center Edition or Windows XP Tablet PC Edition or remove the .NET Framework 2.0 or 3.0 from Windows Vista or Windows Server 2008.  In addition, if you run the cleanup tool on an OS that has any edition of the .NET Framework installed as a part of the OS, it will prevent you from using the .NET Framework - All Versions option because there is at least one version that it cannot remove.

If you are planning to run the cleanup tool in silent mode, you need to make sure to detect what OS it is running on and not pass in a version of the .NET Framework with the /p switch that is a part of the OS or make sure that you know how to handle the failure exit code that you will get back from the cleanup tool in that type of scenario.

Unattended installation mode

The .NET Framework cleanup tool supports running in silent mode.  In this mode, the tool will run and only show a progress dialog during removal, but will require no user interaction.  Unattended mode requires the user to pass in a version of the .NET Framework to remove as a command line parameter.  To run the cleanup tool in unattended mode, you need to download the cleanup tool, extract the file cleanup_tool.exe from the zip file, and then run it using syntax like the following:

cleanup_tool.exe /q:a /c:"cleanup.exe /p <name of product to remove> /u"

For example, if you would like to run the cleanup tool in unattended mode and remove the .NET Framework 1.1, you would use a command line like the following:

cleanup_tool.exe /q:a /c:"cleanup.exe /p .NET Framework 1.1 /u"

Exit codes

The cleanup tool can returns the following exit codes:

  • 0 - cleanup completed successfully for the specified product
  • 3010 - cleanup completed successfully for the specified product and a reboot is required to complete the cleanup process
  • 1 - cleanup tool requires administrative privileges on the machine
  • 2 - the required file cleanup.ini was not found in the same path as cleanup.exe
  • 3 - a product name was passed in that cannot be removed because it is a part of the OS on the system that the cleanup tool is running on
  • 4 - a product name was passed in that does not exist in cleanup.ini
  • 100 - cleanup was able to start but failed during the cleanup process
  • 1602 - cleanup was cancelled

Log files

The cleanup tool creates the following log files:

  • %temp%\cleanup_main.log - a log of all activity during each run of the cleanup tool; this is a superset of the logs listed below as well as some additional information
  • %temp%\cleanup_actions.log - a log of actions taken during removal of each product; it will list files that it finds and removes, product codes it tries to remove, registry entries it tries to remove, etc.
  • %temp%\cleanup_errors.log - a log of errors and warnings encountered during each run of the cleanup tool

More

Wednesday, August 1, 2012

It is often good idea to isolate our domain model from consuming applications by using service layer and data transfer objects (DTO) or application specific models. Using DTO-s means that we need two-way mapping between domain classes and DTO-s. In this posting I will show you how to use AutoMapper to build generic base class for your mappers.

AutoMapper

AutoMapper is powerful object to object mapper that is able to do also smart and complex mappings between objects. Also you can modify existing and define your own mappings. Although it is possible to write way faster lightweight mappers still AutoMapper offers very good performance considering all the nice features it provides.

What’s most important – AutoMapper is easy to use and it fits perfect to the context of this posting.

Why mapping?

To those who have no idea about the problem scope I explain a little bit why mapping between domain classes and application specific models or DTO-s is needed. Often domain classes have complex dependencies between each other and they may also have complex dependencies with their technical environment. Domain classes may have cyclical references that makes it very hard to serialize them to text based formats. And domain classes may be hard to create.

By example, if you are using vendor offered powerful grid component then this component may want to serialize its data source so it can use it on client side to provide quick sorting and filtering of grid data. Moving from server to client means serialization to JSON or XML. If our domain objects have cyclical references (and it is normal they have) then we are in trouble. We have to use something lighter and less powerful, so we use DTO-s and models.

If you go through all complexities mentioned before you will find more issues with using domain classes as models. As we have to use lightweight models we need mappings between domain classes and models.

Base mapper

Instead of writing mapper for each type-pair mappings you can avoid writing many lines of repeating code when using AutoMapper. Here is my base class for mappers.


public abstract class BaseMapper<T, U> where T : BaseEntity where U : BaseDto, new()
{
protected IMappingExpression<U, T> DtoToDomainMapping { get; private set; }
protected IMappingExpression<T, U> DomainToDtoMapping { get; private set; }

public BaseMapper()
{
DomainToDtoMapping = Mapper.CreateMap<T, U>();

var mex = Mapper.CreateMap<U, T>()
.ForMember(m => m.Id, m => m.Ignore());

var refProperties = from p in typeof(T).GetProperties()
where p.PropertyType.BaseType == typeof(BaseEntity)
select p;

foreach (var prop in refProperties)
{
mex.ForMember(prop.Name, m => m.Ignore());
}

Mapper.CreateMap<PagedResult<T>, PagedResult<U>>()
.ForMember(m => m.Results, m => m.Ignore());
}

public U MapToDto(T instance)
{
if (instance == null)
return null;

var dto = new U();

Mapper.Map(instance, dto);

return dto;
}

public IList<U> MapToDtoList(IList<T> list)
{
if (list == null)
return new List<U>();

var dtoList = new List<U>();

Mapper.Map(list, dtoList);

return dtoList;
}

public PagedResult<U> MapToDtoPagedResult(PagedResult<T> pagedResult)
{
if (pagedResult == null)
return null;

var dtoResult = new PagedResult<U>();
Mapper.Map(pagedResult, dtoResult);
Mapper.Map(pagedResult.Results, dtoResult.Results);

return dtoResult;
}

public void MapFromDto(U dto, T instance)
{
Mapper.Map(dto, instance);
}
}






It does all the dirty work and in most cases it provides all functionality I need for type-pair mapping.

In constructor I define mappings for domain class to model and model to domain class mapping. Also I define mapping for PagedResult – this is the class I use for paged results. If inheriting classes need to modify mappings then they can access protected properties.

Also notice how I play with domain base class: the code avoids situations where AutoMapper may overwrite ID-s and properties that extend domain base class. When you start using mapping then you very soon find out how bad mess AutoMapper can create if you don’t use it carefully.

Methods of mapper base:


  • MapToDto – takes domain object and returns mapped DTO.
  • MapToDtoList – takes list of domain objects and returns list of DTO-s.
  • MapToDtoPagedResult – takes paged result with domain objects and returns paged result with DTO-s.
  • MapFromDto – maps DTO properties to domain object.

If you need more mapping helpers you can upgrade my class with your own code.

Example

To give you better idea about how to extend my base class here is the example.



public class FillLevelMapper : BaseMapper<FillLevel, FillLevelDto>
{
public FillLevelMapper()
{
DomainToDtoMapping.ForMember(
l => l.Grade, m => m.MapFrom(l => l.Grade.GradeNo)
);
}
}






Mapper classes extend from BaseMapper and add their specifics to mappings that base mapper doesn’t provide.

Conclusion

Mapping is also one repeating patterns in many systems. After building some mappers from zero you start recognizing parts they have in common. I was able to separate common operations of my mappers to base class using generics and AutoMapper. Mapper classes are very thin and therefore also way easier to test. AutoMapper makes a lot of dirty work for me that is otherwise time consuming to code. Of course, by all it’s power you must use AutoMapper carefully so it doesn’t do too much work.

More

Thursday, July 26, 2012

Introduction:

Application performance is the very important factor for an application success. Yahoo's Best Practices for Speeding Up Your Web Site is a great resource for increasing your application performance. Out of these practices, 'Putting Stylesheets at the Top','Putting Scripts at the Bottom' and 'Minifying(external and inline) JavaScript and CSS' are very important practices. Minifying inline css and js is also very important. From Yahoo Best Practices page 'In addition to minifying external scripts and styles, inlined <script> and <style> blocks can and should also be minified. Even if you gzip your scripts and styles, minifying them will still reduce the size by 5% or more. As the use and size of JavaScript and CSS increases, so will the savings gained by minifying your code '. So, in this article, I will show you how to minify and bundle(combine all css/js) your inline css/js.

Description:

Open your ASP.NET application(WebForm or MVC) and install BundleMinifyInlineJsCss nuget package.

                    Then register the response filter. If you are using WebForm, you can register response filter in a master page and if you are MVC, you can use register response filter in an action filter.  

   1:  public partial class SiteMaster : System.Web.UI.MasterPage
   2:  {
   3:      protected void Page_Load(object sender, EventArgs e)
   4:      {
   5:          Response.Filter = new BundleAndMinifyResponseFilter(Response.Filter);
   6:      }
   7:  }
   8:   
   9:  public class BundleMinifyInlineCssJsAttribute : ActionFilterAttribute
  10:  {
  11:      public override void OnActionExecuting(ActionExecutingContext filterContext)
  12:      {
  13:          filterContext.HttpContext.Response.Filter = new BundleAndMinifyResponseFilter(filterContext.HttpContext.Response.Filter);
  14:      }
  15:  }
  16:   
  17:  [BundleMinifyInlineCssJs]
  18:  public class HomeController : Controller
 


Now just run your application. If a page view-source is,


After using the above response filter, it will become,

.

Note in the above screen the inline css moved to top, inline javascript moved to bottom and inline javascript/css is minified and bundled. 

Summary:

In this article, I showed you how to you quickly and easily put all your inline css at the top, put all your js at bottom and minifying/bundle all your inline  javascript/css using a response filter. Hopefully you will enjoy this article too.

More

Tuesday, July 24, 2012

I’ve been doing more JavaScript lately than I have in the past and am starting to take a closer look at semantics. In particular, the strange looking exactly equal operator with the three equal signs, ===. Someone who’s been working a career of C, C++, Java, and C# might not be familiar with exactly equalbecause equality in these languages is already strongly typed.

The point is that JavaScript is not strongly typed, so the development experience is different. The subject of this post addresses the typing issue associated with equality and the meaning of the JavaScript exactly equal operator.

The primary difference between the equal, ==, and exactly equal, ===, operator is typing. They both test for equality, but exactly equal tests for type too.  Here’s an example:

var fiveInt = 5;
var fiveString = "5";

var equal = fiveInt == fiveString;
var exactlyEqual = fiveInt === fiveString;


In the code above, fiveInt is a integer type and fiveString is a string type.  The equal operator expression sets the equal variable to true.  However, the exactly equal operator expression sets the exactlyEqual variable tofalse.  The exactly equal operator expression in the example above results in false because it’s comparing two variables that are different types.

Most of the time, it seems like exactly equals is what you should do because it’s safer and avoids errors through false positives. However, I can see where equals would be useful for when reading screen input that is read as a string and being able to make a quick comparison without the extra conversion/validation code that would be required in C#.

More

Monday, July 16, 2012

There are many times in .NET where we have an instance of a value type that we need to treat as optional.  That is, we may want to consider its value as being supplied or missing.

The System.Nullable<T> structure in the .NET Framework can be used to represent these situations in a consistent and meaningful way.

Why Do We Use Nullable<T>?

With instances of reference types, you can easily denote an optional item by simply leaving the reference as null, but this isn’t really possible with a value type (that is, not directly), because the instance of a value type always has a value.

For example, if you had an Person class with some basic data:

   1: public class Person
   2: {
   3:     public string FirstName { get; set; }
   4:     public string LastName { get; set; }
   5:     public int YearsRetired { get; set; }
   6:  
   7:     // ...
   8: }

We could have a person with no first name (Sting, Madonna, etc… or is that no last name?), simply by setting the string property FirstName tonull:



   1: aPerson.FirstName = null;

But in the case of YearsRetired, if the person hasn’t retired yet, we can’t set a simple int to null, because an int is a value type, which must always have a value (strictly speaking):



   1: // compiler error
   2: aPerson.YearsRetired = null;

That said, we could use a sentinel value (-1), or have a separate bool field (IsRetired) to say whether we should use this field or not, but these get messy and harder to maintain.  Consider that if you use a sentinel value, everyone who uses this field must know what that value would be and to test for it.


Alternatively, if you use a bool field to tell you if the value field is usable, they aren’t encapsulated, so again there could be usage issues or consistency issues in naming, etc.


This is why Nullable<T> exists, to allow you to easily mark value type instances as optional (“nullable”) by providing a mechanism that gives values types something like null semantics in an encapsulated and uniform way.


In this way, anyone who looks at your interface and sees Nullable<int> (can also be abbreviated int?) will know how to test whether it has a valid value or not.


How the Nullable<T> struct Works


When you have a Nullable<T> wrapped type in the .NET Framework, it doesn’t give you a reference which you can make null.  It actually is a simple struct (value type) that wraps your value type.  This is an important distinction because it clears up some common misconceptions on what the Nullable<T> type does and does not do.


For example, let’s say you have:



   1: // or int? for short…
   2: Nullable<int> yearsRetired = null;

What really is yearsRetired?  Is it a reference that points to nothing?  No, it’s actually an instance of a value type with two fields: HasValue, and Value.  Note: for you C++ boost library users out there, this is much like how boost::optional<T> works.


The HasValue field is a bool that tells you whether or not Value contains a valid value, and the Value field contains the value set by the user.  Also, to make sure that you use the type correctly, if you attempt to access Value directly when HasValue is false, you will get anInvalidOperationException.


So as you can see, this mimics the behavior of a reference type in some ways, but not others.  For example, you won’t save any space having an “empty” Nullable<BigHonkingStruct>.  The Value field still has the space for a BigHonkingStruct, it’s just inaccessible (that is, it always has a value, it just may not be a valid – i.e. user assigned -- value).


This may be confusing, because while you think you are setting a field to a null, it’s really just compiler magic.  For example, you can do this:



   1: int? yearsRetired = null;
   2:  
   3: if (yearsRetired == null)
   4: {
   5:     Console.WriteLine(“Active Employee”);
   6: }

But this is just syntactical sugar that actually just converts the usage of null to mimic calls against HasValue and Value:



   1: int? yearsRetired = default(int?);     // creates with HasValue = false, Value = default(int)
   2:  
   3: if (yearsRetired.HasValue == false)
   4: {
   5:     Console.WriteLine(“Active Employee”);
   6: }

So don’t be fooled into thinking Nullable<T> magically saves space for “null” instances of large value types.  In fact, if you have a struct so large that you are worried about wasted space, consider a class instead (see C# Fundamentals: The Differences between Struct and Class for more details).


Getting a Default Value


Many times while you are using a Nullable<T> instance, you may find yourself writing code like this:



   1: int cost = 0;
   2:  
   3: if (contractSize.HasValue)
   4: {
   5:     // you can do math on Nullable<int> directly, with caveats…
   6:     cost = contractSize * price;
   7: }
   8:  
Which you could shorten down using a conditional, of course:

   1: int cost = (contractSize.HasValue ? contractSize.Value : 100) * price;

That is, you want to use the value of a Nullable<T> in an expression, or a stand-in if the instance is “null”.  Either way so far, it looks a wee bit ugly, but there are a few ways we can clean this code up.


Nullable<T> has a method GetValueOrDefault() that allows you to retrieve the value if it exists, or the default specified if not.  It has two forms:



  • GetValueOrDefault()

    • Returns Value if HasValue is true, or default(T) if not.

  • GetValueOrDefault(T defaultValue)

    • Returns Value if HasValue is true, or defaultValue if not.

Thus, the code we wrote above could more concisely be written as:



   1: int cost = contractSize.GetValueOrDefault(100) * price;

Ah, much cleaner!  In addition, if you want the defaultValue to be whatever the default is for the given type, you can just call it without any parameter.



   1: // these evaluate to same value, because 0 is default for int.
   2: int cost1 = contractSize.GetValueOrDefault(0) * price;
   3: int cost2 = contractSize.GetValueOrDefault() * price;  

Nullable<T> and the Null-coalescing operator


Another nice thing C# did in .NET 2.0 was to add a null-coalescing operator (??) to get the value of a reference type if non-null, or a stand-in value if null.  They also performed some syntactical candy to allow this to work with Nullable<T> as well.  Basically, this behaves very similarly to using GetValueOrDefault():



   1: Console.WriteLine(“ The contract size is: {0}”, contractSize ?? 100);

The main thing to note here is that ?? is very low on the operator precedence, so if instead you had typed this:



   1: // compiler error, thinks you are trying to ?? between string and int
   2: Console.WriteLine(“The contract size is: “ + contractSize ?? 100);

You’d get an error, because it first tries to concatenate the string and contractSize, which results in a string, and then attempts to null-coalesce a string with an int value, which is invalid.  That is, it thought you wanted this:



   1: // + has higher precedence than ??
   2: Console.WriteLine((“The contract size is: “ + contractSize) ?? 100);

So when you use ?? in an expression, make sure you surround it in parenthesis where appropriate to make sure it is performed in the order you really mean:



   1: Console.WriteLine(“The contract size is: “ + (contractSize ?? 100));

Nullable Math Doesn’t Always Add Up


Finally, there are some interesting results when you attempt to use an arithmetic or logical comparison operator overload on a Nullable<T>wrapping a T that has those operators.  That is, if you have:



   1: int? x = null;
   2:  
   3: if ((x * 5) < 100)
   4: {
   5:     // ...
   6: }
   7:  

What will the result be?  It turns out false because the operator * between null and 5 returns null, and null has no meaningful order so <returns false.  In essence, this is modeled to behave much like SQL expressions with null values.  The long and the short of the matter is that math with a null numeric type yields null, and an ordered logical comparison with a null yields false.


For more details, I have a post titled C#/.NET Little Pitfalls: Nullable Math Doesn’t Always Add Up which you can dig into for more information on why this happens.


Summary


The Nullable<T> is a handy structure that was created to give us a consistent way to handle “optional” instances of value types. Nullable<T>instances can be assigned to null or compared with null, which really is syntactical sugar which creates a default instance or checks theHasValue property respectively.


In addition, you can use the GetValueOrDefault() method or the null-coalescing operator (??) to query the value, or provide a substitute if the value was never set.


 


More