Category Archives: Web

Using SendGrid and emails are not being delivered to Hotmail/Outlook/Live/MSN.com recipients?

Me too, or at least I was… While the problem I was having might not be related to SendGrid exclusively, I am going to talk about the solution.

The Problem

Before I go into the solution, let’s talk about the problem first. Many of you know that I run Desert Code Camp in Chandler, AZ. Originally, the site ran on the Microsoft stack, it used ASP.NET (Web Forms) and SQL Server. There is an API for mobile apps and future development but that’s another story. The site has 12,000 registered users. A few thousand are SPAM/Bots, a few thousand are “inactive” accounts (opted out or moved), and the other 6000 or so are active users that have an interest in Desert Code Camp or have attended at least one.

And here lies the first problem.

When an announcement email goes out to our attendees or users of the site, we need to send out about 6000 emails. I used to do this by sending the email from a web page through code using System.Net.SMTP via localhost. At first, it wasn’t an issue. After a while, as Desert Code Camp grew, this became more and more of a problem. Typically the page would time out or IIS would die or something. So I needed to find a solution. Sometime last year, probably around this time, I offloaded the processing of emails to Azure Queue Storage and used Azure WebJobs to handle the “logic”. But wait, Azure does not support sending stuff via localhost. And that is true! This is where SendGrid comes into play. Azure provides, as of the creation of this post, a free 25,000 email per month subscription to SendGrid. For more on that, check out this post.

Now that I implemented the new Azure/SendGrid combination everything was great.

Fast forward a year, to this past weekend, I announced that the next Desert Code Camp was happening on Twitter and some people started submitting sessions. This is great! But I noticed that I was wasn’t getting my emails about the submissions.  At first, I thought, “Oh Joe, you forgot something when you ‘created’ the new event”.  It happens every time :). However, this was not the case this time. Microsoft decided to embrace something called DMARC, Domain-based Message Authentication, Reporting & Conformance. In a nutshell, it checks to see if you are sending emails from the domain you claim you are sending them from, which for me was bad.  Not because I was trying to be deceitful, but because I was sending emails saying they were from ‘@hotmail.com‘ and sending them via ‘SendGrid‘ because I wanted people to reply to my Hotmail address. Well, when Microsoft implemented the DMARC…

What this means: As of June, 2016, you can no longer send with the From address being anything from a Microsoft address when sending to a domain that checks DMARC before accepting mail.

… it saw my email as not being ‘legitimate‘ and did not deliver it to my inbox and probably others.

The Solution

The answer is ‘Whitelist‘ your domains while using SendGrid. There are more detailed instructions on how to whitelist a domain using SendGrid here.

What is Whitelabeling?

Whitelabeling allows you to send through your own custom domain instead of SendGrid’s default settings. This will mask the header information of your emails with your data–not theirs–and will improve your email deliverability.

Non-Whitelabeled Example vs. Whitelabeled Example

Luckily, SendGrid makes it easy to whitelist your domain(s). Here is how you do it. Please note: You will need access to your domain records, you will be making changes to your TXT or CNAME entries to prove you have rights to the domain.

  • First, log-in to your SendGrid Account
  • Click ‘Settings’ (on the left)
  • Click ‘Whitelabels’
  • Click + Add Domain button.
  • SendGrid will walk you though everything else you need.

But what about the replies to @Hotmail.com

I’m glad you are still with me :). This part is the easy part. Essentially, I added ‘noreply@desertcodecamp.com‘ as the ToAddress and added ‘jguadagno@hotmail.com‘ as the ReplyTo. As shown in this gist.

I hope this saves you some time troubleshooting mail delivery to @hotmail.com, @outlook.com, @live.com, @msn.com, @yahoo.com, and @gmail.com.

jQuery Twitter Bootstrap Flickr Carousel

A few months ago I built a jQuery plugin that uses the Twitter Bootstrap Carousel to cycle through images on Flickr. In order to use this plugin you need to get an Api Key from Flickr and have the following software:

  • jQuery (v1.8 or higher)
  • Twitter Bootstrap (v3.0 or higher)
  • Twitter Bootstrap components (v3.0 or higher)
  • twbsPagination (optional)

Sample Usage

$('#flickr-carousel').twbsFlickrCarousel(
	{
		tagsToSearchFor: 'mvpsummit,mvp2013,mvp13', 
		flickrApiKey: 'insert your key here', 
		paginationSelector: '#flickr-pagination'
	}
);

Download the plugin from GitHub at: https://github.com/jguadagno/twbs-flickrCarousel

See an example of usage at: http://mvp2014.mvpsummitevents.info/flickr

Taking the “Leap” to Everleap

