Tag Archives: .NET

Using the Bing Maps REST Services To Obtain the Route in the .NET Application

The Bing Maps platform provides multiple API options for your application including an AJAX control, a Windows Store apps control, a WPF control, REST Services, and Spatial Data Services. See more information: http://www.microsoft.com/maps/choose-your-bing-maps-API.aspx

To obtain the route data, Bing Maps REST Services is our choice: http://msdn.microsoft.com/en-us/library/ff701713.aspx

The Bing™ Maps REST Services Application Programming Interface (API) provides a Representational State Transfer (REST) interface to perform tasks such as creating a static map with pushpins, geocoding an address, retrieving imagery metadata, or creating a route.

About using the REST Services with .NET, this article is helpful: http://msdn.microsoft.com/en-us/library/jj819168.aspx

Here is my WPF sample:

XAML:

<Grid>
        <m:Map Name="myMap" 
               Center="-1.968404, 30.036240" 
               ZoomLevel="10"
               CredentialsProvider="Fill Your Key"
               Mode="AerialWithLabels" ></m:Map>

        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Bottom">
            <Label Content="From: " FontWeight="Bold" />
            <TextBox Width="80" Height="20" Name="fromTxb" Text="New York" />
            <Label Content="To: " FontWeight="Bold" />
            <TextBox Width="80" Height="20" Name="toTxb" Text="Seattle" />
            <Button Content="Route" Width="80" Click="RouteButton_Click" />
        </StackPanel>
    </Grid>

Using the following method to request route data from REST Services:

private void Route(string start, string end, string key, Action<Response> callback)
{
            //Culture c = CultureDD.SelectedItem as Culture;
            Uri requestURI = new Uri(string.Format("http://dev.virtualearth.net/REST/V1/Routes/Driving?wp.0={0}&wp.1={1}&rpo=Points&key={2}", Uri.EscapeDataString(start), Uri.EscapeDataString(end), key));
            //QueryURLTbx.Text = requestURI.AbsoluteUri;
            GetResponse(requestURI, callback);
}

