metadevblog

Windows Phone 7 App Development

Master Key published!

leave a comment »

While I’ve not blogged the event in a timely manner my app Master Key was published on 10th May a couple of days after I submitted it.  I’m pretty pleased with this!

I’ve used the app since it was in early development and am now working on V2.0 based on my own user feedback which I hope to upload over the next week or so.  I’ve extended the functionality now beyond simply having the password associated with a caption to include an identity and some additional notes.

I’m up to 20 different entries now, it’s really come as quite a surprise as to how many different identities I have and it’s really great having all the info in one secure place.

As I have blogged previously the phone can easily connect to a web service.  I’ve used this approach to provide a backup and restore facility for the Master Key vault.  As the service is provided as an HTTP endpoint it can run anywhere the phone can access.

When the phone is attached by it’s cable to a PC it has access to the Ethernet the PC is connected to as as the HTTP endpoint can be easily exposed on the network it becomes quite simple to make a connection without having to have any complex security or exposure to the wider internet.

Advertisements

Written by metadevblog

June 5, 2011 at 1:11 pm

Posted in Master Key, WCF

Master Key sent for approval

leave a comment »

I’ve finally sent Master Key off to the App Hub for approval so I now have to wait and see if it passes and gets published.

Writing my first Windows Phone app has been an interesting process.  Like anything new it’s taken quite a long time to go from a blank sheet of paper through to the final solution and now that I’ve done it once I’m pretty confident that next time it will be much quicker.

Writing for the WP7 platform is great, especially as I’m very experienced with Visual Studio, c# and to a lesser extent Silverlight.  Microsoft have excelled themselves in producing such a great development environment.

I’ve now completed version 1.0 of the application and am already thinking of version 2.0; I would have continued to add features but really wanted to complete the first deployment and get onto the Marketplace.  As I follow a RAD process it can be quite hard to be disciplined and stop development as feedback testing suggests new features and better approaches to solving a problem.

Setting up my account on App Hub has been very time consuming.  As a UK based developer I have to jump through a bunch of US IRS hoops in order to get paid the full royalty amount without losing 30% in withholding taxes.  While this is not much of an issue currently as I’m not expecting any significant royalties it will hopefully be worthwhile in the future.

Along with putting the app up for approval I’ve finally deployed the MDL website.  It does not have a great deal of content currently but I have published the help for Master Key.  The web site is at:

http://www.metadev.co.uk

I used the new WebMatrix tool to create the site and am reasonably happy with the outcome.  I use Discount.ASP as my hosting service; I’ve used them for a few years now and am pretty pleased with their level of support and the functionality.

It took me a few goes to get the deployment to work properly but this was partly down to me using .NET4.0, having to configure IIS7 and modify one of the CSHTML pages so that it wasn’t attempting to connect to a database.

I tried to use FTP but it didn’t work very well and read the recommended method was to use Web Deploy. I used the ‘Import publish settings’ to get the correct info from Discount.ASP and all I had to do was enter my password.  You need to use ‘Validate Connection’ and ensure it passes before deploying.

Take a look at this support article on Discount.ASP site:

http://support.discountasp.net/KB/a891/how-to-deploy-an-application-using-web-deploy-feature.aspx

Configure IIS7 by checking the box to give your Discount.ASP login account access.

image

I added the following to the web.config – I am not convinced that this is necessary as I do not have a database.

    <connectionStrings>
        <add name="LocalSqlServer" connectionString="x" providerName="System.Data.SqlClient" />
    </connectionStrings>
I still had errors but this time they were more explicit and commenting out this line: 
 

//WebSecurity.InitializeDatabaseConnection("StarterSite", "UserProfile", "UserId", "Email", true);

in _AppStart.cshtml fixed it and my web site was deployed.

Written by metadevblog

May 9, 2011 at 5:49 pm

Starting an WP7 app with alternate start page

with one comment

I have had to change the method for starting Master Key in order to fit in with the way that the WP7 page navigation works.  On the face of it the issue is pretty trivial and one that users would typically only hit once or twice during their use of the App.

WP7 uses a browser based metaphor for moving between pages in an application.  So you can move from page to page and the history is retained on a stack, pressing the back button returns to the previous page.  This can seem confusing, Page1 can invoke Page2 and this can in turn invoke Page1.  However it will NOT be the original Page1 but a new instance of it.  Pressing back on this last page will will return to Page2 and pressing back again will go to the first instance of Page1 (pressing back one more time will close the App).