For the past 5+ years I’ve had a few different sites hosted at Discount ASP.NET, this site being one of them. Recently, Discount ASP.NET released a new product in the web hosting arena, Everleap. Everleap is a new cloud based hosting solution.  I know, the word “cloud” is massively overused nowadays.  Everleap differs from other solutions as it uses the Windows Azure Pack for it’s services. The Windows Azure Pack is the same technology that Microsoft uses to run their own Windows Azure hosting platform. Microsoft has made Azure technologies available to their partners so they can build public and private cloud offerings that run in the their own data centers. For more on the Windows Azure Pack check out http://www.everleap.com/cloud-hosting/features/azure-pack-hosting/

The move to Everleap

The move to Everleap was easy considering I already had my site on Discount ASP.NET

  1. Open up an Everleap account: Cloud Websites or Multi-Domain Cloud
  2. Create a Discount ASP.NET support ticket requesting the move
  3. In a few hours or so, the new sites were created and moved over. They even updated web.config with the new database connection strings and smtp settings.
  4. If you do not use Discount ASP.NET to register your domains, you will have to log in to your registrar to update the DNS servers to point to the new Everleap DNS servers.

That was it.

If you need a scalable site where you can increase and decrease the number of servers as needed and want predicable billing, Everleap might be the solution for you.

Disclaimer: I was given a free Everleap account to host this site and other community sites that I run like Desert Code Camp. This is not a sponsored post.

Foursquare Autocomplete jQuery Plugin

This post will go over implementing the foursquare Autocomplete jQuery plugin. In the upcoming days (weeks) I will have a few blog posts on using the foursquare API with C#.

A few months ago I was making updates for the MVP Summit Events site, one of the features I wanted to add was foursquare integration to the site. I was thinking that it would be cool for each of the parties listed on the site, to show how many people have checked in to that event (venue) on foursquare. This way you could see what parties to attend and which ones to avoid :).

In order to determine who was checked in at one of the events, I needed to add the foursquare venue id to all of my venues. For the existing venues, I manually added the foursquare venue id but for new venues I was thinking of making the user experience as easy as possible, a user should enter a few characters and get venues in the area with those characters. The first thing that popped into my head was to use an auto complete control and use foursquare as the data source. So after “Googling it with Bing” I found that there was one control that did this but no longer worked. So what does every good developer do, re-invent the wheel :).

Getting Started with the foursquare API

Just like most social media sites now, foursquare has a REST based API. Foursquare provides a quick start guide to get you started using their API. In order to get started with the foursquare API you will need the following:

foursquare does have many API end points for accessing their data. After checking out several of them I decided to go with the Suggest Completion Venues end point even though (at the time of this writing it was an experimental feature).

Suggest Completion End Point

According to the API end point documentation for the Suggest Completion end point, the end point provides a list of mini-venues partially matching the search term, near the location.

