Showing posts with label Other. Show all posts
Showing posts with label Other. Show all posts

Sunday, September 22, 2013

A Website That May Never Be Public

Around two years ago a friend of mine and I started working on a project on fashion business in our spare times. My friend has some connections in clothing manufactures and found some opportunity on it. So he came up an idea that we could build a platform to bridge fashion designers and the customers directly.

Unlike TeeSprint and TeeSpring where you could get commodity products, we offered limited quantity of custom made clothing by named designers. We targeted on those designers who received rewards in recent years. They may not be as famous as those top names, but they have great potential and many of them already have quite a number of followers. With our platform, designers will have a channel to sell their products, and those people who desire unique fashion can buy the custom design clothing with moderate price. The price will be relative low because they will be made directly from the manufacture without other intermediate costs. In addition, designers themselves will introduce our site to their followers, another save of marketing cost. Of course we expected a lot of challenges but we believed there's still a chance. He was in charge of the business aspects and I mainly worked on technical stuff.

About a year ago we had built a complete eCommerce website with some cool features. We also had an agreement with a manufacturer who makes high-end clothing (they OEM some famous brands). Everything was ready to set our business online except the key part: not many designers trust us. They just don't believe an unknown small company in Canada without fashion background would actually help them to sell their design and products. Some designers who had positive feedback at the beginning didn't end up doing business with us.

That was really tough. At some point we realized that without some help from an influential person in the fashion field our approach may not work at all. But it's hard to find such a person to join us. We didn't have money to promote our idea and prove ourselves. If we would have met those designers in person and presented them some nice samples made by the manufacture, there may be another story of ending.

Time flies and lives move on. My friend got his first baby last month and he enjoys the new role of being a father. We haven't talked much about the website and the designer sign-on topic recently as we both knew it's not working out and it's basically failed. The initial business build up can't last that long. If you can't launch such online business after two years of work, then it may never be launched in the future. The website is still running in a secret domain and it may never be public. It's simply sad.

On the other hand, although we did not succeed the way we would have hoped for, we did learn a lot in the whole process. For me those are valuable experience.

Friday, October 12, 2012

Eclipse Tips

I mainly use Visual Studio for development in the past 8 years. Recently I switch to Eclipse to do some Android work. Not like old days I had to spend a lot of time on memorizing a list of commands to run the vi editor, modern IDEs are quite easy to work with, but the right settings and handy short-cuts can still speed up your work. Below is some of my findings on Eclipse that helps me to do my work more efficiently.

Preference Settings:

1. Show code line number:

I am not sure why both Eclipse and Visual Studio are not showing line number by default. The line number is quite useful for me to pin point the source code, so I turn it on the first place.

2. Save before build but not automatically build.

Unlike Visual Studio Eclipse will not save your changes when you click build or run the application. On the other hand, Eclipse automatically build(compile) the source files in the background every time you make a change in source file. I don't like both default options and here is where you can change the behavior:

3. Enable auto insert:

This is a nice feature in Eclipse which is not available in Visual Studio or I am not aware of. Basically you can type ";" or "{" anywhere during coding and Eclipse will automatically put it to the right spot, the ending of the code line.

4. Enable step filters:

With “Step Filters” you will skip stepping into those types during debugging, so you could just focus on your own code.

Handy short-cuts

Ctrl+Space content assist just like intellisense in Visual Studio
Ctrl+Shift+F format code
Ctrl+/ comment/uncomment code with //
Ctrl+Shift+/ comment code with /**/
Ctrl+D delete line
F3 go to declaration
Ctrl+Shift+O auto import (when this available in Visual Studio?)
Ctrl+T show type hierarchy
Ctrl+Shift+T search for type
Ctrl+Shift+R search for resource
Ctrl+Shift+G find all references
Ctrl+H open advanced search window
Alt+Left/Right navigate source back and forward like Ctrl-/+ in Visual Studio

Monday, September 24, 2012

Android Experience

Nowadays electronic gadgets are so pervasive. I have iPhone, iPad, multiple laptops and desktops at home. Recently I got a Nexus 7 tablet, my first Android device. What really impressed me is its easiness of development process.