Master Key requires the user to enter the master key password in order to access the secured information.  However when the user first starts Master Key the user has to enter the password that will be used on subsequent visits and I have a different UI for this.

I originally wrote the code so that the MainPage.xaml checked to see if the users vault (the list of passwords) already exists and if it does not then the page re-directs in the OnNavigatedTo event in MainPage.xaml to a password entry page called EnterPassword.xaml where the user enters the master key.

If the user enters a valid master key and presses ‘ok’ then the vault is set up and the app is ready to use.

However if the user hits the ‘back’ button before entering a valid password then the App is left in a state of limbo and will hit the same OnNavigatedTo event in the MainPage.xaml which will re-invoke the EnterPassword.xaml page again.

I could write code to trap this cycle but wanted to look at the alternatives; one of which is to have different start pages.  I.e. when the vault exists then the MainPage.xaml will be the start page, and if the vault does not exist then EnterPassword.xaml should be the start page.

This is best achieved using Uri remapping by adding the code to the App.xaml.cs Application_Launching event:

private void Application_Launching(object sender, LaunchingEventArgs e)
{
    DAL.LoadVault();

    UriMapper mapper = Resources["uriMapper"] as UriMapper;
    RootFrame.UriMapper = mapper;

    // Update the mapper as appropriate
    if (DAL.VaultExists)
        mapper.UriMappings[0].MappedUri =                   
          new Uri("/MainPage.xaml", UriKind.Relative);
    else
        mapper.UriMappings[0].MappedUri =                   
          new Uri("/EnterPassword.xaml?type=newvault", UriKind.Relative);
}

The App.xaml has to be modified to have a default UriMapper added to it (note the addition of the xmlns:navigation namespace).

<Application
    x:Class="WPVault.App"
    xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"      
    xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:navigation="clr-namespace:System.Windows.Navigation;assembly=Microsoft.Phone"
    >

    <!–Application Resources–>
    <Application.Resources>
        <navigation:UriMapper x:Name="uriMapper">
            <navigation:UriMapping Uri="/MainPage.xaml" />
        </navigation:UriMapper>
    </Application.Resources>

It works and I can see uses for it in other Apps; however it comes at a cost that ruled it out for me as the back button behaviour is to return to the page that was navigated from.  This means that once the user has entered the master key password and started to make entries then hitting the back button will return to the EnterPassword.xaml page again which is not a great UX.

I ended up combining the Open and New Vault pages into MainPage.xaml as there is a lot of overlap in their functionality – I then simply drive changes into the UI in the OnNavigatedTo event as appropriate to what the user is doing.  Thus the ‘new vault’ info is shown when the vault does not exist and then when the user returns back to this page again and the vault does exist the ‘open vault’ page is shown.

image

 

Written by metadevblog

May 1, 2011 at 2:59 pm

Posted in Master Key, Silverlight, WP7

Build Version numbers

leave a comment »

A quick note on Visual Studio Build Version numbers as there is some quite confusing notes around and it’s taken me a few hours to get this process working end to end.

Version numbers are vital when building software that is to be released to the outside world and automating at least part of the process ensures that you can pretty much keep track of what is out there.

The default process provides a build number like this: 1.3.4138.18913.

This number represents the following information: Major.Minor.Build.Revision

So the build is version 1.3 and the build number is 4138 and the revision number is 18913.

The build information is maintained in AssemblyInfo.cs

// 1.0 – Password Vault
// 1.1 – first version released to MSFT
// 1.2 – renamed to Master Key
// 1.3 – added remote save/load and refactor UX
[assembly: AssemblyVersion("1.3.*")]

The auto generation of the build/revision only occurs when you remove either AssemblyVersion or AssemblyFileVersion; I have only worked with the former.

I have to set the major/minor build numbers and I include a comment to track the changes.  I only change these when there is a big change to the app and will also set a minor version prior to each release.

I use VS TS Source Control and as part of the development process I label the each change to the Minor build when I have checked the updates in.  This allows me to quickly pull a version from source control when I have an issue reported to me.

Each time I build the solution the Build and Revision numbers will change. The Build is actually the number of days since 31/12/1999 and so only changes when the date changes.  The Revision is the number of seconds since midnight/2.

Getting this info into an About Box where it’s visible to the user is the next task.  There are a bunch of ways to do this but the simplest is the following:

System.Reflection.Assembly execAssembly = System.Reflection.Assembly.GetExecutingAssembly();

string[] version = execAssembly.FullName.Split(',');
textBlockVersion.Text = version[1];


The output looks like this:

image

 

Written by metadevblog

May 1, 2011 at 11:06 am

Posted in c#, Silverlight, WP7

Tagged with , ,

WP7 accessing a Windows Service DataService

leave a comment »

This application took 2 minutes to write…

Now that I have demonstrated how Silverlight can access a DataService that is hosted by a WindowsService the final example is to show that it will work on a WP7.

I created a new Windows Phone application and added a Button and Textbox.

I added a Service Reference to the DataService to the Solution.

Finally I pretty much copied the code from the Silverlight application in the previous post.

using WPService.DataService;
using System.Xml.Linq;

namespace WPService
{
    public partial class MainPage : PhoneApplicationPage
    {
        DataServiceClient dataService = null;

        // Constructor
        public MainPage()
        {
            InitializeComponent();

            dataService = new DataServiceClient();
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                dataService.GetDateTimeCompleted += new EventHandler<GetDateTimeCompletedEventArgs>(dataService_GetDateTimeCompleted);
                dataService.GetDateTimeAsync();
            }
            catch (Exception ex)
            {
                textBlock1.Text = string.Format("Error occurred: {0}", ex.Message);
            }
        }

        void dataService_GetDateTimeCompleted(object sender, DataService.GetDateTimeCompletedEventArgs e)
        {
            try
            {
                XElement xResult = (XElement)e.Result;

                string date = xResult.Element("Date").Value;
                string time = xResult.Element("Time").Value;

                textBlock1.Text = string.Format("The date is: {0}\nThe time is: {1}", date, time);

            }
            catch (Exception ex)
            {
                textBlock1.Text = string.Format("Error occurred: {0}", ex.Message);
            }
        }
    }
}

 

I clicked the Button!

image

Says it all!

Written by metadevblog

March 29, 2011 at 10:00 pm

Posted in WCF, WP7

Tagged with , ,

Using Silverlight with a Windows Service – Part 2

with one comment

In order to get the Silverlight version of the application to work the Windows Service has to be modified so that it can provide the necessary Silverlight clientaccesspolicy.xml file or Flash policy file crossdomain.xml from root domain of the service.

This is accomplished by adding a WebService to the WindowService running on the same port as the existing Data Service and using a URL rewriter to provide the correct xml file to the Silverlight application.

First add empty IWebService.cs and WebService.cs classes.

The IWebService.cs should be replaced with this code:

using System.ServiceModel;
using System.IO;
using System.ServiceModel.Web;

namespace ConsoleApplicationWCF
{
    [ServiceContract]
    public interface IWebServer
    {
        [OperationContract, WebGet(UriTemplate = "ClientAccessPolicy.xml")]
        Stream GetClientAccessPolicy();
    }
}

 

Note: You will need to add a reference to System.ServiceModel.Web which can only be added when the dialog is filtered by .NET 4.0 Framework (and not the Client framework).

The key difference between this interface and the one use for the DataService is the WebGet() that has been added to the Operation Contract and it will invoke the GetClientAccessPolicy() method when a GET request matches the template.  The more typical use of this pattern is to respond to more generic request pattern, however it is ideal for handling the Silverlight request.

http://localhost:1234/clientaccesspolicy.xml

The code to handle the request is also very simple:

using System.IO;
using System.ServiceModel.Web;
using System.Reflection;

namespace ConsoleApplicationWCF
{
    public class WebServer : IWebServer
    {
        public const string AssemblyRootPath = "ConsoleApplicationWCF.";

        public Stream GetClientAccessPolicy()
        {
            WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
            return Assembly.GetExecutingAssembly().
               GetManifestResourceStream(AssemblyRootPath + "ClientAccessPolicy.xml");
        }
    }
}

 

The AssemblyRootPath is the namespace for the application.  This should be ConsoleApplicationWCF but can be confirmed by looking at the Default Namespace in the Projects Properties.

Add the following XML as a ClientAccessPolicy.xml file to the project and make sure that the Build Action for the file is set to ‘Embedded Resource’.  When the project is built the xml file will be built into the binary file.

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="*">
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

 

When the method is invoked the file data is returned to the caller.