private void GetResponse(Uri uri, Action<Response> callback)
{
            try
            {
                HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
                using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                {
                    using (Stream stream = response.GetResponseStream())
                    {
                        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Response));

                        if (callback != null)
                        {
                            callback(ser.ReadObject(stream) as Response);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
}

Getting the credential:

private void GetRoute(string fromloc, string toloc)
{
            string to = toloc;//"Seattle";
            string from = fromloc;//"New York";

            if (!string.IsNullOrWhiteSpace(from))
            {
                if (!string.IsNullOrWhiteSpace(to))
                {
                    GetKey((c) =>
                    {
                        Route(from, to, c, (r) =>
                        {
                            if (r != null &&
                                r.ResourceSets != null &&
                                r.ResourceSets.Length > 0 &&
                                r.ResourceSets[0].Resources != null &&
                                r.ResourceSets[0].Resources.Length > 0)
                            {
                                Route route = r.ResourceSets[0].Resources[0] as Route;

                                double[][] routePath = route.RoutePath.Line.Coordinates;
                                LocationCollection locs = new LocationCollection();

                                for (int i = 0; i < routePath.Length; i++)
                                {
                                    if (routePath[i].Length >= 2)
                                    {
                                        locs.Add(new Microsoft.Maps.MapControl.WPF.Location(routePath[i][0], routePath[i][1]));
                                    }
                                }

                                MapPolyline routeLine = new MapPolyline()
                                {
                                    Locations = locs,
                                    Stroke = new SolidColorBrush(Colors.Red),
                                    StrokeThickness = 5
                                };

                                myMap.Children.Add(routeLine);

                                myMap.SetView(locs, new Thickness(30), 0);
                            }
                            else
                            {
                                MessageBox.Show("No Results found.");
                            }
                        });
                    });
                }
                else
                {
                    MessageBox.Show("Invalid End location.");
                }
            }
            else
            {
                MessageBox.Show("Invalid Start location.");
            }
}

Screenshot(gif):
WpfBingMapsRoute

Download Sample: WpfBingMapsRoute

To get the Bing Maps Trial Key, please go to here: http://www.microsoft.com/maps/

Here are some Bing Maps resources, please refer to: Bing Maps Resources

Always Use Plain Type(e.g. char*) As Parameter For P/Invoke

Background:

Recently, a customer encountered a strange issue. He created a C++ class library with I/O operation:

Source File:

#include "stdafx.h"
#include
#include

#include "DynamicDLLToCall.h"
using namespace std;

void zlog(string fstr)
{
	FILE * debug;
	debug = fopen("zlog.txt", "a");
	ifstream iFile(fstr);
	fprintf(debug, "fsadfsdfsdfsdfdsfsdf");
	fclose(debug);
}

Header File:

using namespace System;
using namespace std;

extern "C" __declspec(dllexport) void zlog(string fstr);

Now, he want to call zlog() method in a .NET project:

[DllImport("D:/ClassLibrary1.dll")]
public static extern void zlog(string fstr);//imported func

private void Button_Click(object sender, RoutedEventArgs e)
{
            zlog("asdas");
}

Issue:
This app crashed when the zlog() function is called and the zlog.txt file was successfully created.

Troubleshoot:

At first, I tried to comment some code snippets in the zlog(string fstr) function, but this issue still existed, so I think it should be more related to the declaration of this function.

With the help from C++ expert, it may be caused by this reason: C++ doesn’t support(or fully support) ABI(Application Binary Interface) which is required to help clean the stack of the object.

What is ABI? Please refer to these references:

ABIs cover details such as:

–the sizes, layout, and alignment of data types

–the calling convention, which controls how functions’ arguments are passed and return values retrieved; for example, whether all parameters are passed on the stack or some are passed in registers, which registers are used for which function parameters, and whether the first function parameter passed on the stack is pushed first or last onto the stack

–how an application should make system calls to the operating system and, if the ABI specifies direct system calls rather than procedure calls to system call stubs, the system call numbers

–and in the case of a complete operating system ABI, the binary format of object files, program libraries and so on.

A complete ABI, such as the Intel Binary Compatibility Standard (iBCS),[1] allows a program from one operating system supporting that ABI to run without modifications on any other such system, provided that necessary shared libraries are present, and similar prerequisites are fulfilled.

——–

So always use plain type(e.g. char*) as parameter for P/invoke instead of using type within the std namespace as parameter.

The following code worked well now:

C++ declaration:

extern "C" __declspec(dllexport) void zlog(char* fstr);
1

C++ function:
1
void zlog(char* fstr)
{
 //...your code
}

In .NET application code behind:

[DllImport("DynamicDLLToCall", CallingConvention = CallingConvention.Cdecl)]
public static extern void zlog(string fstr);

Desktop Application: Stack Exchange API – OAuth 2.0

Recently, we need to integrate Stack Exchange authentication to our Desktop Application. To obtain Access Token, someone tried to send web request to the specified url with parameters, but this didn’t work.

Ref to Stack Exchange API Authentication Document:

Desktop Applications

Desktop applications cannot participate directly in OAuth 2.0 flows, however the embeddable browser controls available in most frameworks make it possible to work around this limitation.

Desktop applications should use the implicit client-side flow, hosting the process within a browser control. For redirect_uri, a value of https://stackexchange.com/oauth/login_success should be used. Upon a successful authentication, access_token will be placed in the url hash as with a standard implicit authentication.

What’s the implicit client-side flow:

1. Open a new window at https://stackexchange.com/oauth/dialog, with these query string parameters

  • client_id
  • scope (details)
  • redirect_uri – must be under an apps registered domain
  • state – optional

2. The user approves your app
3. The user is redirected to redirect_uri, with these parameters in the hash

  • access_token
  • expires – optional, only if scope doesn’t contain no_expiry

After understanding the above flow, we’ll step through the flow with examples.

Firstly, we need to register for an app key: http://stackapps.com/apps/oauth/register

Secondly, by using the Client Id generated in the above step, the url with parameters will be like this:

https://stackexchange.com/oauth/dialog?client_id=<Your ClientID>&scope=no_expiry&redirect_uri=https://stackexchange.com/oauth/login_success

In this step, we could create a new window with WebBrowser control and navigate to the above url, but the default IE version was not the same as my OS(Win8.1 IE11), so I created a method to Fix this issue, used the FEATURE_BROWSER_EMULATION feature: http://msdn.microsoft.com/en-us/library/ie/ee330730(v=vs.85).aspx

private void IEbrowserFix()
{
            try
            {
                Microsoft.Win32.RegistryKey regDM = Registry.CurrentUser;
                string KeyPath = "SOFTWARE\\Microsoft\\Internet Explorer\\MAIN\\FeatureControl\\FEATURE_BROWSER_EMULATION";

                regDM = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(KeyPath, false);
                if (regDM == null)
                {
                    regDM = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(KeyPath);
                }

                object Sleutel = null;
                if ((regDM != null))
                {
                    string location = System.Environment.GetCommandLineArgs()[0];
                    string appName = System.IO.Path.GetFileName(location);

                    Sleutel = regDM.GetValue(appName);
                    if (Sleutel == null)
                    {
                        //Sleutel onbekend
                        regDM = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(KeyPath, true);
                        Sleutel = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(KeyPath, Microsoft.Win32.RegistryKeyPermissionCheck.ReadWriteSubTree);

                        //What OS are we using
                        Version OsVersion = System.Environment.OSVersion.Version;

                        if (OsVersion.Major == 6 & OsVersion.Minor == 1)
                        {
                            //WIN 7
                            ((RegistryKey)Sleutel).SetValue(appName, 9000, Microsoft.Win32.RegistryValueKind.DWord);
                        }
                        else if (OsVersion.Major == 6 & OsVersion.Minor == 2)
                        {
                            //WIN 8
                            ((RegistryKey)Sleutel).SetValue(appName, 10000, Microsoft.Win32.RegistryValueKind.DWord);
                        }
                        else if (OsVersion.Major == 6 & OsVersion.Minor == 3)
                        {
                            <strong>//WIN 8.1</strong>
<strong>                            ((RegistryKey)Sleutel).SetValue(appName, 11001, Microsoft.Win32.RegistryValueKind.DWord);</strong>
                        }
                        else if (OsVersion.Major == 5 & OsVersion.Minor == 1)
                        {
                            //WIN xp
                            ((RegistryKey)Sleutel).SetValue(appName, 8000, Microsoft.Win32.RegistryValueKind.DWord);
                        }

                        ((RegistryKey)Sleutel).Close();
                    }
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
}

RedirectForm.cs:

public partial class RedirectForm : Form
{
        public RedirectForm()
        {
            InitializeComponent();
        }
        public string Token
        {
            get;
            set;
        }

        public RedirectForm(string url)
        {
            InitializeComponent();

            webBrowser1.Navigate(url);
        }

        private void RedirectForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            NameValueCollection urlParameters = HttpUtility.ParseQueryString(webBrowser1.Url.ToString());

            // extract the access token from the url.
            string accessToken = urlParameters["https://stackexchange.com/oauth/login_success#access_token"];
            if(accessToken!=null)
            {
                //MessageBox.Show(accessToken);
                this.Token = accessToken;
            }
        }

        private void IEbrowserFix()
        {
            //...Omitted...
        }

        private void RedirectForm_Load(object sender, EventArgs e)
        {
            IEbrowserFix();
        }
}

MainFrom.cs:

private void button1_Click(object sender, EventArgs e)
{
            string url2 = "https://stackexchange.com/oauth/dialog?client_id="+txtClientID.Text+"&scope=no_expiry&redirect_uri=https://stackexchange.com/oauth/login_success";

            using( RedirectForm rf =new RedirectForm(url2))
            {
                DialogResult result=rf.ShowDialog();
                if(result == DialogResult.Cancel)
                {
                    txtToken.Text = rf.Token;
                }
            }
}

Screenshot:

Auth1

Obtained Access Token:

Auth2