Apple products are cool, no doubt about it. But you have to have a physical Mac machine to work on iOS/Mac apps. In addition you need to register the developer license which cost $99/year. Apple defines quite a bit of restriction and rules to mark sure they have full control of the Apple nation. Apple's main focus is user experience, not much for developers. Many people claim Object C and XCode the worst development environment comparing with other popular languages and IDE in the market. However, due to Apple's huge crowd of so called high-end and loyal customers, more and more developers are joining this not so friendly platform.

On the other hand, Windows phone as a late-catch-up follower, surprisingly, still requires the same $99/year fee too. With registration done, you need to install the commercial Visual Studio IDE, Windows phone SDK and that notorious Zune package to develop a simple app to run on a Windows phone handset. Should they have made all free on the first day when realizing they were way behind Apple and Google? I love C# and .NET, but I feel sad about those dump decisions made by Microsoft.

In the Android world things are very different. You only need to pay one-time $25 registration fee to publish your app to the public. It's totally free for you to do any coding experience on your own Android devices. Unlike proprietary object C and C#, you will use Java and eclipse to program the Android apps. Java is the most used object-oriented programming language (source from Tiobe) in the past few years, and open-source eclipse is a popular IDE for many programming languages for years. All Java developers would easily switch to Android development.

Yesterday I downloaded the free Android SDK, unzipped it (no need to install anything), and I was able to open eclipse IDE to create a new Android project. After installed the USB driver for Nexus 7 I could connect the tablet to my development machine using USB cable, within 30 minutes, my first "Hello World" Android app was running in the Nexus 7. The only problem I had was the Android emulator which is super slow and basically useless. But running and debugging the code via a physical device is easy and fast.

Android devices become so popular in just a few years. Will Android rules the mobile world as Microsoft dominates PC world in the past 30 years? No one knows, but people like Android for reasons. From a developer point of view, it's free, open and easy to work with. All that is a nice invitation to developers to join the Android world.

Thursday, March 08, 2012

A Lesson Learned From A SharePoint Patch Installation

A busy morning started from tons of reported issues on our SharePoint 2010 portal: my sites, audience, and some navigations were not working...Open up SharePoint Central Admin we first noticed saw an error "User Profile Application's connection is currently not available.." in the user profile service:


Inside profile synchronization service we saw the "An error has occurred while accessing the SQL Server database or the SharePoint Server Search service. If this is the first time you have seen this message, try again later. If this problem persists, contact your administrator.":


It looked like something wrong with the database connection. But there's no recent change on SQL database and service accounts. From the SharePoint log we noticed many unexpected errors from User Profile Web Services:

w3wp.exe (0x0B3C) 0x0268 SharePoint Portal Server User Profiles eh0u Unexpected ProfilePropertyService.GetProfileProperties Exception:
System.MissingMethodException: Method not found: 'Microsoft.SharePoint.Administration.SPIdentifierType Microsoft.SharePoint.Administration.SPAce`1.get_BinaryIdType()'. at
Microsoft.Office.Server.Administration.SPAclFormatter.Serialize[TRights](XmlWriter xmlWriter, SPAcl`1 acl) at
Microsoft.Office.Server.Administration.SPAclFormatter.Serialize[TRights](SPAcl`1 acl) at
Microsoft.Office.Server.Administration.UserProfileApplication.get_SerializedAdministratorAcl() at
Microsoft.Office.Server.Administration.UserProfileApplication.GetProperties() at
Microsoft.Office.Server.UserProfiles.ProfilePropertyService.GetProfileProperties() 4507cc64-e9bd-43d3-9191-5e10b9509083

"Method not found" implies that the service calls and web services were not matching and they had different method signature. What on earth was happening? We recalled that a SharePoint security patch KB2597124 was installed last night (described in Microsoft Security Bulletin). Would it be the culprit? Not likely at the first glance since we a few developers had already installed that patch and didn't find any issue on it.

We traced down the SharePoint update history and found the security patch was installed successfully. The only difference between development and production machines is that production servers didn't have SharePoint Oct. 2011 cumulative updates installed but development machines did:
Production environment: SharePoint2010_SP1(14.0.4763.1000) + KB_2597124_Patch
Dev environment: SharePoint2010_SP1(14.0.4763.1000) + Oct_2011_CU(14.0.6112.5000) + KB_2597124_Patch

Would that difference caused the problem? We read through the patch instruction and it clearly showed it can be applied to SharePoint 2010 or SharePoint 2010 SP1 server without any other prerequisite information.