The final part of the process is to create a web server endpoint to handle this contracted request.

   <behaviors>
    <endpointBehaviors>
      <behavior name="WebServerEndpointBehavior">
        <webHttp />
      </behavior>
    </endpointBehaviors>
    <serviceBehaviors>
      <behavior name="WebServerBehavior">
        <serviceMetadata httpGetEnabled="false" />
        <serviceDebug httpHelpPageEnabled="false" includeExceptionDetailInFaults="true" />
      </behavior>
        ...
    </serviceBehaviors>
   </behaviors>

 

Notice that there is an endpointBehaviour and a serviceBehaviour. 

These two behaviours are used in the definition of the WebServer service:

    <service behaviorConfiguration="WebServerBehavior" name="WebServer">
      <endpoint address="" behaviorConfiguration="WebServerEndpointBehavior"
        binding="webHttpBinding" contract="IWebServer">
        <identity>
          <dns value="localhost" />
        </identity>
      </endpoint>
      <host>
        <baseAddresses>
          <add baseAddress="http://localhost:1234/" />
        </baseAddresses>
      </host>
    </service>

 

Notice that the <service> behaviourConfiguration uses the WebServerBehaviour and the <endpoint> behaviourConfiguration uses the WebServerEndpointBehaviour.  I know that this looks simple but it’s driven me mad while configuring WCF previously – the trick I think is to make sure the names are really reflecting the configuration!

