Archive

Archive for September, 2013

Moving IIS sites using AppCmd

Backup Process

%windir%\System32\inetsrv>appcmd list apppool /config /xml >C:\temp\apppools.xml
%windir%\System32\inetsrv>appcmd list sites /config /xml >C:\temp\sites.xml
… And all your website files

Zip up all these files, and move them to the destination server.

Restore Process

… Restore all your website files from the zip file.

Then Edit the apppools.xml file, and comment out any appPools that are already present in the destination server, for example
“DefaultAppPool” etc.

Then … Import App Pools using:

%windir%\system32\inetsrv\appcmd add apppool /in < c:\apppools.xml

Step 2.
Edit the Sites.xml file, and comment out any websites that are already present in the destination server, for example “Default website” etc

Edit the sites.xml file, and change the Site.ID=”<number>” and ID=”<number>” attributes so that they are larger than the largest Site ID in IIS.

Important: If you import a site with the same site ID as an existing site, then the entire server will crash

%windir%\system32\inetsrv\appcmd add site /in < c:\sites.xml

Categories: Uncategorized

no xaml was found at the location ‘/mainpage.xaml’

After upgrading a WP7 app to WP8 (VS 2013 RC), I got this very annoying error when trying to run the app in the emulator. “no xaml was found at the location ‘/mainpage.xaml'”.

I came across a conversation on twitter, regarding this, and saw that someone had the same problem, but said “Found it!!! Your application MUST have Invariant Language ticked as a supported language. Blog post to come :-)”

So, that narrowed my search, and I discovered a one line fix; In the AssemblyInfo.cs file, you have to change the line:

[assembly: NeutralResourcesLanguage(“en”, UltimateResourceFallbackLocation.Satellite)]

To

[assembly: NeutralResourcesLanguage(“en”)]

One line fix!. Pity the error message is not helpful at all.

Categories: Uncategorized

Saving files locally using PhoneGap

One of the quintessential differences between an application and a web page is that applications are trusted to read and write to the hard drive on the machine it is running on. With the exception of limited space given under certain circumstances for Isolated storage (Silverlight), Cookies and Localstorage (5Mb ~ or effectively 2.5 Mb of text), web pages aren’t trusted enough to read and write to your hard drive, and rightly so.

With Apps, there is an elevated level of trust, so you can read and write files within your application “Sandbox”, i.e. space devoted to your app, and no-one else’s.  With smartphones coming now with up to 64 GB of storage, this gives plenty of opportunity to download images, video and content for offline use.

I just learned this morning how to use PhoneGap’s File API, – This example applies specifically to version 2.9.0 on iOS, but it should be equally applicable to other versions, and Android.

First off, you need to get a handle to the local file system, which you can do on the device ready event like so:

var fileSystem = null;

document.addEventListener(“deviceready”, onDeviceReady, false);

function onDeviceReady()
{
console.log(“Device Ready”);
window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, function gotFS(fs)
{
console.log(“Got File System Reference”);
fileSystem = fs;
}, fail);
}

Here the variable fileSystem is declared with global scope, and I have selected Temporary storage. Temporary storage is not designed for “mission critical” or user generated content, just things that can be downloaded again, if need be. Ideal for short-term caching.

Then, I have written a handy function to store this data onto disk:

function createFileWithContent(filename, content)
{
fileSystem.root.getFile(
filename,
{create: true, exclusive: false},
function gotFileEntry(fileEntry) {
console.log(“Got File Entry Reference”);
console.log(fileEntry.toURL());
fileEntry.createWriter(
function gotFileWriter(writer) {
writer.onwriteend = function(evt) {
console.log(writer.fileName);};
writer.write(content);
}, fail);
}, fail);
}

This function writes text content to a file. You don’t worry about the path, since this is dictated by the operating system.

To read this back in, you can use simple ajax, as you would read a local file off disk.

The fail function is omitted here, but it can be a simple console.log, or something more advanced, depending on how you wish the app to respond to errors in the process of saving data.

 

Categories: Uncategorized

The Search API for Shopping has been shut down

As of this morning, Google shut down its Shopping API (As was forewarned). Now, if you try to call it, https://www.googleapis.com/shopping/search/v1/public/products?key=…&country=US&q=pogo&alt=json you get the following Error 412 response:

{
“error”: {
“errors”: [
{
“domain”: “global”,
“reason”: “conditionNotMet”,
“message”: “The Search API for Shopping has been shut down”,
“locationType”: “header”,
“location”: “If-Match”
}
],
“code”: 412,
“message”: “The Search API for Shopping has been shut down”
}
}

 

Adieu, le Shopping API.

Categories: Uncategorized

Console.log – Remote

If you have a PhoneGap/Cordova App, then you surely use Console.log statements to help with the debugging of your app while it is running in a simulator, or USB-attached device.

However, if your device cannot be attached to your development machine, or you cannot debug in the normal way, then this simple script lets you see Console.log output on a web browser.

Firstly, you’ll need access to a windows web-server, and upload this script:

<script language="C#" runat="server">

public static System.Collections.Generic.List<LogItem> logList = new 
System.Collections.Generic.List<LogItem>();

protected void Page_Load(object sender, EventArgs e)
{
string strText = Request.QueryString["text"];
if (strText != null)
{
logList.Add(new LogItem(strText));
return;
}
Response.Write("Log Running...<hr>");
Response.Flush();
DateTime startTime = DateTime.UtcNow;

while(DateTime.UtcNow - startTime < TimeSpan.FromMinutes(1))
{

foreach(LogItem logItem in logList)
{
if (!logItem.isRead)
{
Response.Write(logItem.text + "<br>");
Response.Flush();
logItem.isRead = true;
}
}
System.Threading.Thread.Sleep(100);
}
Response.Redirect(Request.RawUrl);
}

