ASP.NET – Use Context.Cache to cache data for http request

The best way to speed up ASP.NET application is to use cache for speeding up the velocity of reading/writing data. Every developer knows that reading/writing memory is orders of magnitude faster than reading/writing files or database on hard disk. Hence reading/writing files or databases for each HTTP request is not a wisdom way. In this small post, I would like to illustrate how man can use ASP.NET for his application.

Continue reading ASP.NET – Use Context.Cache to cache data for http request

Windows Phone – Current weather application

When I am “jogging” around some programming forums, I found out an interesting website http://www.webservicex.net/WCF/default.aspx which provides us many web services in many fields which can be used in our application. As you can see in URL, the web services of this site may be based on WCF which has a many advantages in compare to normal web service. Therefore I would like to use this free web service to write a small application telling me the current weather of a specific city. This application should work in portrait and landscape mode as images below.

So that the application is compatible in 2 modes, I used ScrollViewer and StackPanel to store the controls and let them automatically adjust when changing between 2 modes.

<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
	<StackPanel Orientation="Vertical">
		<StackPanel Orientation="Vertical">
			<StackPanel  Orientation="Horizontal" Width="450">
				<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Name="textBlock1" Text="Country" Width="74" />
				<swci:AutoCompleteBox GotFocus="acbCountry_GotFocus" LostFocus="acbCountry_LostFocus"  x:Name="acbCountry" HorizontalAlignment="Left" Width="199"></swci:AutoCompleteBox>
				<Button Content="Set Default" Height="72" HorizontalAlignment="Left"  Name="btnSetAsDefault" VerticalAlignment="Top" Width="183" Click="btnSetAsDefault_Click" />
			</StackPanel>
			<StackPanel Orientation="Horizontal" Width="449">
				<TextBlock HorizontalAlignment="Left" Name="textBlock2" Text="City" VerticalAlignment="Center" Width="74" />
				<swci:AutoCompleteBox x:Name="acbCity"  HorizontalAlignment="Left" Width="199"></swci:AutoCompleteBox>
				<Button Content="Browse" Height="72" HorizontalAlignment="Left"  Name="btnBrowse" VerticalAlignment="Top" Width="183" Click="btnBrowse_Click" />
			</StackPanel>
		</StackPanel>
		<Rectangle Height="25"></Rectangle>
		<StackPanel Orientation="Vertical" Width="450">
			<StackPanel Orientation="Vertical">
				<TextBlock FontSize="20" Text="{Binding Location}" HorizontalAlignment="Left" Name="textBlock10"  VerticalAlignment="Top" />
				<TextBlock FontSize="14" Text="{Binding Time}" HorizontalAlignment="Left" Name="textBlock11" VerticalAlignment="Top" />
			</StackPanel>
			<Rectangle Height="25"></Rectangle>
			<StackPanel Orientation="Horizontal">
				<StackPanel Orientation="Vertical">
					<Image Source="{Binding SkyConditionImage}"></Image>
					<TextBlock Text="{Binding SkyConditions}" HorizontalAlignment="Left" Name="textBlock5"  VerticalAlignment="Top" />
				</StackPanel>
				<Rectangle Width="25"></Rectangle>
				<StackPanel Orientation="Vertical">
					<TextBlock FontSize="48" Text="{Binding Temperature}" HorizontalAlignment="Left" Name="textBlock6"  VerticalAlignment="Top" />

					<Rectangle Height="15"></Rectangle>
					<TextBlock Width="270" TextWrapping="Wrap" Text="{Binding Wind}"  HorizontalAlignment="Left"  Name="textBlock3" VerticalAlignment="Top" />

					<Rectangle Height="15"></Rectangle>
					<TextBlock Height="30" Text="{Binding RelativeHumidity}" HorizontalAlignment="Left"  Name="textBlock8" VerticalAlignment="Top" />

					<Rectangle Height="15"></Rectangle>
					<TextBlock Height="30" Text="{Binding DewPoint}" HorizontalAlignment="Left"  Name="textBlock7"  VerticalAlignment="Top" />

					<Rectangle Height="15"></Rectangle>
					<TextBlock Height="30" Text="{Binding Pressure}" HorizontalAlignment="Left"  Name="textBlock9" VerticalAlignment="Top" />

					<Rectangle Height="15"></Rectangle>
					<TextBlock Height="30" Text="{Binding VisibilityW}" HorizontalAlignment="Left"  Name="textBlock4"  VerticalAlignment="Top" />
				</StackPanel>
			</StackPanel>
		</StackPanel>
	</StackPanel>