Anyway we did some tests. We installed KB2597124 Patch in a SharePoint 2010 SP1 test machine (14.0.4763.1000 without any CU installed). Bamm, we then saw all those issues in the test machine!

The conclusion was clear. That the security patch has dependency on previous cumulative updates (Oct. 2011 CU or latest Dec. 2011 CU). But this dependency information is not included in patch’s document, and security patch doesn’t do any prerequisite check.

Those "Method not found" errors now are understandable. Those CU updates modify some user profile web services, and the security patch makes some changes on top of those updated web services. I guess Microsoft found the security vulnerability. They thought it's critical so they teamed up some developers to work on it quickly. What those developers did was grab the latest code including the CU build, fix the issue, test it and make it public. But should Microsoft be a little bit more responsible for that? At least do some testing for different environments before the release right?

The security patch can not be uninstalled. The only option for us was to apply the CU after the security patch which is not the right order. We installed Oct. 2011 CU in that test machine with security patch installed. The CU install was smooth but it failed in SharePoint configuration wizard after machine reboot as prompted:

A few errors can be found in the log file:

03/08/2012 16:08:49 14 ERR The exclusive inplace upgrader timer job failed.
03/08/2012 16:08:49 14 ERR Task upgrade has failed with a PostSetupConfigurationTaskException An exception of type Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException was thrown. Additional exception information: Failed to upgrade SharePoint Products.
03/08/2012 16:08:49 14 ERR An exception of type Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException was thrown. Additional exception information: Failed to upgrade SharePoint Products.
Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException: Exception of type 'Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException' was thrown.
at Microsoft.SharePoint.PostSetupConfiguration.UpgradeTask.Run()
at Microsoft.SharePoint.PostSetupConfiguration.TaskThread.ExecuteTask()
03/08/2012 16:08:49 14 ERR Task upgrade has failed
03/08/2012 16:08:49 1 ERR Task upgrade has stopped and failed. Total failed is now 1
03/08/2012 16:08:49 8 ERR Task upgrade SharePoint Products failed, so stopping execution of the engine
03/08/2012 16:08:49 8 ERR Failed to upgrade SharePoint Products.
An exception of type Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException was thrown. Additional exception information: Failed to upgrade SharePoint Products.
Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException: Exception of type 'Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException' was thrown.
at Microsoft.SharePoint.PostSetupConfiguration.UpgradeTask.Run()
at Microsoft.SharePoint.PostSetupConfiguration.TaskThread.ExecuteTask()
03/08/2012 16:08:49 8 ERR One or more configuration tasks has failed or some tasks were not run
03/08/2012 16:08:49 8 ERR Configuration of SharePoint Products failed. Configuration must be performed in order for this product to operate properly. To diagnose the problem, review the extended error information located at C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\LOGS\PSCDiagnostics_3_8_2012_15_42_40_120_1586599544.log, fix the problem, and run this configuration wizard again.

We could see there were a few configuration tasks errors during the configuration wizard, which may because "Configuration must be performed in order for this product to operate properly" (message from log error). Fortunately, we found the site was back to normal after the CU installation: user profile service was up, mysites and navigation were all working properly. Reapplying the security patch was not implemented and we just didn't have enough time to test all that.

Lesson learned: make sure the test machine has the exact same configuration, fully test before applying any SharePoint patch, and don't take Microsoft for granted.

Monday, February 27, 2012

Working With Windows Phone 7