public class LogItem
{
public LogItem(string text)
{
this.text = text;
}

public string text = "";

public bool isRead = false;
}
</script>

Let’s imagine that you put this script at http://www.yourserver.com/log.aspx

Then, you need to override the default action of console.log with this piece of javascript (Which requires JQuery)

console = {};
console.log = function(text)
{
$.get(“http://www.yourserver.com/log.aspx?text=&#8221; + encodeURIComponent(text) + “&nocache=” + Math.random());
}

This, then means that instead of writing to the console output, it makes an AJAX call to the logging script. Visiting the logging script webpage will display the text passed to console.log.

There are some limitations, such that it is only suitable for one-app-one-developer type environments, and you have to remember to remove the override for console.log before submitting the app to Google / Apple / BlackBerry …

Categories: Uncategorized

Exceeding the Maximum size for Google static Maps

The table below shows the maximum allowable values for the size parameter at each scale value.

API scale=1 scale=2 scale=4
Free 640x640 640x640 (returns 1280×1280 pixels) Not available.
Google Maps API for Business 2048x2048 1024x1024 (returns 2048×2048 pixels) 512x512 (returns 2048×2048 pixels)

– As per Google’s documentation, this is the largest size images you can get from the Google Static Maps API

However, there is a work-around that allows for larger images to be returned from the Google static maps API. But it requires quite a bit of work. Basically, you need to find the adjacent tile to the requested tile.

For this, you need to flatten your longitude and latitudes into a flat x / y grid. Once you have X/Y coordinates, then you can use simple maths to pick up the next tile, then with these new x/y positions, you have to re-map this to the spherical projection of the world, to give you back longitude and latitude values.

Flattening and projecting latitude/longitude coordinates to x/y grid coordinates is done using the Mercator projection. Here is a modified version of Mercator.js, that you can include in your project.

var MERCATOR_RANGE = 256;

function bound(value, opt_min, opt_max) {
if (opt_min != null) value = Math.max(value, opt_min);
if (opt_max != null) value = Math.min(value, opt_max);
return value;
}

function degreesToRadians(deg) {
return deg * (Math.PI / 180);
}

function radiansToDegrees(rad) {
return rad / (Math.PI / 180);
}

function MercatorProjection() {
this.pixelOrigin_ = {x: MERCATOR_RANGE / 2, y: MERCATOR_RANGE / 2};
this.pixelsPerLonDegree_ = MERCATOR_RANGE / 360;
this.pixelsPerLonRadian_ = MERCATOR_RANGE / (2 * Math.PI);
};

MercatorProjection.prototype.fromLatLngToPoint = function(latLng) {
var me = this;

var point = {x:0,y:0};

var origin = me.pixelOrigin_;
point.x = origin.x + latLng.lng * me.pixelsPerLonDegree_;
// NOTE(appleton): Truncating to 0.9999 effectively limits latitude to
// 89.189. This is about a third of a tile past the edge of the world tile.
var siny = bound(Math.sin(degreesToRadians(latLng.lat)), -0.9999, 0.9999);
point.y = origin.y + 0.5 * Math.log((1 + siny) / (1 – siny)) * -me.pixelsPerLonRadian_;
return point;
};

MercatorProjection.prototype.fromPointToLatLng = function(point) {
var me = this;
var origin = me.pixelOrigin_;
var lng = (point.x – origin.x) / me.pixelsPerLonDegree_;
var latRadians = (point.y – origin.y) / -me.pixelsPerLonRadian_;
var lat = radiansToDegrees(2 * Math.atan(Math.exp(latRadians)) – Math.PI / 2);
return {lat:lat, lng:lng};
};

Let’s just quickly have a look at how the Google static maps API works.

function renderMap(image, LatLng)
{
image.attr(“src”,”http://maps.googleapis.com/maps/api/staticmap?center=&#8221; + LatLng.lat + “,” + LatLng.lng + “&zoom=10&size=400×400&sensor=false”);
}

This displays a map of a specified latitude and longitude  at zoom level 10, and a 400×400 size image. The image parameter is a jquery collection object referring to a HTML IMG tag.

Now, to display a map at 55,-7 you’d call:

renderMap($(“#img11”),{lat:55,lng:-7});

Now, to apply some magic to this, and display the map tile immediately eastward of this map location, then I use this function:

function GetTileDelta(center,zoom,mapWidth,mapHeight,delta){
var proj = new MercatorProjection();
var scale = Math.pow(2,zoom);
var centerPx = proj.fromLatLngToPoint(center);
var DeltaPx = {
x: (centerPx.x + ((mapWidth / scale) * delta.x)) ,
y: (centerPx.y + ((mapHeight/ scale) * delta.y))
};
var DeltaLatLon = proj.fromPointToLatLng(DeltaPx);
return DeltaLatLon;
}

Which is called as follows:

var RightLatLng = GetTileDelta({lat:55,lng:-7},10,400,400,{x:+1,y:0});
renderMap($(“#img12”),RightLatLng);

How this works, is by “flattening” the globe using the mercator projection, using simple maths to shift the x position the width of the map over to the right (eastward), then folding the x/y coordinates over the globe using the mercator projecion again, to provide the lat/lon coordinates.

By extension, you can then use this to obtain any size map required.

Categories: Uncategorized