Creare App per Windows Phone 8


Oggi è stato pubblicato il libro di Enrico Rossini Creare App per Windows Phone 8 Concetti di base.

Nel mercato degli smartphone è arrivato da qualche tempo il nuovo sistema operativo di Microsoft, Windows Phone, che rappresenta un taglio netto con il passato: nuova architettura, nuova user experience, nuova grafica e anche nuovi strumenti di sviluppo. Con questo libro, partendo dalle basi fino ad arrivare agli aspetti più avanzati, scopriamo tutte le caratteristiche della piattaforma e quali sono gli strumenti che abbiamo a disposizione per creare applicazioni originali e innovative. Dai sensori (accelerometro, GPS, NFC ecc.) alla rete, passando per notifiche, tile e accesso ai dati. Il libro è basato sulla versione più recente della piattaforma, Windows Phone 8 che, rispetto alla release originale, ha portato a un profondo rinnovamento dell’architettura e ha introdotto moltissime novità sia per gli utenti sia per gli sviluppatori.

In questo primo volume si affrontano tutti i più importanti aspetti della programmazione con Visual Studio nella versione 2012 o 2013 fino ad utilizzare tutti i componenti base messi a disposizione e l'utilizzo del Windows Phone Toolkit. I concetti qui illustrati possono essere utilizzati per Windows Phone 8, Windows Phone 8.1 e Windows 8.

Serving WebP images with ASP.NET MVC

Speed is a feature and one thing that can slow down web apps is clients waiting to download images. To speed up image downloads and conserve bandwidth, the good folks of Google have come up with a new image format called WebP (“weppy”). WebP images are around 25% smaller in size than equivalent images encoded with JPEG and PNG (WebP supports both lossy and lossless compression) with no worse perceived quality.

This blog post shows how to dynamically serve WebP-encoded images from ASP.NET to clients that support the new format.

One not-so-great way of doing this is to serve different HTML depending on whether clients supports WebP or not, as described in this blog post. As an example, clients supporting WebP would get HTML with <img src="image.webp"/> while other clients would get <img src="image.jpeg"/>. The reason this sucks is that the same HTML cannot be served to all clients, making caching harder. It will also tend to pollute your view code with concerns about what image formats are supported by browser we’re rendering for right now.

Instead, images in our solution will only ever have one url and the content-type of responses depend on the capabilities of the client sending the request: Browsers that support WebP get image/webp and the rest get image/jpeg.

I’ll first go through creating WebP-encoded images in C#, then tackle the challenge of detecting browser image support and round out the post by discussing implications for CDN use.

Serving WebP with ASP.NET MVC

For the purposes of this article, we’ll assume that we want to serve images from an URI like /images/:id where :id is some unique id of the image requested. The id can be used to fetch a canonical encoding of the image, either from a file system, a database or some other backing store. In the code I wrote to use this, the images are stored in a database. Once fetched from the backing store, the image is re-sized as desired, re-encoded and served to the client.

At this point, some readers are probably in uproar: “Doing on-the-fly image fetching and manipulation is wasteful and slow” they scream. That’s not really the case though, and even if it were, the results can be cached on first request and then served quickly.

Assume we have an Image class and method GetImage(int id) to retrieve images:

private class Image
{
public int Id { get; set; }
public DateTime UpdateAt { get; set; }
public byte[] ImageBytes { get; set; }
}

We’ll now use the managed API from ImageResizer to resize the image to the desired size and then re-encode the result to WebP using Noesis.Drawing.Imaging.WebP.dll (no NuGet package, unfortunately).

public ActionResult Show(int imageId)
{
var image = GetImage(imageId);

var resizedImageStream = new MemoryStream();
ImageBuilder.Current.Build(image.ImageBytes, resizedImageStream, new ResizeSettings
{
Width = 500,
Height = 500,
Mode = FitMode.Crop,
Anchor = System.Drawing.ContentAlignment.MiddleCenter,
Scale = ScaleMode.Both,
});

var resultStream = new MemoryStream();
WebPFormat.SaveToStream(resultStream, new SD.Bitmap(resizedImageStream));
resultStream.Seek(0, SeekOrigin.Begin);

return new FileContentResult(resultStream.ToArray(), "image/webp");
}

System.Drawing is referenced using using SD = System.Drawing;. The controller action above is fully functional and can serve up sparkling new WebP-formatted images.


Browser support


Next up is figuring out whether the browser requesting an image actually supports WebP, and if it doesn’t, respond with JPEG. Luckily, this doesn’t involve going back to the bad old days of user-agent sniffing. Modern browsers that support WebP (such as Chrome and Opera) send image/webp in the accept header to indicate support. Ironically given that Google came up with WebP, the Chrome developers took a lot of convincing to set that header in requests, fearing request size bloat. Even now, Chrome only advertises webp support for requests that it thinks is for images. In fact, this is another reason the “different-HTML” approach mentioned in the intro won’t work: Chrome doesn’t advertise WebP support for requests for HTML.


To determine what content encoding to use, we inspect Request.AcceptTypes. The resizing code is unchanged, while the response is generated like this:

	var resultStream = new MemoryStream();
var webPSupported = Request.AcceptTypes.Contains("image/webp");
if (webPSupported)
{
WebPFormat.SaveToStream(resultStream, new SD.Bitmap(resizedImageStream));
}
else
{
new SD.Bitmap(resizedImageStream).Save(resultStream, ImageFormat.Jpeg);
}

resultStream.Seek(0, SeekOrigin.Begin);
return new FileContentResult(resultStream.ToArray(), webPSupported ? "image/webp" : "image/jpeg");

That’s it! We now have a functional controller action that responds correctly depending on request accept headers. You gotta love HTTP. You can read more about content negotiation and WebP on lya Grigorik’s blog.


Client Caching and CDNs


Since it does take a little while to perform the resizing and encoding, I recommend storing the output of the transformation in HttpRuntime.Cache and fetching from there in subsequent requests. The details are trivial and omitted from this post.


There is also a bunch of ASP.NET cache configuration we should do to let clients cache images locally:

	Response.Cache.SetExpires(DateTime.Now.AddDays(365));
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetMaxAge(TimeSpan.FromDays(365));
Response.Cache.SetSlidingExpiration(true);
Response.Cache.SetOmitVaryStar(true);
Response.Headers.Set("Vary",
string.Join(",", new string[] { "Accept", "Accept-Encoding" } ));
Response.Cache.SetLastModified(image.UpdatedAt.ToLocalTime());

Notice that we set the Vary header value to include “Accept” (as well as “Accept-Encoding”). This tells CDNs and other intermediary caching proxies that if they try to cache this response, they must vary the cached value based on value of the “Accept” header of the request. This works for “Accept-Encoding”, so that different values can cached based on whether the response is compressed with gzip, deflate or not at all, and all major CDNs support it. Unfortunately, the mainstream CDNs I experimented with (CloudFront and Azure CDN) don’t support other Vary values than “Accept-Encoding”. This is really frustrating, but also somewhat understandable from the standpoint of the CDN folks: If all Vary values are honored, the number of artifacts they have to cache would increase at a combinatorial rate as browsers and servers make use of cleverer caching. Unless you find a CDN that specifically support non-Accept-Encoding Vary values, don’t use a CDN when doing this kind of content negotiation.


That’s it! I hope this post will help you build ASP.NET web apps that serve up WebP images really quickly.


Display list of files from Server folder in ASP.Net GridView

In this article I will explain how we can save and retrieve files from Windows Folder and Directory and display them in ASP.Net GridView control with download and delete option.

 

HTML Markup

Below is the HTML Markup of the page, where I have an ASP.Net control FileUpload to upload files, a Buttoncontrol to trigger file uploads and an ASP.Net GridViewcontrol to display the files from folder.

    <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" EmptyDataText="No files uploaded">
<Columns>
<asp:BoundField DataField="Text" HeaderText="File Name" />
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton ID="lnkDownload" Text="Download" CommandArgument='<%# Eval("Value") %>' runat="server" OnClick="DownloadFile"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton ID="lnkDelete" Text="Delete" CommandArgument='<%# Eval("Value") %>' runat="server" OnClick="DeleteFile" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>