After Windows Phone 7.1 SDK was installed, a list of Silverlight-based WP project templates will be available in Visual Studio 2010. Then you are ready to create your WP application using Sliverlight(XAML/C#). Yes WP just looks like a special Sliverlight client. You can simply test your WP application simply by the built-in emulator.

I got a Samsung Focus WP handset. I created a simple app and hoped easily to deploy it to the handset device. I thought it's trivial since I found "Windows Phone Device" option right beside the debug button on VS2010 menu. But it's not as easy as I thought.

I connected the handset to the dev machine with a USB cable, then click run with "Windows Phone Device" option. Bingo I got an error telling me that Zune software is not installed. Why deploying a WP app has business with the notorious Zune? Just copying the bad ideal of tethering iPhone on iTune from Apple? Is iZune or iTone a better name for that? No idea what MS is thinking about. Anyway download a 100M Zune package, install it in the dev machine and reboot the machine.

Ready to deploy my own app to the external handset right? The answer is NO! I got another error "Failed to connect to device as it is developer locked". Fantastic the Samsung phone is "locked". Is it locked by MS, Samsung or the carrier? I don't know. But it doesn't look like a carrier lock as iPhone's case.

To unlock a smartphone device, you will have to register a App Hub account, basically a WP/XBOX developer membership costing $99 a year. By paying a hundred bucks, you are eligible to unlock three physical smartphone devices the most. Who figured out the number of 3, instead of 5, 10 or whatever? Guess people from WP team are quite sure that there won't be more than three WP devices around you as a developer. It’s just ridiculous.

So you have a smartphone device, and you want to do some homebrew stuff for yourself and don't want to pay $99/year fee, what should you do? No luck at all! You may end up to an Android device.

WP market share is less than 5 percent, almost ignorable. It's so low that developers are just not willing to work on it. Should MS just make WP development a bit easier in such case? Sigh...

Tuesday, November 29, 2011

SharePoint Server 2010 User Profile

There's no big change between SharePoint Server 2010 and MOSS 2007 in terms of User Profile management. The MOSS 2007 user profile database attached to SSP (Shared Service Provider) can be mounted directly to SharePoint Server 2010 User Profile Service Application. The mount process actually upgrades the MOSS 2007 user profile database. You will notice some new tables and columns are added in the backend database. Following image shows the scheme change made on the UserProfile_Full table in user profile database.

The User Information List is still there in each top site collection where SharePoint foundation manitains the basic user data. A record will be added to the User Information List when a user or a group is first referenced by the SharePoint environment. The initial User Information data, like title, user login, email address, etc., are imported from the authentication provider such as Active Directory. In SharePoint Foundation 2010 the User Information List is updated when you modify user info through "My Settings". All User Information List data are stored in the UserInfo table in content database:

Once the User Profile Service is enabled in SharePoint Server 2010, the User Information List became read-only for end user except the "Mobile Number" property, and user profile database is updated when the user modifying "My Settings", instead of the User Information List (UserInfo table). A timer job is responsible for replicating the user profile data to User Information data for each top site collection, and User Information List data will be overridden unless the corresponding property is not set to "Replicable" in User Profile Service:

Sometime it would cause some confusion when the User Information data are not synced to the User Profile data. Remember regular SharePoint sites always get user info from the User Information List but the User Profile content are the original data source when User Profile Service is enabled.

There's slight difference in SharePoint 2010 when accessing or updating the user profile data comparing with SharePoint 2007. In MOSS 2007, Microsoft.Office.Server.ServiceContext is available and you can create a UserProfileManager object from a ServiceContext. In SharePoint 2010 ServiceContext is replaced by the new Microsoft.SharePoint.SPServiceContext:

void UpdateUserProfiles(string siteUrl)
{
string userName = null;
using (SPSite spSite = new SPSite(siteUrl))
{
//ServiceContext is obsolete in SharePoint 2010
//UserProfileManager userProfileManager = new UserProfileManager(ServerContext.GetContext(spSite));

UserProfileManager userProfileManager = new UserProfileManager(SPServiceContext.GetContext(spSite));

foreach (UserProfile profile in userProfileManager)
{
string account = Convert.ToString(profile[PropertyConstants.AccountName].Value);
if (string.IsNullOrEmpty(account) || account.IndexOf("\\") <= 0)
continue;
userName = account.Substring(account.IndexOf("
\\"));
profile[PropertyConstants.PictureUrl].Value = GetUserPhotoLocation(userName);
profile.Commit();
}
}
}
The method simply goes through each user profile, and updates the user photo by some custom logic (GetUserPhotoLocation method). Notice Microsoft.Office.Server.UserProfiles has become a separate dll in SharePoint 2010, so in order to get above code compiled you need to add Microsoft.Office.Server and Microsoft.Office.Server.UserProfiles to the references.

Friday, May 29, 2009

Microsoft Virtual Earth Tutorial

What is Virtual Earth?

Microsoft Virtual Earth (rebranded as Bing Map in middle of 2009) is a platform to visualize location based data over a simple web connection, and is a powerful service that renders interactive maps directly in web pages. By combining the map images provided by Microsoft’s platform with our custom data, we can create an interactive experience for end users to do the location-related searches.

A Simple Map Page

Virtual Earth is rendered purely by JavaScript in client side browser. The latest version of VE JavaScript library is 6.2. Loading a VE Map is simple: reference the VE JavaScript library, create a VEMap object and call loadMap method to show the map. The source of a simple web page and its UI screen-shoot below demos the simplicity of VE Map usage.
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2"></script>
<script type="text/javascript">
var map = null;
function LoadMap() {
map = new VEMap('myMap');
map.LoadMap();
}
</script>
</head>
<body onload="LoadMap();">
<form id="form1" runat="server">
<div id='myMap' style="position: relative; width: 600px; height: 400px;"></div>
</form>
</body>
</html>
The page looks like:


Map Initial Setting and Show Map Info

VE map initial location and scale can be set in the loading. VELatLong object is passed to LoadMap method to locate the central point of the map, and view level or zoom level can be set from 0 – 19 (default 4 showing the most part United States). To get the map geo info, we use MapView object, and the minimum and maximum latitude/longitude values of the map can be read by map’s corner points. Following page source illustrates how to initialize a map centering at Microsoft with scale of city view, and how to get map information.
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2"></script>
<script type="text/javascript">
var map = null;
function LoadMap() {
map = new VEMap('myMap');
map.LoadMap(new VELatLong(47.65, -122.14), 12);
showMapInfo();
}
function showMapInfo() {
var view = map.GetMapView();
latMin = view.BottomRightLatLong.Latitude;
latMax = view.TopLeftLatLong.Latitude;
lonMin = view.TopLeftLatLong.Longitude;
lonMax = view.BottomRightLatLong.Longitude;
latCenter = map.GetCenter().Latitude;
lonCenter = map.GetCenter().Longitude;
var mapInfo = 'Map Info - Min lat: '+ latMin.toFixed(6);
mapInfo += ' Max lat:' + latMax.toFixed(6);
mapInfo += ' Min lon: ' + lonMin.toFixed(6);
mapInfo += ' Max lon: ' + lonMax.toFixed(6);
mapInfo += '<br> Center Lat: ' + latCenter.toFixed(6);
mapInfo += ' Center lon: ' + lonCenter.toFixed(6);
mapInfo += ' Zoom Level: ' + map.GetZoomLevel();
document.getElementById('divMapInfo').innerHTML = mapInfo;
}
</script>
</head>
<body onload="LoadMap();">
<form id="form1" runat="server">
<div id="divMapInfo" style="height: 50px;"></div>
<div id='myMap' style="position: relative; width: 600px; height: 400px;"></div>
</form>
</body>
</html>
The page is loaded as:


Capture Map Events

All user interactive actions in the map pages are triggered by events and handled by event handlers. There are more than ten events available on VE maps. To handle a map event, you have to attach it explicitly to an event handler (JavaScript function) by calling map.AttachEvent(eventName, eventHandler). The details of VE Map events are listed in http://msdn.microsoft.com/en-us/library/bb429568.aspx, such as onendzoom event occurring when the map zoom ends and onresize event happens in resizing. Besides the events described in the above link, common mouse-based events, like onclick, ondoubleclick and onmouseover events, can also be attached to a map.

The example map page above only shows the map information of the initial state. To see the updated info when there is a change on the map, we can use the onchangeview event:
       function LoadMap() {
map = new VEMap('myMap');
map.LoadMap(new VELatLong(47.65, -122.14), 12);
map.AttachEvent("onchangeview", showMapInfo);
showMapInfo();
}

Pushpins on the Map

Pushpins are visible locaters on the map. Pushpins can be used to show location specific landmarks or custom data. The pushpin is abstracted in a VE Shape object, and the Shape object model allows users to customize the UI shown on the map. With common DHTML techniques, we can substitute images, controls and dynamic layers for the default pushpin control.

Following code shows how to create a pushpin with image and description:
function LoadMap() {
map = new VEMap('myMap');
map.LoadMap(new VELatLong(47.65, -122.14), 12);
var imageURL = 'http://www.microsoft.com/about/images/link_visitMS_new.gif';
addPushpin(47.65, -122.14, 'My pushpin', 'Just a test', imageURL);
showMapInfo();
}
function addPushpin(lat, lon, title, description, icon) {
var point = new VELatLong(lat, lon);
var shape = new VEShape(VEShapeType.Pushpin, point);
shape.SetTitle(title);
shape.SetDescription(description);
if (icon) {
shape.SetCustomIcon(icon);
}
map.AddShape(shape);
}
function showMapInfo() {
//Skip the rest for abbreviation...
Result:


Showing Dynamic Data Using AJAX and JSON Objects

In this example custom pushpins are populated on the map dynamically using AJAX call with JSON data transfer.jQuery is used to facilitate the AJAX invocation:
<!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>Dynamically Loading Virtual Map</title>

<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2"></script>
<script type="text/javascript" src="http://www.json.org/json2.js"></script>
<script src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js" type="text/javascript"></script>

<script type="text/javascript">
var map = null;
function LoadMap() {
map = new VEMap('myMap');
map.LoadMap(new VELatLong(47.64, -122.13), 12);
map.SetScaleBarDistanceUnit(VEDistanceUnit.Kilometers);
map.AttachEvent("onchangeview", showMapInfo);
showMapInfo();
}

function showMapInfo() {
var view = map.GetMapView();
latMin = view.BottomRightLatLong.Latitude;
latMax = view.TopLeftLatLong.Latitude;
lonMin = view.TopLeftLatLong.Longitude;
lonMax = view.BottomRightLatLong.Longitude;
latCenter = map.GetCenter().Latitude;
lonCenter = map.GetCenter().Longitude;

var mapInfo = 'Map Info - ' + ' Min lat: ' + latMin.toFixed(6);
mapInfo += ' Max lat:' + latMax.toFixed(6);
mapInfo += ' Min lon: ' + lonMin.toFixed(6);
mapInfo += ' Max lon: ' + lonMax.toFixed(6);
mapInfo += '<br> Center Lat: ' + latCenter.toFixed(6);
mapInfo += ' Center lon: ' + lonCenter.toFixed(6);
mapInfo += ' Zoom Level: ' + map.GetZoomLevel();

$('#divMapInfo').html(mapInfo);

if (map.GetZoomLevel() > 15) {
getDataByLatLonArea(latMin, latMax, lonMin, lonMax);
}
else {
map.DeleteAllShapes();
}
}

function getDataByLatLonArea(latMin, latMax, lonMin, lonMax) {
var parameters = "{'latMin':" + latMin + ",'latMax':" + latMax;
parameters += ",'lonMin':" + lonMin + ",'lonMax':" + lonMax + "}";
$.ajax({
type: "POST",
url: "MapService.asmx/GetDataByGeoRange",
data: parameters,
contentType: "application/json; charset=utf-8",
dataType: "json",
error: function(xhr, desc, exceptionobj) {
alert(xhr.responseText);
},
success: function(msg) {
if (msg.d != null) {
var jsonObjects = JSON.parse(msg.d);
//var mapInfo = $('#divMapInfo').html();
//mapInfo += " <b>Item found:" + jsonObjects.length; $('#divMapInfo').html(mapInfo);
$.each(jsonObjects, function(i, item) {
var description = populateDescription(item);
addPushpin(item.Latitude, item.Longitude, item.Name, description, null);
});
}
}
});
}

function populateDescription(item) {
var description = "<br><b>Description for " + item.Name + "<br><br>";
return description;
}

function addPushpin(lat, lon, title, description, icon) {
var point = new VELatLong(lat, lon);
var shape = new VEShape(VEShapeType.Pushpin, point);
shape.SetTitle(title);
shape.SetDescription(description);
if (icon) {
shape.SetCustomIcon(icon);
}
map.AddShape(shape);
}
</script>

</head>
<body onload="LoadMap();">
<form id="form1" runat="server">
<div id="divMapInfo" style="height: 50px;">
</div>
<div id='myMap' style="position: relative; width: 600px; height: 400px;">
</div>
</form>
</body>
</html>
Note that we only show the pushin data when the zoom level is greater than 15, and won’t add any pushpins on the map when the scale of the map is too big.

The Web Service returns data in JSON format, which is generated by DataContractJsonSerializer class directly, a new feature in .NET 3.5:
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Services;
using System.Text;
using System.IO;

//From System.Web.Extensions assembly (.NET 3.5 SP1)
using System.Web.Script.Services;
//From System.ServiceModel.Web assembly (.NET 3.5 SP1)
using System.Runtime.Serialization.Json;

namespace Web
{
/// <summary>
/// Summary description for MapService
/// </summary>
[ScriptService]
[WebService(Namespace = "http://tempuri.org/")]
public class MapService : System.Web.Services.WebService
{
[WebMethod]
public string GetDataByGeoRange(double latMin, double latMax, double lonMin, double lonMax)
{
List<MapData> dataList = MapData.GetDataByGeoRange(latMin, latMax, lonMin, lonMax);
DataContractJsonSerializer serializer =
new DataContractJsonSerializer(dataList.GetType());
StringBuilder sb = new StringBuilder();
using (MemoryStream ms = new MemoryStream())
{
serializer.WriteObject(ms, dataList);
sb.Append(Encoding.UTF8.GetString(ms.ToArray()));
}
return sb.ToString();
}
}

public class MapData
{
private struct Point
{
public string Name;
public double Latitude;
public double Longitude;
public Point(string name, double lat, double lon)
{
Name = name;
Latitude = lat;
Longitude = lon;
}
}

public string Name { get; set; }
public string Latitude { get; set; }
public string Longitude { get; set; }

static private List<Point> mockData = GetMockData();
static private List<Point> GetMockData()
{
int pointNumber = 1000;
double latMin = 47.593662, latMax = 47.686192;
double lonMin = -122.232857, lonMax = -122.026863;
List<Point> mockPoints = new List<Point>();
Random rand = new Random();
for (int i = 0; i < pointNumber; i++)
{
double lat = rand.NextDouble() * (latMax - latMin) + latMin;
double lon = rand.NextDouble() * (lonMax - lonMin) + lonMin;
Point point = new Point("Mock " + i.ToString(), lat, lon);
mockPoints.Add(point);
}
return mockPoints;
}
public static List<MapData> GetDataByGeoRange(double latMin, double latMax, double lonMin, double lonMax)
{
List<MapData> dataList = new List<MapData>();
foreach (Point point in mockData)
{
if (point.Latitude > latMin && point.Latitude < latMax &&
point.Longitude > lonMin && point.Longitude < lonMax)
{
MapData mapData = new MapData();
mapData.Latitude = string.Format("{0:0.000000}", point.Latitude);
mapData.Longitude = string.Format("{0:0.000000}", point.Longitude);
mapData.Name = point.Name;
dataList.Add(mapData);
}
}
return dataList;
}
}
}
The screen shot of the map with dynamically loaded data:


Conclusion

In this article we examine a few simple scenarios of using Microsoft Virtual Earth. In reality we can build very powerful location-based web applications using Microsoft Virtual Earth as a platform.

Saturday, January 12, 2008

Configure Log4Net To Log Different Files For Different Projects

Log4Net is a free logging helper running in .NET environment (ported from Log4j). By configuration setting you can log message to files, event log, console window, etc. The common usage is logging to one file, but you can also separate the log files for different projects if you want. Following configuration is an example to separate web UI project logs and backend class library logs:
  <log4net>
<appender name="RollingFileAppenderBackend" type="log4net.Appender.RollingFileAppender">
<file value="C:\inetpub\logs\Backend.log" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="100" />
<maximumFileSize value="1000KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d [%t] %-5p: %m%n" />
</layout>
</appender>
<appender name="RollingFileAppenderWebUI" type="log4net.Appender.RollingFileAppender">
<file value="C:\inetpub\logs\WebUI.log" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="100" />
<maximumFileSize value="1000KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d [%t] %-5p: %m%n" />
</layout>
</appender>
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender" >
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
<layout type="log4net.Layout.PatternLayout">
<param name="Header" value="[Header]\r\n" />
<param name="Footer" value="[Footer]\r\n" />
<param name="ConversionPattern" value="%d [%t] %-5p: %m%n" />
</layout>
</appender>
<logger name="Backendlogger">
<level value="DEBUG" />
<appender-ref ref="RollingFileAppenderBackend" />
<appender-ref ref="EventLogAppender" />
<appender-ref ref="ConsoleAppender" />
</logger>
<logger name="UILogger">
<level value="DEBUG" />
<appender-ref ref="RollingFileAppenderWebUI" />
<appender-ref ref="ConsoleAppender" />
</logger>
</log4net>

Tuesday, November 07, 2006

A Few Releases

After long time of Beta the final release date of Java 6 (1.6) is confirmed to be released next month, which is a big news for Java community. In the Linux world, Fedora Core 6 was released last month, and its previous version Fedora Core 5 was released less than 7-month ago. Fedora looks like trying to catch up the installation/UI improvement brought by Ubuntu, who announced latest 6.10 release two weeks ago.

I used to work with C/Java in Unix/Linux, but most of my work in recent years is with Microsoft solutions, .NET and C# specifically. Now I pay more attention on MS technologies. So what's new in Microsoft world? Well Microsoft has long product lines, and new releases or updates are just too frequent: Team Foundation Server (TFS) 2006, BizTalk 2006, Office 2007, Windows Server 2008, etc...

What else? Microsoft has just released .NET 3.0 and announced the completion of SharePoint 2007 RTM today!

What's new in .NET 3.0? Mainly four components are added and Microsoft named them foundations:
  • Windows Presentation Foundation (WPF): a new user interface subsystem and API based on XML and vector graphics, which uses 3D computer graphics hardware and Direct3D technologies.
  • Windows Communication Foundation (WCF): a service-oriented messaging system which allows programs to interoperate locally or remotely similar to web services.
  • Windows Workflow Foundation (WF): a workflow engine for task automation and integrated transactions.
  • Windows CardSpace: a component securely storing a person's digital identities and provides a unified interface for choosing the identity for a particular transaction, such as logging in to a website.
What's the SharePoint 2007? SharePoint 2007 includes a free version of Windows SharePoint Services (WSS) 3.0, and a not free (actually quite expensive) product called Microsoft Office SharePoint Server (MOSS) 2007. MOSS 2007 is built on top of WSS 3.0 and offers many features that are not included in WSS 3.0.

I happen to have a chance to take some BizTalk 2006/SharePoint 2007 courses during the past 6 months. The course materials were based on the SharePoint 2007 Beta. I am very impressive of how SharePoint technologies can help a business to streamline line their process. Common IT tasks in company, such as creating/editing pages, adding/configuring web parts, configuring people permissions, document management, team collaborations, etc., now can be easily done by business people without IT guys' assistance.

Well you would say, what about developers and IT specialists? In this radically changing world, we need to learn more and more, right? True. New releases and new products indicate changes and new stuff. Change can be scary and you have to face it. But no matter C, Java or C#, Windows or Linux, your existing skills can transition in new technologies in some forms. Those fancy technologies and buzz words can be easily adopted since you have the fundamental of understanding how the computer world works. People living in this world all face too much information, especially in IT world. It would be great if we could filter all information around us efficiently.

Is there a course of "IT 101 - How To Avoid Being Overwhelmed" in school?

Monday, May 29, 2006

Free Tools For Developers

Unlike Scott Hanseleman's long list of useful tools, following are just a few free utilities I use most during my work:

.NET related:
Web related:
File related:

Friday, December 09, 2005

Check Windows Group Users & Clean-up Network Logon

Often used commands inside Windows domain:

Show users in a local group:
>net localgroup administrators

Show users in a domain group:
>net group All_IT_Staff /domain

Delete credential for a network share
>net use \\shareServerName /del

Delete all credentials for all shares:
>net use * /del

Open Credential manager:
>control keymgr.dll
>rundll32.exe keymgr.dll, KRShowKeyMgr

Friday, August 19, 2005

Autonomus System

We are working on a pilot project called BEAT (Best-Effect Autonomous Technology) that will be used in buildings' remote management. The project is quite challenging. We face so many concerns. The complexity of the application would grow significantly if every concern needs to be well addressed. It seems very hard to implement a practical and effective autonomous system in the real world. But hold on a second, is autonomous system well set in every automobile?:-)

Three of us in our team spent almost a whole day on discussing a module of our autonomous system, and the whiteboard pictures of our discussion:

Saturday, July 10, 2004

Gmail is Awesome

Last week I luckily got a gmail invitation and created a new account for myself. I have been played it around since then. It's super clean, fast and I love it!

Hotmail, Yahoo Mail, along with many other free email providers, offer only free 20-50M of mailbox. I know many corporate email systems also have a limit size of 100M for employees. Google sets the bar to 1G and it's free. It definitely is a big hit.

That makes sense. Google has expertise in building huge distributing system with commodity Linux boxes, and they could provide the same capacity with much lower price.

The only thing is the maximum size of attachment is 10M in gmail. How great it's if 20M or even 50M could be supported? I may consider using gmail as my personal online storage not just an email account.