The method uses the HTTP GET verb and has two required parameters; ll and query. The ll parameter which is the latitude and longitude of the users location (or search area) . And the query parameter is the string you want to search for. The results that get returned is an array of mini venues (essentially an arrays without a lot of extra properties, just the minimum set required for suggestion.

This was perfect for my needs.

Creating the plugin

I decided to go with using the auto complete widget from the jQuery UI, use the suggest completion end point from foursquare and turn it into a jQuery plugin. Unfortunately I have never created a jQuery plugin before, however, I was lucky enough to run across a post from a buddy of mine Elijah Manor on How to Create Your Own jQuery Plugin.

After a few hours of fiddling around with the cost from the blog post above I eventually figured it out and got it to work. The resulting control looks like this:

image

In order to use the foursquare jQuery auto complete plugin you will need to include on your page, jQuery, jQuery UI, one of the jQuery UI themes and this plugin.

I’ve also included a sample page to get you started. It has a bunch of styles to make the use of the plugin a little cleaner.

4sqautocomplete

Once you have the required files referenced on your page, you can “foursquare auto complete” a textbox by calling the foursquareAutocomplete method as shown here:

$("#venue").foursquareAutocomplete({
  'latitude': 47.22,
  'longitude': -122.2,
  'oauth_token': "your oauth token",
  'minLength': 3,
  'search': function (event, ui) {
    $('#venue-name').html(ui.item.name);
    $('#venue-id').val(ui.item.id);
    $('#venue-address').html(ui.item.address);
    $('#venue-cityLine').html(ui.item.cityLine);
    $('#venue-icon').attr("src", ui.item.photo);
    return false;
  },
  'onError' : function (errorCode, errorType, errorDetail) {
    var message = "Foursquare Error: Code=" + errorCode + 
    ", errorType= " + errorType + 
    ", errorDetail= " + errorDetail;
    log(message);
  }
});
Properties and Events
Name Description
latitude The latitude where you want to look for the venue.
longitude The longitude where you want to look for the venue.
oauth_token Your foursquare oauth token.
minLength The minimum length the text should be before you kick off the search.
search This event is fired once the user selects a venue from the list.
onError This event is fired if there is an error returned from the foursquare REST API.
onAjaxError This event is fired if there is an error making the call to the foursquare REST API.

Handling the results

Once a user selects the venue from the list, the search event is raised. The search event has two parameters:

  • Event: The event
  • Item: the foursquare venue that was returned.

The item that is returned is a custom object that provides the basic address properties for the venue. The properties combined, will look like a US formatted address and will take into account fields that are not populated in foursquare.

image

Item properties
Property Name Description
name The name of the venue
id The foursquare venue id
address The address line (formatted like a US address) address1, address2
cityLine The city line (formatted like a US address). Chandler, AZ 85286
photo The 32 pixel image that foursquare uses for the venue.
full The entire mini-venue response returned from foursquare.

Conclusion

It took a while for me to figure out all of the parts needed to create the jQuery plugin but overall I think it was worth it. Again this is my first venture into creating a jQuery plugin, so if it is way off, let me know.

Using an ASP.NET DataRepeater ItemTemplate to create a jQuery Mobile Nested List with List Dividers

The jQuery Mobile framework has a list view widget that displays unordered lists in several different ways. In the process of converting the Microsoft Global MVP Summit mobile site to use jQuery Mobile I wanted to change the way I displayed the events. The idea was to have a header for each date that there was an event along with some of the details of the event. Clicking on the event would take you the to event details page.

To accomplish this I used the count bubble, list dividers, content formatting and the search filter bar features of jQuery Mobile.

First let’s look at the HTML, for the sake of brevity I removed the ID fields from the HTML.

<ul data-role="listview" data-inset="true" data-theme="d" data-filter="true">
	<li data-role="list-divider">2/25/2012<span id="EventCount_0" class="ui-li-count">1</span></li>
	<li>
		<a href="/m/e.aspx?Id=45">
			<h3><span>Northwest Harvest at MVP Summit 2012</span></h3>
			<p><strong><span>Northwest Harvest Warehouse</span></strong></p>
			<p class="ui-li-aside"><span>from 11:30 AM to 5:00 PM</span></p>
		</a>
	</li>
	<li data-role="list-divider">2/27/2012<span class="ui-li-count">2</span></li>
	<li>
		<a href="/m/e.aspx?Id=48">
			<h3><span>Consumer Camp: Bellevue</span></h3>
			<p><strong><span id="VenueName_0">Microsoft Store: Bellevue</span></strong></p>
			<p class="ui-li-aside"><span>from 5:00 PM to 8:00 PM</span></p>
		</a>
	</li>
	<li>
		<a href="/m/e.aspx?Id=46">
			<h3><span>First Time MVPs Event</span></h3>
			<p><strong><span>Rockbottom - Top of the Rock</span></strong></p>
			<p class="ui-li-aside"><spa>from 6:00 PM to 9:00 PM</span></p>
		</a>
	</li>
</ul>

From this HTML markup the jQuery Mobile framework will generate a view that looks like this:

image

The jQuery Mobile ListView

Creating the ListView

The start of the unordered list, Line 1, has 4 attributes:

<ul data-role="listview" data-inset="true" data-theme="b" data-filter="true">

The data-role of listview tells the jQuery Mobile framework to use the jQuery Mobile Listview widget. Setting the data-inset attribute to true tells the jQuery Mobile framework to indent the list view and add the rounded edges. The data-theme attribute tells jQuery Mobile to use the dtheme. Setting the data-filter equal to true tells the jQuery Mobile framework to add the filter items text box up top. No additional work is needed to add the filter, it will search all of the ListItems that are part of this unordered list who’s data-role attribute is not set to list-divider for the text entered.

The List Divider

Adding the data-role of list-divider (Line 2 of the initial example) will make that list item appear as a divider. You can use this attribute to group items, in my case, I grouped by date.

To establish the count bubble you will need to wrap the count of item around a span tag and give it the class of ui-li-count, as shown in Line 2.

Here’s an annotated image with markup.

image

The item in red is the individual list item which will be discussed in the next section.

The Items

Each sub item under the list divider needs to be it’s own Anchor element ( A ) wrapped in a ListItem (LI) tag as shown in lines 3-9 and 11-24 above.

<li>
  	<a href="/m/e.aspx?Id=45">
		<h3><span>Northwest Harvest at MVP Summit 2012</span></h3>
		<p><strong><span>Northwest Harvest Warehouse</span></strong></p>
		<p class="ui-li-aside"><span>from 11:30 AM to 5:00 PM</span></p>
	</a>
</li>

Each LI formatted above will generate a “row” as highlighted in the red boxed image above within your browser. Clicking on one of those links will take you to the page specified in Anchor tag. In order to get the times to “float” to the left, you will need to use the ui-li-aside class. Note, the > image will get added automatically by the framework.

Creating the jQuery ListView with an ASP.NET DataRepeater Control

In order to accomplish this, I went with a DataRepeater within a DataRepeater . The first, or outside, DataRepeater (DateRepeater)will get a list of distinct dates from the data store in order to create the List Dividers. The second, or inner, DataRepeater (EventRepeater) will list all of the events for the day specified by the DateRepeater.

Let’s take a look at the code:

<asp:Repeater runat="server" ID="DateRepeater" DataSourceID="EventDatesDataSource" OnItemDataBound="DateRepeaterOnItemDataBound">
	<HeaderTemplate>
		<ul data-role="listview" data-inset="true" data-theme="d" data-filter="true">
	</HeaderTemplate>
	<ItemTemplate>
		<li data-role="list-divider"><%# Container.DataItem %>
			<asp:Label runat="server" ID="EventCount" class="ui-li-count"></asp:Label>
		</li>
		<asp:Repeater runat="server" ID="EventRepeater" OnItemDataBound="EventRepeaterOnItemDataBound">
			<ItemTemplate>
				<li>
					<asp:HyperLink runat="server" ID="EventUrl">
						<h3><asp:Label runat="server" ID="EventName" /></h3>
						<p><strong><asp:Label runat="server" ID="VenueName"></asp:Label></strong></p>
						<p class="ui-li-aside"><asp:Label runat="server" ID="EventDate"></asp:Label></p>
					</asp:HyperLink>
				</li>
			</ItemTemplate>
		</asp:Repeater>
	</ItemTemplate>
	<FooterTemplate>
		</ul>
	</FooterTemplate>
</asp:Repeater>

In lines 2-4, using the HeaderTemplate property of the DateRepeater DataRepeater control I create the initial ListView. It is then closed in the lines 21-24 using the FooterTemplate of the DateRepeater DataRepeater control. Next in the ItemTemplate property (Line 6-8) of the DateRepeater DataRepeater control, I create a list divider by adding a ListItem (LI) with the data-role of list-divider with a label for the date. Line 7 has a label control with a class of ul-li-count that holds the count of events that date.

Now within the ItemTemplate property of the DateRepeater DataRepeater control I also have another DataRepeater, EventRepeater. This DataRepeater will iterate through all the events for a day and create the individual ListItems (LI) for each event on that day (Lines 11-17). Notice how the ListItem is wrapped in an ASP:HyperLink control. This will provide the hyperlink to the event details page.

That sums up creating jQuery Mobile listview using an ASP.NET DataRepeater control.

Converting an ASP.NET “Mobile” site to use jQuery Mobile

Building upon my previous post Introduction to jQuery Mobile, I wanted to share how I converted the Microsoft Global MVP Summit mobile site to use jQuery Mobile.

Getting Started

The first step was to look at the existing ASP.NET Master Page that the site was using and see where I had to make changes.  I included the skeleton mobile master page, prior to jQuery Mobile below.  Please note, I removed parts of the page that do not relate to the blog post.

<%@ Master Language="C#" 
	AutoEventWireup="true" 
	CodeBehind="Mobile.master.cs" 
	Inherits="MVPSummitEvents.Website.Mobile" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
	<title>MVP Summit Events - Mobile - </title>
	<asp:ContentPlaceHolder ID="head" runat="server">
	</asp:ContentPlaceHolder>
</head>
<body>
	<form id="form1" runat="server">
	<div id="mHead"><h1>MVP Summit Events</h1></div>
	<div id="mMenu">
		<asp:HyperLink runat="server" ID="hlMain" 
			NavigateUrl="~/m/default.aspx" Text="Home" ToolTip="Home" /> | 
		<asp:HyperLink runat="server" ID="hlMap" 
			NavigateUrl="~/m/map.aspx" Text="Map" ToolTip="Map" /> | 
		<a href="http://tinyurl.com/4e5mp5p" 
			title="Windows Phone 7 App">Window Phone 7</a> App. |
		<a href="http://itunes.apple.com/us/app/mvp-events/id416291827?mt=8">iPhone</a> App.
	</div>
	<div id="mBody">
		<asp:ContentPlaceHolder ID="CphBody" runat="server">
		</asp:ContentPlaceHolder>
	</div>
	</form>
	<div id="mFoot">Copyright ©2009-2012, 
		<a href="//www.josephguadagno.net" title="Joseph Guadagno">Joseph Guadagno</a> | 
		<a href="http://twitter.com/jguadagno" title="Follow jguadagno">@jguadagno</a> | 
		<a href="mailto:jguadagno@sevdnug.org">Contact</a>
	</div>
</body>
</html>

Converting the document head

The first thing I needed to do was to update the DOCTYPE on line 3 to

<!DOCTYPE HTML>

Next was to include the jQuery Mobile scripts and css files, after that my head section looked like this:

<%@ Master Language="C#" 
	AutoEventWireup="true" 
	CodeBehind="Mobile.master.cs" 
	Inherits="MVPSummitEvents.Website.Mobile" %>
<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
	<title>MVP Summit Events - Mobile - </title>
	<meta name="viewport" content="width=device-width, initial-scale=1"> 
	<link rel="stylesheet" 
		href="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.css" />
	<script type="text/javascript" 
		src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
	<script type="text/javascript" 
		src="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.js"></script>
	<asp:ContentPlaceHolder ID="HeadContent" runat="server" />
	<link id="Link1" rel="stylesheet" runat="server" href="/css/m.css" />
	<script type="text/javascript" src="../js/analytics.js"></script>
	<script type="text/javascript" src="../js/analytics.jqmobile.js"></script>
</head>

Again, I removed parts that are not required for this post.

You should notice that line 5 is now different and I added lines 9 – 15. Line 9 contains the viewport meta tag, the description from the jQuery Mobile docs is …

Note above that there is a meta viewport tag in the head to specify how the browser should display the page zoom level and dimensions. If this isn’t set, many mobile browsers will use a "virtual" page width around 900 pixels to make it work well with existing desktop sites but the screens may look zoomed out and too wide. By setting the viewport attributes to content="width=device-width, initial-scale=1", the width will be set to the pixel width of the device screen.

Lines 10-15 contain the references to jQuery Mobile style sheet, the jQuery library and the jQuery Mobile library. Line 19, is a work around for using Google Analytics which is described here.

Converting the Document Body

Looking at the body of the Master Page, I was almost ready for the jQuery Mobile conversion.

<div id="mHead"><h1>MVP Summit Events</h1></div>
<div id="mMenu">
	<asp:HyperLink runat="server" 
		ID="hlMain" 
		NavigateUrl="~/m/default.aspx" 
		Text="Home" ToolTip="Home" /> | 
	<asp:HyperLink runat="server" 
		ID="hlMap" 
		NavigateUrl="~/m/map.aspx" 
		Text="Map" ToolTip="Map" /> | 
	<a href="http://tinyurl.com/4e5mp5p" 
		title="Windows Phone 7 App">Window Phone 7</a> App. |
	<a href="http://itunes.apple.com/us/app/mvp-events/id416291827?mt=8">iPhone</a> App.
</div>
<div id="mBody">
	<asp:ContentPlaceHolder ID="CphBody" runat="server">
	</asp:ContentPlaceHolder>
</div>
<div id="mFoot">Copyright ©2009-2012, 
	<a href="//www.josephguadagno.net" title="Joseph Guadagno">Joseph Guadagno</a> | 
	<a href="http://twitter.com/jguadagno" title="Follow jguadagno">@jguadagno</a> | 
	<a href="mailto:jguadagno@sevdnug.org">Contact</a>
</div>

I have my Master Page broken up into a header, menu, body, and footer. All I had to do was assign the jQuery Mobile data-role attributes and I was done. However I took this time to “tweak” the layout of the mobile site look more like it would on the iPhone and other mobile devices. I still keep the header, but moved the menu to the footer section and moved the existing footer to an about page. The new body of the mobile Master Page looks like this.

<div data-role="page">    
	<div data-role="header" data-theme="b">
		<h1><asp:Label runat="server" ID="HeaderLabel"></asp:Label></h1>
	</div>
	<div data-role="content" data-theme="b">
		<asp:ContentPlaceHolder ID="BodyContent" runat="server">
		</asp:ContentPlaceHolder>  
	</div>
	<div data-role="footer" data-theme="b">
		<div data-role="navbar">
			<ul>
				<li><asp:HyperLink runat="server" 
					NavigateUrl="~/m/default.aspx" data-icon="home">Home</asp:HyperLink></li>
				<li><asp:HyperLink runat="server" 
					NavigateUrl="~/m/map.aspx" data-ajax="false">Map</asp:HyperLink></li>
				<li><asp:HyperLink runat="server" 
					NavigateUrl="~/m/Apps.aspx">Apps</asp:HyperLink></li>
				<li><asp:HyperLink runat="server" 
				NavigateUrl="~/m/About.aspx" data-icon="info">About</asp:HyperLink></li>
			</ul>
		</div>
	</div>
</div>

To me this seems quite readable and clearly identifies what each section (div) is responsible for.

Let’s break it down.

First all the previous DIV’s in between the FORM tags where placed within a

<div data-role="page"></div>

tag. The next step was to convert each of the DIV’s that I had into a jQuery Mobile DIV. There is really no ‘jQuery Mobile DIV’ just an attribute that tells jQuery what “section” of the document this div is for. I added the data-role=”header” to the DIV with the ID of mHead, I added the data-role=”content” to the DIV with the ID of mBody and I added the data-role=”footer” to the DIV with the ID of mFooter.

“Ok but what happened to the mMenu DIV” you ask. Take a look at line 8 in the code sample above. I moved the “menu” to the footer of the new document and assigned it a data-role of navbar. This is a jQuery Mobile widget that creates a simple menu of buttons out of all of the listitem elements of the unordered list. The data-icon attribute is an attribute that allows you to indicate one of the 18 built in icons for any jQuery Mobile button.

After this, I was done. I now have a jQuery Mobile version of the Microsoft Global MVP Summit site that looks the same on virtually every mobile browser with little to no work.

Up next, how to convert other elements of an ASP.NET mobile site to use jQuery Mobile widgets.

Using Bing Maps Web Services Imagery Service

In my previous post, Using the Bing Maps Web Services for Geocoding Addresses, I talk about geocoding addresses using the Bing Maps Web Services. Now it is time to talk about getting imagery of maps, roads or aerials views for addresses or geocodes.

In order to get started using the Bing Maps Web Services, check out the previous post Getting Started section.

Bing Maps Web Services

Bing Maps Web Services is a set of Web services that allow you to add mapping and search functionality to your application, including location finding, map imagery, and routing capabilities. For example, you can:

Use the Imagery Service to:

  • Return a link to a map with a pushpin at a specific location
  • Provide a road map or bird’s eye or aerial imagery to you application

Use the Route Service to:

  • Get directions that include traffic warnings and route hints between multiple locations.
  • Get directions from all major roads to a destination (1-click directions, also referred to as a “party map”) and then use the Imagery Service to map those routes.

For this post we will cover the Imagery service.

Just like the Geocode Service, there is a request, MapUriRequest, and response, MapUriResponse, object for the Imagery Service.

In order to get the Uri to display a map in your application you will need to use the imagery service client, ImageryServiceClient. The ImageryServiceClient needs to be instantiated with the WCF endpoint to use, by default it should be ‘BasicHttpBinding_IImageryService’. Then call the GetMapUri method passing your MapUriRequest object.

ImageryServiceClient imageryService = 
    new ImageryServiceClient("BasicHttpBinding_IImageryService");
MapUriResponse mapUriResponse = imageryService.GetMapUri(mapUriRequest);
Building the MapUriRequest

The MapUrilRequest has two properties that need to be populated; the Credentials property which should contain you Bing Maps Id and either the Center, MajorRoutesDestination, or Pushpins property.  The code snippet below demonstrates instantiating the MapUriRequest and setting the properties based on values passed into a method (outlined later).

MapUriRequest mapUriRequest = new MapUriRequest
    {
      Credentials = new Credentials {ApplicationId = appId},
      Pushpins = pushpins,
      Center = new Location {Latitude = latitude, Longitude = longitude}
    };

Now you can customize the options for the map using the MapUriOptions property of the MapUriRequest object. Here is a list of the properties from the MSDN documentation:

Property name Description
DisplayLayers A string array indicating the layer data to display on the map. Optional. The default value is null.
ImageSize A SizeOfint Class object specifying the height and width of the image to return. Optional. The default width is 350 and the default height is 350.
ImageType An ImageType Enumeration value specifying the format of the image to return. Optional. The default value is ImageType.Default, which means the default changes depending on the map style specified.
PreventIconCollision A bool indicating whether or not to separate pushpin icons that are close to each other on the map so that they are more visible. Optional. The default value is false.
Style A MapStyle Enumeration value specifying the map style of the image to return. Optional. The default value is MapStyle.Road.
UriScheme A UriScheme Enumeration value specifying the URI scheme to return. Optional. The default value is UriScheme.Http.
ZoomLevel An int indicating the zoom level of the map to return. Optional.

Assigning some of the options:

// Set the map options
MapUriOptions mapUriOptions = new MapUriOptions();
mapUriOptions.Style = MapStyle.Road;
mapUriOptions.ZoomLevel = zoom;
mapUriOptions.ImageSize = new SizeOfint {Height = height, Width = width};
// Set the options property of the request.
mapUriRequest.Options = mapUriOptions;

Now you are ready to call the image service client to get the MapUriResponse.

ImageryServiceClient imageryService = 
    new ImageryServiceClient("BasicHttpBinding_IImageryService");
MapUriResponse mapUriResponse = imageryService.GetMapUri(mapUriRequest);

Here is a helper class, Imagery.cs,  which wraps the GetMapUri function with 8 different overloads.

Working with the MapUriResponse

The MapUriResponse object has three properties:

Name Description
BrandLogoUri The System.Uri of the Bing Maps brand logo image.
ResponseSummary A ResponseSummary Class object describing the response that was returned by the service.
Uri A string that is the URI of the requested map.

For brevity sake, we will just use the Uri property.  You should, though, for good programming practices, check the ResponseSummary property for any exceptions.

string mapUri = Imagery.GetMapUri("YourAppId", 47.62, -122.2);
imgMap.imageUrl = mapUri;

This call retrieve the Uri to use to display a 200×200 road map of the area at latitude 47.62 and longitude -122.2 with a zoom of 14, which is downtown Bellevue, WA.

image

If you want to add pushpins or markers similar to the above image you will need to populate the an array of PushPin objects. A PushPin object has an IconStyle which is the type of icon to use, a Label which an optional text to display on the pushpin (only works with certain pushpins) and the Location which contains the latitude and longitude that the pushpin should be located at.

That’s it.  It seems like a lot of work for a one line call.  With the attached Imagery.cs class, a lot of the overhead work was done for you.

Using the Bing Maps Web Services for Geocoding Addresses

For the MVPSummitEvents and Mix10Events site I wanted to create a map of all of the events listed on the site. In order to do that I needed to Geocode all of the addresses for the events.  There are several services out there for geocoding an address, Microsoft, Yahoo, and Google provide this service as well as others.  I decided to go with the Microsoft Bing services, being a Microsoft MVP.

Getting Started

Let’s get started. MSDN has just about everything you need to get started with using the Bing Map Web Services.

Step 1: The first step is to get a key or token to use in your application for the Bing Maps Web Services application. This can be done by visiting the Bing Maps Account center and clicking on Create a Bing Maps account.

Step 2: If you are using Visual Studio, add a service reference to one or more Bing Maps Web Services that provide the features you need. See the Generating Client Proxy Classes topic and the Bing Maps Web Services Metadata topic.

VirtualEarthWebServicesWhether you used Visual Studio or the svcutil application you should have one file, most likely named VirtualEarthWebServices.cs. The file will contain a bunch of wrapper classes around the Bing Maps Web Services, and the required Windows Communication Foundation (WCF) classes. You will also see the generated configuration settings for the app or web config files.

Step 3: Set every Bing Maps Web Services request a valid Credentials property. You will see more on this in a bit.

Geocoding an Address

There are two properties that are required to successfully request a GeoCode for an address.

  1. 1) Set the Credential Property of the GeoCodeRequest object
  2. 2) Set either the Query property or Address property of the GeoCodeRequest object.