The binding for the WebServer is ‘webHttpBinding’ which will respond to the HTTP GET method that Silverlight makes (and notice that the GetClientAccessPolicy() outgoing content type is ‘text/html’

Here is the full service configuration for both the WebService and the DataService:

<?xml version="1.0"?>
<configuration>
  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="WebServerEndpointBehavior">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="WebServerBehavior">
          <serviceMetadata httpGetEnabled="false"/>
          <serviceDebug httpHelpPageEnabled="false" includeExceptionDetailInFaults="true"/>
        </behavior>
        <behavior name="DataServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="WebServerBehavior" name="ConsoleApplicationWCF.WebServer">
        <endpoint address="" behaviorConfiguration="WebServerEndpointBehavior" 
             binding="webHttpBinding" contract="ConsoleApplicationWCF.IWebServer">
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:1234/"/>
          </baseAddresses>
        </host>
      </service>
      <service behaviorConfiguration="DataServiceBehavior" name="ConsoleApplicationWCF.DataService">
        <endpoint address="" binding="basicHttpBinding" contract="ConsoleApplicationWCF.IDataService">
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:1234/DataService"/>
          </baseAddresses>
        </host>
      </service>
    </services>
  </system.serviceModel>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
</configuration>

And now when the Silverlight application runs and the button is pressed it will request the client access policy file, validate it and then assuming its all OK will fetch the date and time. Awesome!

image

Written by metadevblog

March 28, 2011 at 10:58 pm

Posted in Silverlight, WCF

Tagged with ,

WCF–Testing the DataService

leave a comment »

The quickest way to test that the Data Service is working is to create a simple Windows Forms based application as this will be able to connect without encountering any of the cross domain issues that a Silverlight application will hit.

Once this test has completed then the WCF service will be changed so that a Silverlight application can be created.

Create a new Windows Forms based application in VS2010.  Its best to develop the application in a separate instance of VS2010 rather than adding new project to the solution because then the DataService can be left running while the client is being developed.

Ensure that the ConsoleApplicationWCF is running and the DataService console window is displayed.

Add a button and a label to the Form1 that will have been created automatically by VS.

In the Project Solution right click on References and select Add Service Reference.  Enter the address of the DataService (e.g. http://localhost:1234/DataService).  Click the Advanced button and tick the ‘Generate asynchronous operations’ checkbox.  Asynchronous operations are slightly more tricky to use but is the only option when using Silverlight so it may as well be implemented now.

Once the service reference has been created (and you can see that the process creates quite a bit of code and support files if you ‘show all files’ in the project Solution explorer) it can be used with relative ease.

One of the really great things about WCF is how much work the Microsoft developers have put into hiding the complexity of what is a very complex process.

The code pretty much writes itself, you only have to remember a couple of names in order to get it working.

The starting point when using the service reference is to create a reference to the service code that has been used, the will be called DataServiceClient.

DataServiceClient dataService = null;

 

Adding this will report an error.  Right clicking on DataServiceClient and selecting Resolve will add the correct using statement to the class (it should be  “using WindowsFormsWCF.DataService”).

Using the event driven asynchronous access pattern that is exposed via the code that has been generated during the creation of the service reference exposes the functionality of WCF.  VS2010 IntelliSense will virtually fill out the code to access the service.  So the button click code should look like this:

        private void button1_Click(object sender, EventArgs e)
        {
            dataService.GetDateTimeCompleted += new EventHandler
                    <GetDateTimeCompletedEventArgs>(dataService_GetDateTimeCompleted);
            dataService.GetDateTimeAsync();
        }


The GetDateTimeCompleted delegate simply needs an appropriate event handler to be added and IntelliSense will event generate the name of the handler “dataService_GetDateTimeCompleted” all that needs to be done is add it to the code.

        void dataService_GetDateTimeCompleted(object sender, DataService.GetDateTimeCompletedEventArgs e)
        {
            try
            {
                XElement xResult = (XElement)e.Result;

                string date = xResult.Element("Date").Value;
                string time = xResult.Element("Time").Value;

                label1.Text = string.Format("The date is: {0}\nThe time is: {1}", date, time);

            }
            catch (Exception ex)
            {
                label1.Text = string.Format("Error occurred: {0}", ex.Message);
            }
        }


The only bit of work that has be hand cranked is to remember that the event handler will have the following parameters:

(object sender, DataService.GetDateTimeCompletedEventArgs e)

The e.Result will be returning an XElement, as this was defined in the original service.  I’m simply grabbing the Date and Time elements from the XML, formatting them and showing the result in the label.

image

The code for the application is:

using System;
using System.Windows.Forms;
using WindowsFormsWCF.DataService;
using System.Xml.Linq;

namespace WindowsFormsWCF
{
    public partial class Form1 : Form
    {
        DataServiceClient dataService = null;

        public Form1()
        {
            InitializeComponent();

            dataService = new DataServiceClient();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            dataService.GetDateTimeCompleted += new EventHandler<GetDateTimeCompletedEventArgs>(dataService_GetDateTimeCompleted);
            dataService.GetDateTimeAsync();
        }

        void dataService_GetDateTimeCompleted(object sender, DataService.GetDateTimeCompletedEventArgs e)
        {
            try
            {
                XElement xResult = (XElement)e.Result;

                string date = xResult.Element("Date").Value;
                string time = xResult.Element("Time").Value;

                label1.Text = string.Format("The date is: {0}\nThe time is: {1}", date, time);

            }
            catch (Exception ex)
            {
                label1.Text = string.Format("Error occurred: {0}", ex.Message);
            }
        }
    }
}

 

Transforming this code to Silverlight is pretty simple.  Create a new Silverlight Application project in VS2010 (remove the checkmark for hosting in a new web site).

In the MainPage.xaml add a Button and a TextBox.  Create the Service Reference and then paste in the following code:

using System;
using System.Windows;
using System.Windows.Controls;
using SilverlightApplicationWCF.DataService;
using System.Xml.Linq;

namespace SilverlightApplicationWCF
{
    public partial class MainPage : UserControl
    {
        DataServiceClient dataService = null;

        public MainPage()
        {
            InitializeComponent();

            dataService = new DataServiceClient();
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                dataService.GetDateTimeCompleted += new EventHandler<GetDateTimeCompletedEventArgs>(dataService_GetDateTimeCompleted);
                dataService.GetDateTimeAsync();
            }
            catch (Exception ex)
            {
                textBlock1.Text = string.Format("Error occurred: {0}", ex.Message);
            }
        }

        void dataService_GetDateTimeCompleted(object sender, DataService.GetDateTimeCompletedEventArgs e)
        {
            try
            {
                XElement xResult = (XElement)e.Result;

                string date = xResult.Element("Date").Value;
                string time = xResult.Element("Time").Value;

                textBlock1.Text = string.Format("The date is: {0}\nThe time is: {1}", date, time);

            }
            catch (Exception ex)
            {
                textBlock1.Text = string.Format("Error occurred: {0}", ex.Message);
            }
        }
    }
}


Apart from a few name differences its the same code!

Run the application and you will get a warning about debugging issues when using web services (you can see what’s coming soon…).  Ignore the warning and continue to run the application and while the Silverlight form will display, as soon as you click the button an cross-domain error will be thrown:

image

The next post will show how this is solved quite elegantly.

Written by metadevblog

March 24, 2011 at 11:07 pm

Posted in WCF

Tagged with ,