</ScrollViewer>

You can see that I used AutoCompleteBox instead of ComboBox because the list of countries and cities are too long. If I use the ComboBox, the drop down list will exceed the height of screen and I must scroll down to choose which will surely lead the phone to crash. I think cause of this reason ComboBox is not officially supported in Windows Phone although we can use it by adding it directly in XAML file. In this version, only countries below are supported

public List<string> Countries
{
	get
	{
		string[] aCountries = {
		"Afghanistan","Algeria","Angola","Argentina","Armenia","Australia","Austria","Azerbaijan","Belarus","Belgium","Benin",
		"Bolivia","Botswana","Brazil","Bulgaria","Burundi","Canada","Central African Republic","Chad","Chile","China",
		"Colombia","Congo","Costa Rica","Cote d'Ivoire","Croatia","Czech Republic","Denmark","Djibouti","Dominican Republic","DRC",
		"Ecuador","Egypt","El Salvador","Estonia","Ethiopia","Finland","France","Gabon","Gambia","Germany",
		"Ghana","Greece","Guatemala","Honduras","Hong Kong","Hungary","Iceland","India","Indonesia","Ireland",
		"Israel","Italy","Japan","Jordan","Kazakhstan","Kenya","Korea","Kyrgyzstan","Latvia","Lebanon",
		"Lesotho","Lithuania","Macao","Madagascar","Malawi","Malaysia","Mali","Mauritius","Mexico","Moldova",
		"Morocco","Mozambique","Namibia","Netherlands","New Zealand","Nigeria","Norway","Oman","Pakistan","Panama",
		"Paraguay","Peru","Philippines","Poland","Portugal","Puerto Rico","Romania","Russia, CIS and Baltics","Rwanda","Sao Tome and Principe",
		"Saudi Arabia","Senegal","Serbia","Seychelles","Sierra Leone","Singapore","Slovakia","Slovenia","South Africa","Spain",
		"Sweden","Switzerland","Taiwan","Tajikistan","Tanzania","Thailand","Togo","Tunisia","Turkey","Turkmenistan",
		"Uganda","Ukraine","United Arab Emirates","United Kingdom","United States","Uruguay","Uzbekistan","Venezuela","Viet Nam","Zambia",
		"Zimbabwe"
		};
		List<string> lstResult = new List<string>();
		lstResult.AddRange(aCountries);
		return lstResult;
	}
}

When a user enters a country name, the application will connect to web service and get supported cities of that country and fill this list to the second AutoCompleteBox.

public void GetAvailableCities(string CountryName)
{
	this.CountryName = CountryName;
	m_gwscClient.GetCitiesByCountryCompleted += new EventHandler<GlobalWeatherService.GetCitiesByCountryCompletedEventArgs>(gwscClient_GetCitiesByCountryCompleted);
	m_gwscClient.GetCitiesByCountryAsync(CountryName);
}

void gwscClient_GetCitiesByCountryCompleted(object sender, GlobalWeatherService.GetCitiesByCountryCompletedEventArgs e)
{
	XDocument doc = XDocument.Parse(e.Result);
	AvailableCities = new List<string>();
	doc.Descendants("City").ToList().ForEach(x => AvailableCities.Add(x.Value));
	if (GetCitiesByCountryCompleted != null) GetCitiesByCountryCompleted(this, new EventArgs());
}

Because I can only get cities list asynchronously, I add an event to notify the View when the progress finishes and load this list to AutoCompleteBox. After choosing appropriate location, the user gets weather info through clicking button “Browse”. Another asynchronous call to web service will be executed to fetch weather data and fill the information into controls.