Here is a helper function that wraps the call to GeoCodeRequest.

/// <summary>Gets the location.</summary>
/// <param name="appId">The app id.</param>
/// <param name="address">The address.</param>
/// <returns></returns>
public static GeocodeResponse GetGeocodeResponse(string appId, string address)
{
    GeocodeRequest geocodeRequest = new GeocodeRequest
      {
          Credentials = new Credentials {ApplicationId = appId},
          Query = address
      };
    ConfidenceFilter[] filters = new ConfidenceFilter[1];
    filters[0] = new ConfidenceFilter {MinimumConfidence = Confidence.High};
    GeocodeOptions geocodeOptions = new GeocodeOptions {Filters = filters};
    geocodeRequest.Options = geocodeOptions;

    GeocodeServiceClient geocodeServiceClient = 
    	new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
    return geocodeServiceClient.Geocode(geocodeRequest);
}

This method will return a GeocodeResponse object. The GeocodeResponse object contains three properties that are populated based on the query.

Name Description
BrandLogoUri The System.Uri of the Bing Maps brand logo image. (Inherited from the ResponseBase Class.)
ResponseSummary A ResponseSummary Class object describing the response that was returned by the service. (Inherited from the ResponseBase Class.) This class returns any exceptions that we raised during the request.
Results A GeocodeResult Class array, where each element is a possible match returned by the Geocode Service.