You will need to import the following namespaces for C# and VB.NET

using System.IO;
or
Imports System.IO



Uploading the File and saving in directory or folder


When the file is selected in APS.Net FileUpload control and the Upload button is clicked the following event handler is triggered. Below I have folder Uploads in the root directory of my ASP.Net Website where I am saving the uploaded file.

C#

protected void UploadFile(object sender, EventArgs e)
{
string fileName = Path.GetFileName(FileUpload1.PostedFile.FileName);
FileUpload1.PostedFile.SaveAs(Server.MapPath("~/Uploads/") + fileName);
Response.Redirect(Request.Url.AbsoluteUri);
}

VB.NET

Protected Sub UploadFile(ByVal sender As Object, ByVal e As EventArgs)
Dim fileName As String = Path.GetFileName(FileUpload1.PostedFile.FileName)
FileUpload1.PostedFile.SaveAs((Server.MapPath("~/Uploads/") + fileName))
Response.Redirect(Request.Url.AbsoluteUri)
End Sub



 




Displaying the files from folder or directory in ASP.Net GridView


Here I am reading all the files from the Uploads directory which I have created and then binding the fetched files to the ASP.Net GridView control.

C#

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string[] filePaths = Directory.GetFiles(Server.MapPath("~/Uploads/"));
List<ListItem> files = new List<ListItem>();
foreach (string filePath in filePaths)
{
files.Add(new ListItem(Path.GetFileName(filePath), filePath));
}
GridView1.DataSource = files;
GridView1.DataBind();
}
}



VB.NET

Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
If Not IsPostBack Then
Dim filePaths() As String = Directory.GetFiles(Server.MapPath("~/Uploads/"))
Dim files As List(Of ListItem) = New List(Of ListItem)
For Each filePath As String In filePaths
files.Add(New ListItem(Path.GetFileName(filePath), filePath))
Next
GridView1.DataSource = files
GridView1.DataBind()
End If
End Sub



Downloading the Uploaded File from ASP.Net GridView


The following event handler is executed when the lnkDownload LinkButton is clicked in the ASP.Net GridView Row. Using the CommandArgument property of the ASP.Net LinkButton, I get the path of the file using which I am downloading the file.

C#

protected void DownloadFile(object sender, EventArgs e)
{
string filePath = (sender as LinkButton).CommandArgument;
Response.ContentType = ContentType;
Response.AppendHeader("Content-Disposition", "attachment; filename=" + Path.GetFileName(filePath));
Response.WriteFile(filePath);
Response.End();
}



VB.NET

Protected Sub DownloadFile(ByVal sender As Object, ByVal e As EventArgs)
Dim filePath As String = CType(sender, LinkButton).CommandArgument
Response.ContentType = ContentType
Response.AppendHeader("Content-Disposition", ("attachment; filename=" + Path.GetFileName(filePath)))
Response.WriteFile(filePath)
Response.End()
End Sub



Deleting the Uploaded File from ASP.Net GridView


The following event handler is executed when the lnkDelete LinkButton is clicked in the ASP.Net GridView Row. Using the CommandArgument property of the ASP.Net LinkButton, I get the path of the file using which I am deleting the file.

C#

protected void DeleteFile(object sender, EventArgs e)
{
string filePath = (sender as LinkButton).CommandArgument;
File.Delete(filePath);
Response.Redirect(Request.Url.AbsoluteUri);
}



VB.NET

Protected Sub DeleteFile(ByVal sender As Object, ByVal e As EventArgs)
Dim filePath As String = CType(sender, LinkButton).CommandArgument
File.Delete(filePath)
Response.Redirect(Request.Url.AbsoluteUri)
End Sub

How to create simple Background Agent in Windows Phone

This article provides a minimal example on how to create Background Agents (Tasks) in Windows Phone. There is a more comprehensive example on Dev Center How to implement background agents for Windows Phone.

 

Introduction

Windows Phone apps are made dormant when running in the background or when the phone is locked (to conserve device memory and battery life). If your application needs to perform processing when it is (may be) in the background you can use a background agent to run activities according to some schedule.

Background agents are divided into Periodic Tasks and Resource-intensive Tasks. Periodic Task can run for no more than 25 seconds every 30 minutes. This sort of agent is suitable for many common use-cases:

  • Downloading data from remote server and then scheduling notifications (for example, when monitoring twitter or facebook updates)
  • Changing lock screen wallpaper ( like the Bing app)
  • Synchronizing data in the background, for example emails

Apps which require more device resources and/or which do not require a fixed update schedule, can use a resource intensive task. These tasks run when the device is connected to external power and/or connected to a WiFi network - they are very useful when you need to transfer a lot of data or perform some other long running task in the background.

This article provides a very simple example of how to create a Periodic Task.

If you want to also understand Resource-intensive tasks then check out How to implement background agents for Windows Phone (Dev Center). This is more complicated to read, but is more comprehensive and covers both periodic and resource-intensive tasks.

 

Limitations

Background agents have certain limitations, as listed below.

  • Background tasks can minimally be run every 30 minutes. There is a debug-only API to run them more regularly, but this is not available for released apps.
  • There are certain APIs which are not supported , you can check here.
  • Some low power devices do not support background agents
  • Background tasks are limited by number on each device and can be enabled or disabled from application settings.
  • They do not work when power saver mode is activated.

 

Basic requirements

  • You need to create an app project, it can be anything from simple basic windows phone app to panorama or pivot based application.
  • Then create your background agent project in the same solution and add its reference to the main app, with necessary code (which is hardly few lines) you can have your background agent running. You can test agents in the simulator as well.

 

References Required

Following references to the DLLs are required.

  • Microsoft.Xna.Framework.Media

This can be added by Project | References | Add Reference..

 

How to....

  • Create a simple windows phone application project as follows and give some suitable name to it.

Screenshot_(4)

  • Create a scheduled task agent project in Visual Studio, this should be added to the same solution. An easy way to do this is: go to solution explorer of main application, right click on solution and select add, select add project and automatically the project created will get added to the existing solution. Assign some suitable name to the project.

Screenshot_(5)

  • The next step is to add a reference to the main application. This can be done by going to Solution Explorer, right clicking references under main project and selecting the Add Reference option.

Screenshot_(6)

  • Next select Solutions section on the Add Reference dialog and you should be able to see the name of your scheduled task agent project name there select it and its done.

Screenshot_(7)

  • Next open ScheduledAgent.cs file from your background agent project and add following lines of code in OnInvoke() method
  protected override void OnInvoke(ScheduledTask task)
{
 
string toastMessage = "Periodic task running.";
 
ShellToast toast = new ShellToast();
toast.Title = "Background Agent Sample";
toast.Content = toastMessage;
toast.Show();
#if DEBUG_AGENT
ScheduledActionService.LaunchForTest(task.Name,TimeSpan.FromSeconds(60));
#endif
 
NotifyComplete();
}

Once the above code is added the Scheduled Agent or your background task is ready to fire a Toast notification whenever its called. As you may run this app to test, don't forget to add following macro at the top in your ScheduledAgent.cs file

#define DEBUG_AGENT

and after the above macro make sure you have all following namespace imports in place

using System.Diagnostics;
using System.Windows;
using Microsoft.Phone.Scheduler;
using Microsoft.Phone.Shell;
using System;


  • Now next step is to setup this Agent (task) to run in background from your main app, it can be done with the help of following lines of code. Make sure you place them in your MainPage.xaml.cs file of main project, I am attaching the complete file for your exposure to the code.
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using DynaLock.Resources;
using Microsoft.Phone.Scheduler;
 
namespace Application1
{
public partial class MainPage : PhoneApplicationPage
{
PeriodicTask periodicTask;
 
 
string periodicTaskName = "PeriodicAgent";
// Constructor
 
public MainPage()
{
InitializeComponent();
 
// Sample code to localize the ApplicationBar
//BuildLocalizedApplicationBar();
agentsAreEnabled = true;
 
// Obtain a reference to the period task, if one exists
periodicTask = ScheduledActionService.Find(periodicTaskName) as PeriodicTask;
 
if (periodicTask != null)
{
RemoveAgent(periodicTaskName);
}
 
periodicTask = new PeriodicTask(periodicTaskName);
 
// The description is required for periodic agents. This is the string that the user
// will see in the background services Settings page on the device.
periodicTask.Description = "This demonstrates a periodic task.";
 
// Place the call to Add in a try block in case the user has disabled agents.
try
{
ScheduledActionService.Add(periodicTask);
 
// If debugging is enabled, use LaunchForTest to launch the agent in one minute.
#if(DEBUG_AGENT)
ScheduledActionService.LaunchForTest(periodicTaskName, TimeSpan.FromSeconds(10));
#endif
}
catch (InvalidOperationException exception)
{
if (exception.Message.Contains("BNS Error: The action is disabled"))
{
MessageBox.Show("Background agents for this application have been disabled by the user.");
agentsAreEnabled = false;
 
}
 
if (exception.Message.Contains("BNS Error: The maximum number of ScheduledActions of this type have already been added."))
{
// No user action required. The system prompts the user when the hard limit of periodic tasks has been reached.
 
}
 
}
catch (SchedulerServiceException)
{
// No user action required.
}
 
 
}
private void RemoveAgent(string name)
{
try
{
ScheduledActionService.Remove(name);
}
catch (Exception)
{
}
}
}
}

We call LaunchForTest() function only for debugging, which should be remove once your application goes into production environment.

Make sure to remove the DEBUG macro once you are done debugging of the project which will stop calling the agent after every few seconds, which should be done only if you wish to debug the application. If you keep that line it may cause failure in app submission process.

Checking the Internet connection type on Windows Phone

All Windows Phone applications that use Internet data should always check if there is a valid Internet connection; if there is no connection, a proper message should be displayed to the user. The correct way to check if you have an Internet connection (WIFI, Ethernet, or none) is by checking the property:

NetworkInterface.NetworkInterfaceType

Unfortunately checking this property is a synchronous operation, so calling it in the UI thread can block the UI for many seconds.

If your application relies on a specific server you might be tempted to simply check the Internet connection by calling the server. This could result in an inaccurate error message if your server is down, since the Internet may be available.

 


Utility class for checking the connection


The utility class below (included in the sample project) checks the network connection in another thread.

using System.Threading;
using Microsoft.Phone.Net.NetworkInformation;
 
namespace DotNetApp.Utilities
{
public class NetworkTypeEventArgs
{
#region Constructor
 
public NetworkTypeEventArgs(NetworkInterfaceType type, bool hasTimeout = false)
{
Type = type;
HasTimeout = hasTimeout;
}
 
#endregion
 
#region Properties
 
public bool HasTimeout { get; private set; }
 
public bool HasInternet
{
get { return Type != NetworkInterfaceType.None; }
}
 
public NetworkInterfaceType Type { get; private set; }
 
#endregion
}
 
/// <summary>
/// Static class to get the NetworkInterfaceType without blocking the UI thread.
/// </summary>
public static class NetworkInformationUtility
{
#region Fields
 
private static bool _isGettingNetworkType;
private static readonly object _synchronizationObject = new object();
private static Timer _timer;
 
#endregion
 
#region Methods
 
/// <summary>
/// Get the NetworkInterfaceType asynchronously.
/// </summary>
/// <param name="timeoutInMs">Specifies the timeout in milliseconds.</param>
public static void GetNetworkTypeAsync(int timeoutInMs)
{
lock (_synchronizationObject)
{
if (!_isGettingNetworkType)
{
_isGettingNetworkType = true;
 
if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
Thread thread = new Thread(GetNetworkType) {IsBackground = true};
thread.Start(timeoutInMs);
}
else
{
FireGetNetworkTypeCompleted(NetworkInterfaceType.None);
}
}
}
}
 
#endregion
 
#region Delegates
 
public delegate void NetworkTypeEventHandler(object sender, NetworkTypeEventArgs networkTypeEventArgs);
 
#endregion
 
#region Events
 
public static event NetworkTypeEventHandler GetNetworkTypeCompleted;
 
#endregion
 
#region Event Handlers
 
private static void OnTimerElapsed(object state)
{
FireGetNetworkTypeCompleted(NetworkInterfaceType.None, true);
}
 
#endregion
 
#region Private Methods
 
private static void GetNetworkType(object state)
{
_timer = new Timer(OnTimerElapsed, null, (int)state, 0);
 
// This is a blocking call, this is why a thread is used to let the UI to be fluid
NetworkInterfaceType type = NetworkInterface.NetworkInterfaceType;
 
_timer.Dispose();
_timer = null;
 
FireGetNetworkTypeCompleted(type);
}
 
private static void FireGetNetworkTypeCompleted(NetworkInterfaceType type, bool hasTimeout = false)
{
lock (_synchronizationObject)
{
if (_isGettingNetworkType)
{
_isGettingNetworkType = false;
 
NetworkTypeEventHandler networkTypeEventHandler = GetNetworkTypeCompleted;
 
if (networkTypeEventHandler != null)
{
networkTypeEventHandler(null, new NetworkTypeEventArgs(type, hasTimeout));
}
}
}
}
 
#endregion
}
}

Using the utility class


Here are the steps to use this class in your code:


  1. Add the NetworkInformationUtility.cs to your project.
  2. Attach method to the event NetworkInformationUtility.GetNetworkTypeCompleted.
  3. Call NetworkInformationUtility.GetNetworkTypeAsync(3000 /*timeout in ms*/);
  4. Retrieve the result on the GetNetworkTypeCompleted method that you attached to the event.

Code sample:

using System.Windows;
using DotNetApp.Utilities;
 
namespace NetworkInformationApp
{
public partial class MainPage {
public MainPage()
{
InitializeComponent();
}
 
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
 
NetworkInformationUtility.GetNetworkTypeCompleted += GetNetworkTypeCompleted;
 
NetworkInformationUtility.GetNetworkTypeAsync(3000); // Timeout of 3 seconds }
 
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
 
NetworkInformationUtility.GetNetworkTypeCompleted -= GetNetworkTypeCompleted;
}
 
private void GetNetworkTypeCompleted(object sender, NetworkTypeEventArgs networkTypeEventArgs)
{
string message;
 
if (networkTypeEventArgs.HasTimeout)
{
message = "The timeout occurred";
}
else if (networkTypeEventArgs.HasInternet)
{
message = "The Internet connection type is: " + networkTypeEventArgs.Type.ToString();
}
else {
message = "There is no Internet connection";
}
 
// Always dispatch on the UI thread Dispatcher.BeginInvoke(() => MessageBox.Show(message));
}
}
}

Checking network availability in Windows Phone

Many applications utilize network connection for various purposes like feeds, sending & receiving data to/from server, etc. The following article explains how one can detect if the network connection is available or not.

Network API Information

Example Code to understand the network connection

namespace NetworkTest
{
public partial class MainPage : PhoneApplicationPage
{
public static readonly DependencyProperty NetProperty =
DependencyProperty.Register("NetworkAvailability",
typeof(string),
typeof(MainPage),
new PropertyMetadata(string.Empty));
 
public MainPage()
{
InitializeComponent();
string isNetworkAvail =
NetworkInterface.GetIsNetworkAvailable() ? "on" : "off";
}
}
}

Enabling quick resume for Windows Phone apps

This article explains how to quickly resume the Windows Phone 8 application which is put in the background.

 

Introduction

Whenever your app loses focus (is put in the background), an instance of the app is saved. This instance is used to resume the app if the user tasks to it from a deep link or returns to it by selecting the back button on the foreground app. However if the user relaunches the app by selecting its icon on the start screen, by default the stored instance is removed and it is started from scratch.

On Windows Phone 8, Fast App Resume is a way to force a relaunch to use the saved instance rather than fully restart the app. This is much faster. This is not enabled by default and you will need to enable it in order to achieve this functionality in your applications.

 

Enable Fast App Resume

Enabling Fast App Resume is as simple as adding one attribute to an XML element in the manifest file.

  1. Open WMAppManifest.xml in any editor. (I use notepad++)
  2. Find the element DefaultTask
  3. Add the attribute ActivationPolicy="Resume"

You should end up with something that looks like this:

<DefaultTask Name="_default" NavigationPage="MainPage.xaml" ActivationPolicy="Resume"/>

References


Apart from setting param in WMAppManifest.xml, there's also a bit one needs to do in App.xaml.cs in order to make the 'fast app resume' feature work correctly.A nice working example is available on msdn: Fast app resume example

Make the application loosely coupled

In this series of tutorials, we build an entire Contact Management application from start to finish. The Contact Manager application enables you to store contact information - names, phone numbers and email addresses - for a list of people.

We build the application over multiple iterations. With each iteration, we gradually improve the application. The goal of this multiple iteration approach is to enable you to understand the reason for each change.

    Iteration #1 - Create the application. In the first iteration, we create the Contact Manager in the simplest way possible. We add support for basic database operations: Create, Read, Update, and Delete (CRUD).

    Iteration #2 - Make the application look nice. In this iteration, we improve the appearance of the application by modifying the default ASP.NET MVC view master page and cascading style sheet.

    Iteration #3 - Add form validation. In the third iteration, we add basic form validation. We prevent people from submitting a form without completing required form fields. We also validate email addresses and phone numbers.

    Iteration #4 - Make the application loosely coupled. In this third iteration, we take advantage of several software design patterns to make it easier to maintain and modify the Contact Manager application. For example, we refactor our application to use the Repository pattern and the Dependency Injection pattern.

    Iteration #5 - Create unit tests. In the fifth iteration, we make our application easier to maintain and modify by adding unit tests. We mock our data model classes and build unit tests for our controllers and validation logic.

    Iteration #6 - Use test-driven development. In this sixth iteration, we add new functionality to our application by writing unit tests first and writing code against the unit tests. In this iteration, we add contact groups.

    Iteration #7 - Add Ajax functionality. In the seventh iteration, we improve the responsiveness and performance of our application by adding support for Ajax.

This Iteration

In this fourth iteration of the Contact Manager application, we refactor the application to make the application more loosely coupled. When an application is loosely coupled, you can modify the code in one part of the application without needing to modify the code in other parts of the application. Loosely coupled applications are more resilient to change.

Currently, all of the data access and validation logic used by the Contact Manager application is contained in the controller classes. This is a bad idea. Whenever you need to modify one part of your application, you risk introducing bugs into another part of your application. For example, if you modify your validation logic, you risk introducing new bugs into your data access or controller logic.

(SRP), a class should never have more than one reason to change. Mixing controller, validation, and database logic is a massive violation of the Single Responsibility Principle.

There are several reasons that you might need to modify your application. You might need to add a new feature to your application, you might need to fix a bug in your application, or you might need to modify how a feature of your application is implemented. Applications are rarely static. They tend to grow and mutate over time.

Imagine, for example, that you decide to change how you implement your data access layer. Right now, the Contact Manager application uses the Microsoft Entity Framework to access the database. However, you might decide to migrate to a new or alternative data access technology such as ADO.NET Data Services or NHibernate. However, because the data access code is not isolated from the validation and controller code, there is no way to modify the data access code in your application without modifying other code that is not directly related to data access.

When an application is loosely coupled, on the other hand, you can make changes to one part of an application without touching other parts of an application. For example, you can switch data access technologies without modifying your validation or controller logic.

In this iteration, we take advantage of several software design patterns that enable us to refactor our Contact Manager application into a more loosely coupled application. When we are done, the Contact Manager won t do anything that it didn t do before. However, we ll be able to change the application more easily in the future.

Refactoring is the process of rewriting an application in such a way that it does not lose any existing functionality.

Using the Repository Software Design Pattern

Our first change is to take advantage of a software design pattern called the Repository pattern. We ll use the Repository pattern to isolate our data access code from the rest of our application.

Implementing the Repository pattern requires us to complete the following two steps:

  1. Create an interface
  2. Create a concrete class that implements the interface

First, we need to create an interface that describes all of the data access methods that we need to perform. The IContactManagerRepository interface is contained in Listing 1. This interface describes five methods: CreateContact(), DeleteContact(), EditContact(), GetContact, and ListContacts().

Listing 1 - Models\IContactManagerRepositiory.cs

using System;
using System.Collections.Generic;

namespace ContactManager.Models
{
public interface IContactRepository
{
Contact CreateContact(Contact contactToCreate);
void DeleteContact(Contact contactToDelete);
Contact EditContact(Contact contactToUpdate);
Contact GetContact(int id);
IEnumerable<Contact> ListContacts();

}
}

Next, we need to create a concrete class that implements the IContactManagerRepository interface. Because we are using the Microsoft Entity Framework to access the database, we ll create a new class named EntityContactManagerRepository. This class is contained in Listing 2.

Listing 2 - Models\EntityContactManagerRepository.cs

using System.Collections.Generic;
using System.Linq;

namespace ContactManager.Models
{
public class EntityContactManagerRepository : ContactManager.Models.IContactManagerRepository
{
private ContactManagerDBEntities _entities = new ContactManagerDBEntities();

public Contact GetContact(int id)
{
return (from c in _entities.ContactSet
where c.Id == id
select c).FirstOrDefault();
}


public IEnumerable ListContacts()
{
return _entities.ContactSet.ToList();
}


public Contact CreateContact(Contact contactToCreate)
{
_entities.AddToContactSet(contactToCreate);
_entities.SaveChanges();
return contactToCreate;
}


public Contact EditContact(Contact contactToEdit)
{
var originalContact = GetContact(contactToEdit.Id);
_entities.ApplyPropertyChanges(originalContact.EntityKey.EntitySetName, contactToEdit);
_entities.SaveChanges();
return contactToEdit;
}


public void DeleteContact(Contact contactToDelete)
{
var originalContact = GetContact(contactToDelete.Id);
_entities.DeleteObject(originalContact);
_entities.SaveChanges();
}

}
}


Notice that the EntityContactManagerRepository class implements the IContactManagerRepository interface. The class implements all five of the methods described by that interface.

You might wonder why we need to bother with an interface. Why do we need to create both an interface and a class that implements it?

With one exception, the remainder of our application will interact with the interface and not the concrete class. Instead of calling the methods exposed by the EntityContactManagerRepository class, we ll call the methods exposed by the IContactManagerRepository interface.

That way, we can implement the interface with a new class without needing to modify the remainder of our application. For example, at some future date, we might want to implement an DataServicesContactManagerRepository class that implements the IContactManagerRepository interface. The DataServicesContactManagerRepository class might use ADO.NET Data Services to access a database instead of the Microsoft Entity Framework.

If our application code is programmed against the IContactManagerRepository interface instead of the concrete EntityContactManagerRepository class then we can switch concrete classes without modifying any of the rest of our code. For example, we can switch from the EntityContactManagerRepository class to the DataServicesContactManagerRepository class without modifying our data access or validation logic.

Programming against interfaces (abstractions) instead of concrete classes makes our application more resilient to change.

You can quickly create an interface from a concrete class within Visual Studio by selecting the menu option Refactor, Extract Interface. For example, you can create the EntityContactManagerRepository class first and then use Extract Interface to generate the IContactManagerRepository interface automatically.

Using the Dependency Injection Software Design Pattern


Now that we have migrated our data access code to a separate Repository class, we need to modify our Contact controller to use this class. We will take advantage of a software design pattern called Dependency Injection to use the Repository class in our controller.

The modified Contact controller is contained in Listing 3.

Listing 3 - Controllers\ContactController.cs

using System.Text.RegularExpressions;
using System.Web.Mvc;
using ContactManager.Models;

namespace ContactManager.Controllers
{
public class ContactController : Controller
{
private IContactManagerRepository _repository;

public ContactController()
: this(new EntityContactManagerRepository())
{}


public ContactController(IContactManagerRepository repository)
{
_repository = repository;
}


protected void ValidateContact(Contact contactToValidate)
{
if (contactToValidate.FirstName.Trim().Length == 0)
ModelState.AddModelError("FirstName", "First name is required.");
if (contactToValidate.LastName.Trim().Length == 0)
ModelState.AddModelError("LastName", "Last name is required.");
if (contactToValidate.Phone.Length > 0 && !Regex.IsMatch(contactToValidate.Phone, @"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
ModelState.AddModelError("Phone", "Invalid phone number.");
if (contactToValidate.Email.Length > 0 && !Regex.IsMatch(contactToValidate.Email, @"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
ModelState.AddModelError("Email", "Invalid email address.");
}

public ActionResult Index()
{
return View(_repository.ListContacts());
}

public ActionResult Create()
{
return View();
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "Id")] Contact contactToCreate)
{
// Validation logic
ValidateContact(contactToCreate);
if (!ModelState.IsValid)
return View();

// Database logic
try
{
_repository.CreateContact(contactToCreate);
return RedirectToAction("Index");
}
catch
{
return View();
}
}

public ActionResult Edit(int id)
{
return View(_repository.GetContact(id));
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Contact contactToEdit)
{
// Validation logic
ValidateContact(contactToEdit);
if (!ModelState.IsValid)
return View();

// Database logic
try
{
_repository.EditContact(contactToEdit);
return RedirectToAction("Index");
}
catch
{
return View();
}
}

public ActionResult Delete(int id)
{
return View(_repository.GetContact(id));
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Delete(Contact contactToDelete)
{
try
{
_repository.DeleteContact(contactToDelete);
return RedirectToAction("Index");
}
catch
{
return View();
}
}

}
}

Notice that the Contact controller in Listing 3 has two constructors. The first constructor passes a concrete instance of the IContactManagerRepository interface to the second constructor. The Contact controller class uses Constructor Dependency Injection.

The one and only place that the EntityContactManagerRepository class is used is in the first constructor. The remainder of the class uses the IContactManagerRepository interface instead of the concrete EntityContactManagerRepository class.

This makes it easy to switch implementations of the IContactManagerRepository class in the future. If you want to use the DataServicesContactRepository class instead of the EntityContactManagerRepository class, just modify the first constructor.

Constructor Dependency injection also makes the Contact controller class very testable. In your unit tests, you can instantiate the Contact controller by passing a mock implementation of the IContactManagerRepository class. This feature of Dependency Injection will be very important to us in the next iteration when we build unit tests for the Contact Manager application.

If you want to completely decouple the Contact controller class from a particular implementation of the IContactManagerRepository interface then you can take advantage of a framework that supports Dependency Injection such as StructureMap or the Microsoft Entity Framework (MEF). By taking advantage of a Dependency Injection framework, you never need to refer to a concrete class in your code.

Creating a Service Layer


You might have noticed that our validation logic is still mixed up with our controller logic in the modified controller class in Listing 3. For the same reason that it is a good idea to isolate our data access logic, it is a good idea to isolate our validation logic.

To fix this problem, we can create a separate service layer. The service layer is a separate layer that we can insert between our controller and repository classes. The service layer contains our business logic including all of our validation logic.

The ContactManagerService is contained in Listing 4. It contains the validation logic from the Contact controller class.

Listing 4 - Models\ContactManagerService.cs

using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Web.Mvc;
using ContactManager.Models.Validation;

namespace ContactManager.Models
{
public class ContactManagerService : IContactManagerService
{
private IValidationDictionary _validationDictionary;
private IContactManagerRepository _repository;


public ContactManagerService(IValidationDictionary validationDictionary)
: this(validationDictionary, new EntityContactManagerRepository())
{}


public ContactManagerService(IValidationDictionary validationDictionary, IContactManagerRepository repository)
{
_validationDictionary = validationDictionary;
_repository = repository;
}


public bool ValidateContact(Contact contactToValidate)
{
if (contactToValidate.FirstName.Trim().Length == 0)
_validationDictionary.AddError("FirstName", "First name is required.");
if (contactToValidate.LastName.Trim().Length == 0)
_validationDictionary.AddError("LastName", "Last name is required.");
if (contactToValidate.Phone.Length > 0 && !Regex.IsMatch(contactToValidate.Phone, @"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
_validationDictionary.AddError("Phone", "Invalid phone number.");
if (contactToValidate.Email.Length > 0 && !Regex.IsMatch(contactToValidate.Email, @"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
_validationDictionary.AddError("Email", "Invalid email address.");
return _validationDictionary.IsValid;
}


#region IContactManagerService Members

public bool CreateContact(Contact contactToCreate)
{
// Validation logic
if (!ValidateContact(contactToCreate))
return false;

// Database logic
try
{
_repository.CreateContact(contactToCreate);
}
catch
{
return false;
}
return true;
}

public bool EditContact(Contact contactToEdit)
{
// Validation logic
if (!ValidateContact(contactToEdit))
return false;

// Database logic
try
{
_repository.EditContact(contactToEdit);
}
catch
{
return false;
}
return true;
}

public bool DeleteContact(Contact contactToDelete)
{
try
{
_repository.DeleteContact(contactToDelete);
}
catch
{
return false;
}
return true;
}

public Contact GetContact(int id)
{
return _repository.GetContact(id);
}

public IEnumerable<Contact> ListContacts()
{
return _repository.ListContacts();
}

#endregion
}
}


Notice that the constructor for the ContactManagerService requires a ValidationDictionary. The service layer communicates with the controller layer through this ValidationDictionary. We discuss the ValidationDictionary in detail in the following section when we discuss the Decorator pattern.

Notice, furthermore, that the ContactManagerService implements the IContactManagerService interface. You should always strive to program against interfaces instead of concrete classes. Other classes in the Contact Manager application do not interact with the ContactManagerService class directly. Instead, with one exception, the remainder of the Contact Manager application is programmed against the IContactManagerService interface.

The IContactManagerService interface is contained in Listing 5.

Listing 5 - Models\IContactManagerService.cs

using System.Collections.Generic;

namespace ContactManager.Models
{
public interface IContactManagerService
{
bool CreateContact(Contact contactToCreate);
bool DeleteContact(Contact contactToDelete);
bool EditContact(Contact contactToEdit);
Contact GetContact(int id);
IEnumerable ListContacts();
}
}


The modified Contact controller class is contained in Listing 6. Notice that the Contact controller no longer interacts with the ContactManager repository. Instead, the Contact controller interacts with the ContactManager service. Each layer is isolated as much as possible from other layers.

Listing 6 - Controllers\ContactController.cs

using System.Web.Mvc;
using ContactManager.Models;

namespace ContactManager.Controllers
{
public class ContactController : Controller
{
private IContactManagerService _service;

public ContactController()
{
_service = new ContactManagerService(new ModelStateWrapper(this.ModelState));

}

public ContactController(IContactManagerService service)
{
_service = service;
}

public ActionResult Index()
{
return View(_service.ListContacts());
}

public ActionResult Create()
{
return View();
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "Id")] Contact contactToCreate)
{
if (_service.CreateContact(contactToCreate))
return RedirectToAction("Index");
return View();
}

public ActionResult Edit(int id)
{
return View(_service.GetContact(id));
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Contact contactToEdit)
{
if (_service.EditContact(contactToEdit))
return RedirectToAction("Index");
return View();
}

public ActionResult Delete(int id)
{
return View(_service.GetContact(id));
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Delete(Contact contactToDelete)
{
if (_service.DeleteContact(contactToDelete))
return RedirectToAction("Index");
return View();
}

}
}


Our application no longer runs afoul of the Single Responsibility Principle (SRP). The Contact controller in Listing 6 has been stripped of every responsibility other than controlling the flow of application execution. All the validation logic has been removed from the Contact controller and pushed into the service layer. All of the database logic has been pushed into the repository layer.

Using the Decorator Pattern


We want to be able to completely decouple our service layer from our controller layer. In principle, we should be able to compile our service layer in a separate assembly from our controller layer without needing to add a reference to our MVC application.

However, our service layer needs to be able to pass validation error messages back to the controller layer. How can we enable the service layer to communicate validation error messages without coupling the controller and service layer? We can take advantage of a software design pattern named the Decorator pattern.

A controller uses a ModelStateDictionary named ModelState to represent validation errors. Therefore, you might be tempted to pass ModelState from the controller layer to the service layer. However, using ModelState in the service layer would make your service layer dependent on a feature of the ASP.NET MVC framework. This would be bad because, someday, you might want to use the service layer with a WPF application instead of an ASP.NET MVC application. In that case, you wouldn t want to reference the ASP.NET MVC framework to use the ModelStateDictionary class.

The Decorator pattern enables you to wrap an existing class in a new class in order to implement an interface. Our Contact Manager project includes the ModelStateWrapper class contained in Listing 7. The ModelStateWrapper class implements the interface in Listing 8.

Listing 7 - Models\Validation\ModelStateWrapper.cs

using System.Web.Mvc;

namespace ContactManager.Models.Validation
{
public class ModelStateWrapper : IValidationDictionary
{
private ModelStateDictionary _modelState;

public ModelStateWrapper(ModelStateDictionary modelState)
{
_modelState = modelState;
}

public void AddError(string key, string errorMessage)
{
_modelState.AddModelError(key, errorMessage);
}

public bool IsValid
{
get { return _modelState.IsValid; }
}
}
}

Listing 8 - Models\Validation\IValidationDictionary.cs

namespace ContactManager.Models.Validation
{
public interface IValidationDictionary
{
void AddError(string key, string errorMessage);
bool IsValid {get;}
}
}


If you take a close look at Listing 5 then you ll see that the ContactManager service layer uses the IValidationDictionary interface exclusively. The ContactManager service is not dependent on the ModelStateDictionary class. When the Contact controller creates the ContactManager service, the controller wraps its ModelState like this:

_service = new ContactManagerService(new ModelStateWrapper(this.ModelState));

Summary


In this iteration, we did not add any new functionality to the Contact Manager application. The goal of this iteration was to refactor the Contact Manager application so that is easier to maintain and modify.

First, we implemented the Repository software design pattern. We migrated all of the data access code to a separate ContactManager repository class.

We also isolated our validation logic from our controller logic. We created a separate service layer that contains all of our validation code. The controller layer interacts with the service layer, and the service layer interacts with the repository layer.

When we created the service layer, we took advantage of the Decorator pattern to isolate ModelState from our service layer. In our service layer, we programmed against the IValidationDictionary interface instead of ModelState.

Finally, we took advantage of a software design pattern named the Dependency Injection pattern. This pattern enables us to program against interfaces (abstractions) instead of concrete classes. Implementing the Dependency Injection design pattern also makes our code more testable. In the next iteration, we add unit tests to our project.

Add form validation ASP.NET MVC

Building a Contact Management ASP.NET MVC Application (C#)

In this series of tutorials, we build an entire Contact Management application from start to finish. The Contact Manager application enables you to store contact information - names, phone numbers and email addresses - for a list of people.

We build the application over multiple iterations. With each iteration, we gradually improve the application. The goal of this multiple iteration approach is to enable you to understand the reason for each change.

    Iteration #1 - Create the application. In the first iteration, we create the Contact Manager in the simplest way possible. We add support for basic database operations: Create, Read, Update, and Delete (CRUD).

    Iteration #2 - Make the application look nice. In this iteration, we improve the appearance of the application by modifying the default ASP.NET MVC view master page and cascading style sheet.

    Iteration #3 - Add form validation. In the third iteration, we add basic form validation. We prevent people from submitting a form without completing required form fields. We also validate email addresses and phone numbers.

    Iteration #4 - Make the application loosely coupled. In this third iteration, we take advantage of several software design patterns to make it easier to maintain and modify the Contact Manager application. For example, we refactor our application to use the Repository pattern and the Dependency Injection pattern.

    Iteration #5 - Create unit tests. In the fifth iteration, we make our application easier to maintain and modify by adding unit tests. We mock our data model classes and build unit tests for our controllers and validation logic.

    Iteration #6 - Use test-driven development. In this sixth iteration, we add new functionality to our application by writing unit tests first and writing code against the unit tests. In this iteration, we add contact groups.

    Iteration #7 - Add Ajax functionality. In the seventh iteration, we improve the responsiveness and performance of our application by adding support for Ajax.

    This Iteration

    In this second iteration of the Contact Manager application, we add basic form validation. We prevent people from submitting a contact without entering values for required form fields. We also validate phone numbers and email addresses (see Figure 1).

    The New Project dialog box

    Figure 01: A form with validation (Click to view full-size image)

    In this iteration, we add the validation logic directly to the controller actions. In general, this is not the recommended way to add validation to an ASP.NET MVC application. A better approach is to place an application s validation logic in a separate service layer. In the next iteration, we refactor the Contact Manager application to make the application more maintainable.

    In this iteration, to keep things simple, we write all of the validation code by hand. Instead of writing the validation code ourselves, we could take advantage of a validation framework. For example, you can use the Microsoft Enterprise Library Validation Application Block (VAB) to implement the validation logic for your ASP.NET MVC application. To learn more about the Validation Application Block, see:

    http://msdn.microsoft.com/en-us/library/dd203099.aspx

    Adding Validation to the Create View

    Let s start by adding validation logic to the Create view. Fortunately, because we generated the Create view with Visual Studio, the Create view already contains all of the necessary user interface logic to display validation messages. The Create view is contained in Listing 1.

    Listing 1 - \Views\Contact\Create.aspx

    <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<ContactManager.Models.Contact>" %>

    <asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
    <title>Create</title>
    </asp:Content>

    <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <%= Html.ValidationSummary() %>

    <% using (Html.BeginForm()) {%>

    <fieldset class="fields">
    <legend>Create New Contact</legend>
    <p>
    <label for="FirstName">First Name:</label>
    <%= Html.TextBox("FirstName") %>
    <%= Html.ValidationMessage("FirstName", "*") %>
    </p>
    <p>
    <label for="LastName">Last Name:</label>
    <%= Html.TextBox("LastName") %>
    <%= Html.ValidationMessage("LastName", "*") %>
    </p>
    <p>
    <label for="Phone">Phone:</label>
    <%= Html.TextBox("Phone") %>
    <%= Html.ValidationMessage("Phone", "*") %>
    </p>
    <p>
    <label for="Email">Email:</label>
    <%= Html.TextBox("Email") %>
    <%= Html.ValidationMessage("Email", "*") %>
    </p>
    <p class="submit">
    <input type="submit" value="Create" />
    </p>
    </fieldset>

    <% } %>

    </asp:Content>

    Notice the call to the Html.ValidationSummary() helper method that appears immediately above the HTML form. If there are validation error messages, then this method displays validation messages in a bulleted list.

    Notice, furthermore, the calls to Html.ValidationMessage() that appear next to each form field. The ValidationMessage() helper displays an individual validation error message. In the case of Listing 1, an asterisk is displayed when there is a validation error.

    Finally, the Html.TextBox() helper automatically renders a Cascading Style Sheet class when there is a validation error associated with the property displayed by the helper. The Html.TextBox() helper renders a class named input-validation-error.

    When you create a new ASP.NET MVC application, a style sheet named Site.css is created in the Content folder automatically. This style sheet contains the following definitions for CSS classes related to the appearance of validation error messages:

    .field-validation-error
    {
    color: #ff0000;
    }

    .input-validation-error
    {
    border: 1px solid #ff0000;
    background-color: #ffeeee;
    }

    .validation-summary-errors
    {
    font-weight: bold;
    color: #ff0000;
    }

    The field-validation-error class is used to style the output rendered by the Html.ValidationMessage() helper. The input-validation-error class is used to style the textbox (input) rendered by the Html.TextBox() helper. The validation-summary-errors class is used to style the unordered list rendered by the Html.ValidationSummary() helper.

    You can modify the style sheet classes described in this section to customize the appearance of validation error messages.

    Adding Validation Logic to the Create Action


    Right now, the Create view never displays validation error messages because we have not written the logic to generate any messages. In order to display validation error messages, you need to add the error messages to ModelState.

    The UpdateModel() method adds error messages to ModelState automatically when there is an error assigning the value of a form field to a property. For example, if you attempt to assign the string “apple” to a BirthDate property that accepts DateTime values, then the UpdateModel() method adds an error to ModelState.

    The modified Create() method in Listing 2 contains a new section that validates the properties of the Contact class before the new contact is inserted into the database.

    Listing 2 - Controllers\ContactController.cs (Create with validation)

    //
    // POST: /Contact/Create

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create([Bind(Exclude = "Id")] Contact contactToCreate)
    {
    // Validation logic
    if (contactToCreate.FirstName.Trim().Length == 0)
    ModelState.AddModelError("FirstName", "First name is required.");
    if (contactToCreate.LastName.Trim().Length == 0)
    ModelState.AddModelError("LastName", "Last name is required.");
    if (contactToCreate.Phone.Length > 0 && !Regex.IsMatch(contactToCreate.Phone, @"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
    ModelState.AddModelError("Phone", "Invalid phone number.");
    if (contactToCreate.Email.Length > 0 && !Regex.IsMatch(contactToCreate.Email, @"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
    ModelState.AddModelError("Email", "Invalid email address.");
    if (!ModelState.IsValid)
    return View();

    // Database logic
    try
    {
    _entities.AddToContactSet(contactToCreate);
    _entities.SaveChanges();
    return RedirectToAction("Index");
    }
    catch
    {
    return View();
    }
    }

    The validate section enforces four distinct validation rules:


    • The FirstName property must have a length greater than zero (and it cannot consist solely of spaces)
    • The LastName property must have a length greater than zero (and it cannot consist solely of spaces)
    • If the Phone property has a value (has a length greater than 0) then the Phone property must match a regular expression.
    • If the Email property has a value (has a length greater than 0) then the Email property must match a regular expression.

    When there is a validation rule violation, an error message is added to ModelState with the help of the AddModelError() method. When you add a message to ModelState, you provide the name of a property and the text of a validation error message. This error message is displayed in the view by the Html.ValidationSummary() and Html.ValidationMessage() helper methods.

    After the validation rules are executed, the IsValid property of ModelState is checked. The IsValid property returns false when any validation error messages have been added to ModelState. If validation fails, the Create form is redisplayed with the error messages.

    I got the regular expressions for validating the phone number and email address from the regular expression repository at http://regexlib.com

    Adding Validation Logic to the Edit Action


    The Edit() action updates a Contact. The Edit() action needs to perform exactly the same validation as the Create() action. Instead of duplicating the same validation code, we should refactor the Contact controller so that both the Create() and Edit() actions call the same validation method.

    The modified Contact controller class is contained in Listing 3. This class has a new ValidateContact() method that is called within both the Create() and Edit() actions.

    Listing 3 - Controllers\ContactController.cs

    using System.Linq;
    using System.Text.RegularExpressions;
    using System.Web.Mvc;
    using ContactManager.Models;

    namespace ContactManager.Controllers
    {
    public class ContactController : Controller
    {
    private ContactManagerDBEntities _entities = new ContactManagerDBEntities();

    protected void ValidateContact(Contact contactToValidate)
    {
    if (contactToValidate.FirstName.Trim().Length == 0)
    ModelState.AddModelError("FirstName", "First name is required.");
    if (contactToValidate.LastName.Trim().Length == 0)
    ModelState.AddModelError("LastName", "Last name is required.");
    if (contactToValidate.Phone.Length > 0 && !Regex.IsMatch(contactToValidate.Phone, @"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
    ModelState.AddModelError("Phone", "Invalid phone number.");
    if (contactToValidate.Email.Length > 0 && !Regex.IsMatch(contactToValidate.Email, @"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
    ModelState.AddModelError("Email", "Invalid email address.");
    }

    public ActionResult Index()
    {
    return View(_entities.ContactSet.ToList());
    }

    public ActionResult Create()
    {
    return View();
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create([Bind(Exclude = "Id")] Contact contactToCreate)
    {
    // Validation logic
    ValidateContact(contactToCreate);
    if (!ModelState.IsValid)
    return View();

    // Database logic
    try
    {
    _entities.AddToContactSet(contactToCreate);
    _entities.SaveChanges();
    return RedirectToAction("Index");
    }
    catch
    {
    return View();
    }
    }

    public ActionResult Edit(int id)
    {
    var contactToEdit = (from c in _entities.ContactSet
    where c.Id == id
    select c).FirstOrDefault();

    return View(contactToEdit);
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(Contact contactToEdit)
    {
    ValidateContact(contactToEdit);
    if (!ModelState.IsValid)
    return View();

    try
    {
    var originalContact = (from c in _entities.ContactSet
    where c.Id == contactToEdit.Id
    select c).FirstOrDefault();
    _entities.ApplyPropertyChanges(originalContact.EntityKey.EntitySetName, contactToEdit);
    _entities.SaveChanges();
    return RedirectToAction("Index");
    }
    catch
    {
    return View();
    }
    }

    public ActionResult Delete(int id)
    {
    var contactToDelete = (from c in _entities.ContactSet
    where c.Id == id
    select c).FirstOrDefault();

    return View(contactToDelete);
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Delete(Contact contactToDelete)
    {
    try
    {
    var originalContact = (from c in _entities.ContactSet
    where c.Id == contactToDelete.Id
    select c).FirstOrDefault();

    _entities.DeleteObject(originalContact);
    _entities.SaveChanges();
    return RedirectToAction("Index");
    }
    catch
    {
    return View();
    }
    }

    }
    }

    Summary


    In this iteration, we added basic form validation to our Contact Manager application. Our validation logic prevents users from submitting a new contact or editing an existing contact without supplying values for the FirstName and LastName properties. Furthermore, users must supply valid phone numbers and email addresses.

    In this iteration, we added the validation logic to our Contact Manager application in the easiest way possible. However, mixing our validation logic into our controller logic will create problems for us in the long term. Our application will be more difficult to maintain and modify over time.

    In the next iteration, we will refactor our validation logic and database access logic out of our controllers. We ll take advantage of several software design principles to enable us to create a more loosely coupled, and more maintainable, application.

    Make the application look nice with ASP.NET MVC

    Building a Contact Management ASP.NET MVC Application (C#)

    In this series of tutorials, we build an entire Contact Management application from start to finish. The Contact Manager application enables you to store contact information - names, phone numbers and email addresses - for a list of people.

    We build the application over multiple iterations. With each iteration, we gradually improve the application. The goal of this multiple iteration approach is to enable you to understand the reason for each change.

      Iteration #1 - Create the application. In the first iteration, we create the Contact Manager in the simplest way possible. We add support for basic database operations: Create, Read, Update, and Delete (CRUD).

      Iteration #2 - Make the application look nice. In this iteration, we improve the appearance of the application by modifying the default ASP.NET MVC view master page and cascading style sheet.

      Iteration #3 - Add form validation. In the third iteration, we add basic form validation. We prevent people from submitting a form without completing required form fields. We also validate email addresses and phone numbers.

      Iteration #4 - Make the application loosely coupled. In this third iteration, we take advantage of several software design patterns to make it easier to maintain and modify the Contact Manager application. For example, we refactor our application to use the Repository pattern and the Dependency Injection pattern.

      Iteration #5 - Create unit tests. In the fifth iteration, we make our application easier to maintain and modify by adding unit tests. We mock our data model classes and build unit tests for our controllers and validation logic.

      Iteration #6 - Use test-driven development. In this sixth iteration, we add new functionality to our application by writing unit tests first and writing code against the unit tests. In this iteration, we add contact groups.

      Iteration #7 - Add Ajax functionality. In the seventh iteration, we improve the responsiveness and performance of our application by adding support for Ajax.

    This Iteration

    The goal of this iteration is to improve the appearance of the Contact Manager application. Currently, the Contact Manager uses the default ASP.NET MVC view master page and cascading style sheet (see Figure 1). These don t look bad, but I don t want the Contact Manager to look just like every other ASP.NET MVC website. I want to replace these files with custom files.

    The New Project dialog box

    Figure 01: The default appearance of an ASP.NET MVC Application (Click to view full-size image)

    In this iteration, I discuss two approaches to improving the visual design of our application. First, I show you how to take advantage of the ASP.NET MVC Design gallery to download a free ASP.NET MVC design template. The ASP.NET MVC Design gallery enables you to create a professional web application without doing any work.

    I decided to not use a template from the ASP.NET MVC Design gallery for the Contact Manager application. Instead, I had a custom design created by a professional design firm. In the second part of this tutorial, I explain how I worked with a professional design company to create the final ASP.NET MVC design.

    The ASP.NET MVC Design Gallery

    The ASP.NET MVC Design Gallery is a free resource provided by Microsoft. The ASP.NET MVC Gallery is located at the following address:

    http://www.ASP.net/mvc/gallery

    The ASP.NET MVC Design Gallery hosts a collection of free website designs that were created specifically for using in an ASP.NET MVC project. Designs are uploaded by members of the community. Visitors to the Gallery can vote for their favorite designs (see Figure 2).

    The New Project dialog box

    Figure 02: The ASP.NET MVC Design Gallery (Click to view full-size image)

    As I write this tutorial, the most popular design in the gallery is a design named October by David Hauser. You can use this design for an ASP.NET MVC project by completing the following steps:

    1. Click the Download button to download the October.zip file to your computer.
    2. Right-click the downloaded October.zip file and click the Unblock button (see Figure 3).
    3. Unzip the file to a folder named October.
    4. Select all of the files from the DesignTemplate folder contained in the October folder, right-click the files, and select the menu option Copy.
    5. Right-click the ContactManager project node in the Visual Studio Solution Explorer window and select the menu option Paste (see Figure 4).
    6. Select the Visual Studio menu option Edit, Find and Replace, Quick Replace and replace [MyProjectName] with ContactManager (see Figure 5).

    The New Project dialog box

    Figure 03: Unblocking a file downloaded from the web (Click to view full-size image)

    The New Project dialog box

    Figure 04: Overwriting files in the Solution Explorer (Click to view full-size image)

    The New Project dialog box

    Figure 05: Replacing [ProjectName] with ContactManager (Click to view full-size image)

    After you complete these steps, your web application will use the new design. The page in Figure 6 illustrates the appearance of the Contact Manager application with the October design.

    The New Project dialog box

    Figure 06: ContactManager with the October template (Click to view full-size image)

    Creating a Custom ASP.NET MVC Design

    The ASP.NET MVC Design Gallery has a good selection of different design styles. The Gallery provides you with a painless way to customize the appearance of your ASP.NET MVC applications. And, of course, the Gallery has the big advantage of being completely free.

    However, you might need to create a completely unique design for your website. In that case, it makes sense to work with a website design company. I decided to take this approach for the design for the Contact Manager application.

    I zipped up the Contact Manager from Iteration #1 and sent the project to the design company. They did not own Visual Studio (shame on them!), but that didn t present a problem. They were able to download Microsoft Visual Web Developer for free from the http://www.ASP.net website and open the Contact Manager application in Visual Web Developer. In a couple of days, they had produced the design in Figure 7.

    The New Project dialog box

    Figure 07: The ASP.NET MVC Contact Manager Design (Click to view full-size image)

    The new design consisted of two main files: a new cascading style sheet file and a new view master page file. A view master page contains the layout and shared content for views in an ASP.NET MVC application. For example, the view master page includes the header, navigation tabs, and footer that appear in Figure 7. I overwrote the existing Site.Master view master page in the Views\Shared folder with the new Site.Master file from the design company,

    The design company also created a new cascading style sheet and set of images. I placed these new files in the Content folder and overwrote the existing Site.css file. You should place all static content in the Content folder.

    Notice that the new design for the Contact Manager includes images for editing and deleting contacts. An Edit and Delete image appear next to each contact in the HTML table of contacts.

    Originally, these links that were rendered with the HTML.ActionLink() helper like this:

    <td>
    <%= Html.ActionLink("Edit", "Edit", new { id=item.Id }) %> |
    <%= Html.ActionLink("Delete", "Delete", new { id=item.Id }) %>
    </td>

    The Html.ActionLink() method does not support images (the method HTML encodes the link text for security reasons). Therefore, I replaced the calls to Html.ActionLink() with calls to Url.Action() like this:

    <td class="actions edit">
    <a href='<%= Url.Action("Edit", new {id=item.Id}) %>'><img src="../../Content/Edit.png" alt="Edit" /></a>
    </td>
    <td class="actions delete">
    <a href='<%= Url.Action("Delete", new {id=item.Id}) %>'><img src="../../Content/Delete.png" alt="Delete" /></a>
    </td>


    The Html.ActionLink() method renders an entire HTML hyperlink. The Url.Action() method, on the other hand, renders just the URL without the <a> tag.

    Notice, furthermore, that the new design includes both selected and unselected tabs. For example, in Figure 8, the Create New Contact tab is selected and the My Contacts tab is not selected.

    The New Project dialog box

    Figure 08: Selected and unselected tabs(Click to view full-size image)

    To support rendering both selected and unselected tabs, I created a custom HTML helper named the MenuItemHelper. This helper method renders either a <li> tag or a <li class=”selected”> tag depending on whether the current controller and action corresponds to the controller and action name passed to the helper. The code for the MenuItemHelper is contained in Listing 1.

    Listing 1 - Helpers\MenuItemHelper.cs

    using System;
    using System.Web.Mvc;
    using System.Web.Mvc.Html;

    namespace Helpers
    {
    /// <summary>
    /// This helper method renders a link within an HTML LI tag.
    /// A class="selected" attribute is added to the tag when
    /// the link being rendered corresponds to the current
    /// controller and action.
    ///
    /// This helper method is used in the Site.Master View
    /// Master Page to display the website menu.
    /// </summary>
    public static class MenuItemHelper
    {
    public static string MenuItem(this HtmlHelper helper, string linkText, string actionName, string controllerName)
    {
    string currentControllerName = (string)helper.ViewContext.RouteData.Values["controller"];
    string currentActionName = (string)helper.ViewContext.RouteData.Values["action"];

    var builder = new TagBuilder("li");

    // Add selected class
    if (currentControllerName.Equals(controllerName, StringComparison.CurrentCultureIgnoreCase) && currentActionName.Equals(actionName, StringComparison.CurrentCultureIgnoreCase))
    builder.AddCssClass("selected");

    // Add link
    builder.InnerHtml = helper.ActionLink(linkText, actionName, controllerName);

    // Render Tag Builder
    return builder.ToString(TagRenderMode.Normal);
    }

    }
    }

    The MenuItemHelper uses the TagBuilder class internally to build the <li> HTML tag. The TagBuilder class is a very useful utility class that you can use whenever you need to build up a new HTML tag. It includes methods for adding attributes, adding CSS classes, generating Ids, and modifying the tag s inner HTML.

    Summary


    In this iteration, we improved the visual design of our ASP.NET MVC application. First, you were introduced to the ASP.NET MVC Design Gallery. You learned how to download free design templates from the ASP.NET MVC Design Gallery that you can use in your ASP.NET MVC applications.

    Next, we discussed how you can create a custom design by modifying the default cascading style sheet file and master view page file. In order to support the new design, we had to make some minor changes to our Contact Manager application. For example, we added a new HTML helper named the MenuItemHelper that displays selected and unselected tabs.

    In the next iteration, we tackle the very important subject of validation. We add validation code to our application so that a user cannot create a new contact without supplying required values such as a person s first and last name.

    Advertsing

    125X125_06

    TagCloud

    MonthList

    CommentList