void m_gwscClient_GetWeatherCompleted(object sender, GlobalWeatherService.GetWeatherCompletedEventArgs e)
{
	if (e.Result != "Data Not Found")
	{
		XDocument doc = XDocument.Parse(e.Result);

		Location = doc.Descendants("Location").ToList()[0].Value;
		NotifyPropertyChanged("Location");

		Time = doc.Descendants("Time").ToList()[0].Value;
		NotifyPropertyChanged("Time");

		Wind = "Wind: " + doc.Descendants("Wind").ToList()[0].Value;
		NotifyPropertyChanged("Wind");

		VisibilityW = "Visibility: " + doc.Descendants("Visibility").ToList()[0].Value;
		NotifyPropertyChanged("VisibilityW");

		if (doc.Descendants("SkyConditions").ToList().Count > 0)
			SkyConditions = doc.Descendants("SkyConditions").ToList()[0].Value;
		NotifyPropertyChanged("SkyConditions");

		string strUrl = "";
		switch (SkyConditions.Trim())
		{
			case "mostly cloudy":
				strUrl = "Images/mostlycloudy.png";
				break;
			case "partly cloudy":
				strUrl = "Images/partlycloudy.png";
				break;
			case "mostly clear":
				strUrl = "Images/partlycloudy.png";
				break;
			default:
				break;
		}
		SkyConditionImage = new BitmapImage(new Uri(strUrl, UriKind.Relative));
		NotifyPropertyChanged("SkyConditionImage");

		Temperature = doc.Descendants("Temperature").ToList()[0].Value;
		NotifyPropertyChanged("Temperature");

		DewPoint = "Dew Point: " + doc.Descendants("DewPoint").ToList()[0].Value;
		NotifyPropertyChanged("DewPoint");

		RelativeHumidity = "Relative Humidity: " + doc.Descendants("RelativeHumidity").ToList()[0].Value;
		NotifyPropertyChanged("RelativeHumidity");

		Pressure = "Pressure: " + doc.Descendants("Pressure").ToList()[0].Value;
		NotifyPropertyChanged("Pressure");

		Status = doc.Descendants("Status").ToList()[0].Value;
		NotifyPropertyChanged("Status");
	}
	else
	{
		Location = "N/A";
		NotifyPropertyChanged("Location");

		Time = "N/A";
		NotifyPropertyChanged("Time");

		Wind = "Wind: " + "N/A";
		NotifyPropertyChanged("Wind");

		VisibilityW = "Visibility: " + "N/A";
		NotifyPropertyChanged("VisibilityW");

		SkyConditions = "N/A";
		NotifyPropertyChanged("SkyConditions");

		Temperature = "N/A";
		NotifyPropertyChanged("Temperature");

		DewPoint = "Dew Point: " + "N/A";
		NotifyPropertyChanged("DewPoint");

		RelativeHumidity = "Relative Humidity: " + "N/A";
		NotifyPropertyChanged("RelativeHumidity");

		Pressure = "Pressure: " + "N/A";
		NotifyPropertyChanged("Pressure");

		Status = "N/A";
		NotifyPropertyChanged("Status");
	}
}

The application can be upgraded by adding forecast feature. I will add it later if I have time. The code is quick and dirty because I just want to play around with web service and UI components and spend time to make a working Facebook API for Windows Phone. The complete source code you can download here “Windows Phone Weather

Windows Phone – Embedded fonts and Bing maps

Today I would like to illustrate about how I can embed font and Bing maps into Windows Phone application. I know it’s a such simple example that every programmer on Windows Phone can write but I just want to make a demo to show that we can use embedded font and host a Bing map control. For Bing map example, I use this example http://www.earthware.co.uk/blog/index.php/2010/03/writing-a-bing-maps-location-aware-application-for-windows-phone-7-series/ with some modifications so that I can relatively find my location on Bing map.

Embedded fonts