To keep this article short(er) I will just cover the Results object. Depending on the Confidence filter and Geocode options that were set in the call you could receive more than one result.

Let’s assume that we only want to work with the first result and get the Geocode for “1 Microsoft Way, Redmond, WA”. We simply call the static method of GetGeocodeResponse and pass in the Bing Maps API key and the address to search for.

var address = "1 Microsoft Way, Redmond, WA";
GeocodeResponse response = GetGeocodeResponse(appId, address);

Assuming the address was found we can now work with the properties of the GeocodeResult class to find out the Geocode.  The Geocode is located in the Locations property which is an array of GeocodeLocation objects. If the Count of the Locations is greater than one, let’s just take the first one and update the txtLatitude and txtLongitude objects.

if (response.Results != null)
{
	var geocodeLocation = response.Results[0].Locations[0];
	if (geocodeLocation != null)
	{
	    txtLatitude.Value = geocodeLocation.Latitude;
	    txtLongitude.Value = geocodeLocation.Longitude;
	}
	else
	{
	    txtLatitude.Value = txtLongitude.Value = 0;
	}
}

That’s it. Next up, using the Bing Maps Web Services for getting map images.

Add an iCal feed to Sitefinity

iCal feeds let you share your and/or import your events that are stored in Sitefinity.  Here is a library that will let you generate an iCal feed from Sitefinity. Future versions of this library might have us filtering by categories or date.

iCal feed for Sitefinity CalendarHandler_2

I’ve made a few changes since the last release to include some bug fixes.

  • Added Google and Outlook friendly fields in the feed file to describe the iCalendar file as well as the publisher.
  • Added code to the Location and Description fields to keep them at 75 characters or less to comply with the iCal specifications.

Installation

web.config changes

First you need to tell ASP.NET about your new handler. Open up the web config file and look for the httpHandlers section, it’s parent is system.web and add the following:

<add verb="GET" path="GetICSFile.ashx" type="SEVDNUG.Web.HttpHandlers.CalendarHandler, App_Code"/>

Note: The path name can be changed to any legal value like “feeds/ical.ashx” or “ical.ashx”.

Files

Copy the vCalendar.cs and CalendarHandler.cs files to the App_Code directory of your Sitefinity installation.

Customize

Getting the event data from Sitefinity and creating the iCalender objects is handled inside the CalendarHandler class.

The class assumes that your events provider is named “Events”, if not you will have to change line 25 of the class.

The class maps the following fields to an iCalendar event.

iCalendar event Sitefinity Field
Description Content
Location LocationName (Meta Field)
Summary Title (Meta field)
Url UrlWithExtension
DTStart Start
DTEnd End

I believe these meta values are the default meta keys from Sitefinity. If your values differ, you can modify them on lines 64 and 65.