Silverlight allows us to embed font in application without installing it on operating system. Using custom font makes GUI of application really beautiful and creative. To embed font, copy it to a folder of your project, set “Build Action” to “Content” and link to control as following

<TextBlock FontFamily="Fonts/AnnabelScript.ttf#Annabel Script" Text="Duration" x:Name="txtDuration" Margin="20,530,173,82"/>

Bing maps

To use Bing map control, you can read the example above. I just tell which I learned when I was trying to use Microsoft.Maps.MapControl library. It’s really very strange. After adding reference to Microsoft.Maps.MapControl, if I add this reference in XAML first

xmlns:bing="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl"

Then I can not use Map control in XAML.

<bing:Map Name="mapMain" NavigationVisibility="Collapsed" Mode="AerialWithLabels" CredentialsProvider="USE_YOUR_BING_MAP_KEY" Height="577">
	<bing:MapLayer>
		<Ellipse Fill="Red" Width="20" Height="20" bing:MapLayer.Position="0,0" Name="ppLocation" Visibility="Collapsed" />
	</bing:MapLayer>
</bing:Map>

Visual Studio says that it can not find Map control and asks if I forget to add reference to assembly. But if I use Map control in XAML first and add reference later then everything works.

private void btnBrowse_Click(object sender, RoutedEventArgs e)
{
	GetLocationOfCity();
}

private void GetLocationOfCity()
{
	string strGetIpUrl = "http://www.whatismyip.com/automation/n09230945.asp";
	WebClient wcIP = new WebClient();
	wcIP.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wcIP_DownloadStringCompleted);
	wcIP.DownloadStringAsync(new Uri(strGetIpUrl, UriKind.Absolute));
}

void wcIP_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
	string strIP = e.Result;
	string strLocation = "http://api.hostip.info/?ip=" + strIP + "&position=true";
	WebClient wcLocation = new WebClient();
	wcLocation.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wcLocation_DownloadStringCompleted);
	wcLocation.DownloadStringAsync(new Uri(strLocation, UriKind.Absolute));
}

void wcLocation_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
	string strResult = e.Result;
	string strOpenTag = "<gml:coordinates>";
	int nStartIndex = strResult.IndexOf(strOpenTag) + strOpenTag.Length;
	string strClosedTag = "</gml:coordinates>";
	int nEndIndex = strResult.IndexOf(strClosedTag);
	string strCoordinates = strResult.Substring(nStartIndex, nEndIndex - nStartIndex);
	double longtitude = Convert.ToDouble(strCoordinates.Split(',')[0]);
	double latitude = Convert.ToDouble(strCoordinates.Split(',')[1]);
	Location locCurrent = new Location(latitude, longtitude);
	mapMain.SetView(locCurrent, 15);

	MapLayer.SetPosition(ppLocation, locCurrent);
	ppLocation.Visibility = System.Windows.Visibility.Visible;
}

As you can see, because the location service is not available with emulator cause of lacking GPS device. I modify the example by getting my IP address through service of whatismyip and then pass my IP to service of hostip to get the longitude and latitude of that IP. With these information I can use Bing map control to navigate to my location but it’s not exact 100%. I hope with a real phone and GPS device, the Bing map can locate exactly where I am.
You can download the source code of Bing map example “Windows Phone Bing Map

Windows Phone – Signature capturing with InkPresenter and save to PNG file

Today I received a small package by post for my neighbor and I must sign on a small device to confirm that I received the package. Therefore the deliver can be sure that I will give it to my neighbor. I thought it was very interesting to write a small application on Windows Phone which should work like the device of postman. This application allows people signing on the screen and it will store this signature into IsolatedStorageFile and show it again in image control below to confirm that the program works correctly.

As you can see in the demo image of application, I have 4 buttons: Undo, Redo, Clear and Save. The “Undo”, “Redo” buttons allow me to remove the strokes or redraw them. The strokes will be drawn on InkPresenter control and then saved into a PNG file. To draw the stroke on InkPresenter, I must handle the MouseLeftButtonDown to capture the mouse movement and draw stroke from point to point.

private StylusPoint GetStylusPoint(Point p)
{
	return new StylusPoint(p.X, p.Y);
}
private void inkSignature_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
	inkSignature.CaptureMouse();
	m_strokeCurrent = new Stroke();
	m_strokeCurrent.StylusPoints.Add(GetStylusPoint(e.GetPosition(inkSignature)));
	m_strokeCurrent.DrawingAttributes.Color = Colors.Blue;
	inkSignature.Strokes.Add(m_strokeCurrent);
}
private void inkSignature_MouseMove(object sender, MouseEventArgs e)
{
	if (m_strokeCurrent != null)
		m_strokeCurrent.StylusPoints.Add(GetStylusPoint(e.GetPosition(inkSignature)));
}

To implement “Undo” and “Redo” feature, I use a stack of strokes to push/pop a stroke in history and then remove/add it on InkPresenter.

private void btnUndo_Click(object sender, RoutedEventArgs e)
{
	if (inkSignature.Strokes != null && inkSignature.Strokes.Count > 0)
	{
		m_stackRemovedStrokes.Push(inkSignature.Strokes.Last());
		inkSignature.Strokes.RemoveAt(inkSignature.Strokes.Count - 1);
	}
}

private void btnRedo_Click(object sender, RoutedEventArgs e)
{
	if (m_stackRemovedStrokes != null && m_stackRemovedStrokes.Count > 0)
	{
		inkSignature.Strokes.Add(m_stackRemovedStrokes.Pop());
	}
}

At last, I use WriteableBitmap to take a snapshot of InkPresenter and encode it to a PNG format file. In current version of Visual Studio for Windows Phone CTP there is still not a PngBitmapEncoder. Therefore I use a custom one from this blog http://geekswithblogs.net/braulio/archive/2009/07/12/export-canvas-to-png-and-save-it-in-your-local.aspx . You can find the source code of PNG Encoder in the archive at the end of this post, too.

private void btnSave_Click(object sender, RoutedEventArgs e)
{
	WriteableBitmap wbBitmap = new WriteableBitmap(inkSignature, new TranslateTransform());
	EditableImage eiImage = new EditableImage(wbBitmap.PixelWidth, wbBitmap.PixelHeight);

	try
	{
		for (int y = 0; y < wbBitmap.PixelHeight; ++y)
		{
			for (int x = 0; x < wbBitmap.PixelWidth; ++x)
			{
				int pixel = wbBitmap.Pixels[wbBitmap.PixelWidth * y + x];
				eiImage.SetPixel(x, y,
				(byte)((pixel >> 16) & 0xFF),
				(byte)((pixel >>  8 ) & 0xFF ) ,
				(byte)(pixel & 0xFF), (byte)((pixel >> 24) & 0xFF)
				);
			}
		}
	}
	catch (System.Security.SecurityException)
	{
		throw new Exception("Cannot print images from other domains");
	}

	// Save it to disk
	Stream streamPNG = eiImage.GetStream();
	StreamReader srPNG = new StreamReader(streamPNG);
	byte[] baBinaryData = new Byte[streamPNG.Length];
	long bytesRead = streamPNG.Read(baBinaryData, 0, (int)streamPNG.Length);

	IsolatedStorageFileStream isfStream = new IsolatedStorageFileStream("temp.png", FileMode.Create, IsolatedStorageFile.GetUserStoreForApplication());
	isfStream.Write(baBinaryData, 0, baBinaryData.Length);
	isfStream.Close();

	//Show to image
	isfStream = new IsolatedStorageFileStream("temp.png", FileMode.Open, IsolatedStorageFile.GetUserStoreForApplication());
	BitmapImage biImage = new BitmapImage();
	biImage.SetSource(isfStream);
	isfStream.Close();
	imgResult.Source = biImage;
}

You can download complete source code here “Windows Phone Sig Capture
Reference: http://www.nickharris.net/2010/03/silverlight-for-mobile-on-windows-phone-7-inkpresenter-fun/