Sitefinity: Random Generic Content Control

One of the many features of Sitefinity is the ability to create custom controls to customize the look and feel of your website. The website for the Southeast Valley .NET User Group contains several custom controls. In the next few weeks I will post all of the controls here.

Sponsor ImageOn to the Random Generic Content Control. The purpose of the control is randomly display items that are based on a Generic  Content provider. I use this control to randomly pick sponsors of the Southeast Valley .NET User Group to display on the home page. Here is a snapshot of the control in use.

Installing the Control

Installing the control is a three part process.

The first step is to add the control to Sitefinity.  This can be done one of three ways.  Which way you choose depends on your technical ability. Here is a list of options in order of least technical to most technical.

  1. Add the class RandomGCControl.cs in the zip file to the App_Code folder of your Sitefinity project.
  2. Create a Visual Studio class library project, add the RandomGCControl.cs class to it. You will need to add the following references to the project; Telerik.Cms, Telerik.Cms.Engine, Telerik.Cms.Web.UI, Telerik.Framework, Telerik.Personalization, and Telerik.Web.UI. Compile the class, then upload it as documented by the Sitefinity article “Adding Controls
  3. Create a separate class project as outlined in the step above  then add a reference to this project to your Sitefinity project.

The next step is let Sitefinity know about the new control. Note: this step is not required if you compiled the control and uploaded it through the Sitefinity interface. To do this you need to modify the web.config file.  The controls are listed in the cms/toolboxControls section. Add the following:

<add name="Random Generic Content"
	section="SEVDNUG"
	type="SEVDNUG.Web.Sitefinity.WebControls.RandomGCContent, SEVDNUG.Web.Sitefinity.WebControls"
	description="Displays a random generic content items"
/>

If you followed the steps, the next you go to edit a page in Sitefinity you should see the Random Generic Content control available in the SEVDNUG group.

Configuring the Control

The Random Generic Content control has four properties that you need configure.

Property name Function
Item List Template File (Appearance Section) Controls the overall look of items that appear. This file dictates the display of the generic content.
Generic Content Details Url (Appearance section) This property points to the single page where you want Sitefinity to navigate to when an item is clicked. This is typically the same page that hosts this generic item.
Number Of Items (Data section) Indicates how many generic items to display.
Provider Name (Data Section) Indicates which generic item provider to use.

Customizing the Control

To customize the display of the control, you will need to edit the file that you specified in the Item List Template File property of the control.  There is a sample template in the attached file.

<div class="topSponsorsList">
    <h2 class="sf_listTitle">Random Content</h2>
    <h3>
        <asp:Literal ID="GCTitle" runat="server"></asp:Literal>
    </h3>
    
    <asp:Repeater ID="GCRepeater" runat="server">
        <HeaderTemplate><ul class="sf_simpleList">
		</HeaderTemplate>
        <ItemTemplate>
            <li class="sf_simpleList">
                <asp:Literal ID="Name" runat="server" />
            </li>
        </ItemTemplate>
        <FooterTemplate></ul></FooterTemplate>
    </asp:Repeater>
</div>

The control will look for form field names that match the names of the meta keys for that provider and replace them with the value of the meta key.

Here is an example of the sponsor template used to generate the image above.

<asp:Repeater ID="GCRepeater" runat="server"> 
	<HeaderTemplate><ul class="sponsorList"></HeaderTemplate> 
	<ItemTemplate> 
		<li class="sponsorList"> 
			<asp:HyperLink ID="fullContent1" runat="server"> 
    		<img src='<asp:Literal ID="Company_Logo_Url" runat="server" />' 
    			alt= '<asp:Literal ID="Company_Name" runat="server" />' 
    			width="120" height="50" onError="img2txt(this)" /> 
			</asp:HyperLink> 
		</li> 
	</ItemTemplate> 
	<FooterTemplate></ul></FooterTemplate> 
</asp:Repeater> 
<script> 
	function img2txt(img) {
		txt = img.alt;
		img.parentNode.innerHTML=txt;
	} 
</script>

Hopefully you will find this control useful.  Look for some more controls a providers soon.

%d bloggers like this: