Nick's .NET Travels

Continually looking for the yellow brick road so I can catch me a wizard....

Off to NZ to work at Intilecta

For those who haven't heard through the grapevine I have been fortunate enough to be involved with an exciting new startup venture here in sunny (not) Wellington, NZ.  Intilecta is set to be a major player in the future of BI software and it has been an awesome experience to date.  With initial funding secured the CTO, Greg Martin, has put together a crack development team, with Steve Sim as the Development Manager, former ISA Technologies architect, David Gardner (also a Perthite) and of course myself. 

After flying into Wellington last week I have almost acclimatised to the time, cold and wind.  These are all good things, especially the cold when you put it in perspective that one of my passions is snowboarding and that I am the proud owner of a season lift ticket to the local mountain.

So, how long am I in NZ for - well at this stage it is a 6 month stint to get the development process underway.  Afterwhich I will be returning to sunny (not joking this time) Perth.  In the meantime my colleague Alastair will be running the user group. 

If you are in Wellington, or feel like coming to NZ for a holiday, please make sure you look me up.  My new contact information should be on the contacts page of the SoftTeq website in the next couple of day.

Vista Update, VMWare and still no Windows Mobile 5 SDK

Mid-last week I spat the dummy and re-paved my machine back to WinXP.  After having Vista and Office running quite smoothly for a couple of weeks the straw that broke the camels back was the inability to connect my laptop to a number of wireless networks.  I must admit I find the new interface for network connections difficult to use - in fact, coupled with the continual need to Ok administrative prompts, it SUX.  But that's another story...

One of the other things that I found frustrating with Vista Beta2 was that I couldn't synchronise my WM5 device using the new Windows Mobile Device Center.  I could explore files, but not able to set up a partnership.  The story is that we had to wait for an update before we could setup a partnership, or for that matter use VS to debug mobile applications.  Anyhow, the update has arrived, but of course if arrived a day or so after I had converted my laptop back to WinXP - talk about frustrating.

So I figured I'd set up a VPC image with Vista - easily done!! and sure enough there was the update.  Once installed I figured this would fix the issues preventing the Windows Mobile 5 SDK from installing properly, but alas it still doesn't work.  The next thing I wanted to check was whether I could set up a partnership.  I ran VS2005 and used the Device Emulator Manager to run up the PPC2003SE emulator.  I then set the emulator to Cradle, which under WinXP would allow activesync to connect to the emulator as if it were a true device.  Unfortunately no joy - does this mean that there is only support for partnering with WM5 devices or is there an issue with the Device Emulator Manager??? 

I then cursed because although I have a real WM5 device there is no way to get it to connect to my Vista VPC because Virtual PC still does not have USB support - urgh when will this be fixed.

A while later I bit the bullet and downloaded a trial edition of VMWare Workstation.  Not only is the interface much richer than Virtual PC (including support for USB) it already has support for building a Vista image.  I wish that the Virtual PC team would learn something from the functionality of VMWare.

Finally, after many hours of installing Vista and Visual Studio I have an image that my WM5 device can connect to.  The new partnership setup is much better than activesync, and seems to work.  Unfortunately this STILL doesn't fix the issues with A) cradling an emulator or B) installing the WM5 SDKs

My experiences with Vista all seem to be 2 steps forward followed by 1 step back ;-) At least we're making progress forward.....

SQL Everywhere CTP - get it while it's hot....

A while ago Microsoft made the announcement that there was to be a change in the SQL product line to include a new product, SQL Server Everywhere.  In fact this is essentially a rebranding exercise around the SQL Mobile product (previously SQL Server CE).  There are going to be a couple of changes made, making it possible to run SQL/e (Steve's cute abbreviation) on Windows XP and hopefully a nice deployment model (for example ClickOnce).

Anyhow, if you want the goods you can get an early version by downloading the CTP

 

"How to build an annoying mobile application 101"

Even wondered how you can stop your device from accidentally calling people?  Or wanted to stop people drawing all over you application?  Perhaps you even have a legitimate reason to stop people using the touch display - like they are supposed to use the keyboard or hardware keys to navigate (like a smartphone)?  Well, look no further, here's a neat trick for disabling the touch screen on your device....

<System.Runtime.InteropServices.DllImport("touch")> _
Private Shared Sub TouchPanelDisable()
End Sub

This code snippet was brought to you curtesy of a fellow .NET CF MVP, Peter Foot.

Wanna see what Exchange SP2/WM5 has that your mobile application needs?

The Messaging and Security Feature pack combined with Exchange SP2 gives us mobile users direct-push email.  So how does this work, well a blog article by the exchange team gives a detailed insight into how it all works.

Why do we want to know how it works?  Well, the same technique can be used in our applications to make them respond immediately as information on the server changes.  Typically most mobile applications currently use some form of polling or SMS notification to initiate a sync.  This can both be expensive and not particularly effective.

Using the technique described by the exchange team, Alex Yakhnin shows how you too can have an application that is always up to date!

 

 

 

 

Mobile Client Software Factory.....we're almost there - Drop 11

In case you haven't seen, drop 11 of the Mobile Client Software Factory has hit the web site.  This includes a number of bug fixes and improvements in documentation.  You will also notice that support within Visual Studio has been added for creating disconnected service agent classes using a guidance package.

IMPORTANT - Feedback is urgently required by this team as they are rapidly approaching code freeze, please send feedback via the gotdotnet website ASAP.

.NET Micro Framework Whitepaper

A couple of people have started talking about the .NET Micro Framework which is, as the name suggests, an extremely cut down version of the .NET Framework.  Unlike the .NET Compact Framework which was designed to run on top of an existing OS, the .NET Micro Framework can operate without an underlying OS.  As such it has provisions for a HAL that is specific to the device onto which it is to be run.  The best news is that this is all going to have rich developer support through Visual Studio.  Check out the new whitepaper that provides early information about this framework.

Vista, Office, Live Messenger and finally MEDC 2006 presentations

So I've been a bit busy since MEDC 2006 installing Vista, Office and Live Messenger betas. The main reason being that there is currently no support for the Windows Mobile 5 SDKs under Vista.  After reinstalling various components and even trying to run the script file separately I was still no better off so I decided to build a WinXP VPC that I could do mobile development on.  Of course this wouldn't of worked using VS2003, but luckily the new emulators that ships with VS2005 are a true ARM emulators so will run happily within an X86 virtual machine, such as VPC.

Anyhow, this said, I finally managed to go through the sample and make sure that it functions.  Here are some of the MEDC resources I've been able to find.  I will try to update this as I track down other sessions:

-   Dr Neil's UX Presentation

-   Dr Pete's Data Presentation

-   Dave Glover's Connectivity Presentation

-   My code samples

One note about the code samples is that they were build using Community Drop 9 of the application blocks being created by the Patterns and Practices group as part of the Mobile Client Software Factory initiative.  I have included the relevant application blocks so that the solution should build.  There are newer builds of the application blocks that I would encourage you to download and start using.  The deadline for feedback on this project is THIS FRIDAY, so if you have something to say, then get it in soon.

Linq up that Webservice

As with many developers around the globe I downloaded the latest CTP of the Linq technology preview last week, but of course, work and other things got in the way.  As such it was this evening when I really had my first play (other than just opening the box and going wooow, which I dutifully did last week).  Of course, as Bill has already pointed out, one of the big improvements in the VB.NET space is the From, Where, Select syntax for Linq expressions.  This makes more sense if you look at how IDE support (eg intellisense) is vital to a feature being usable!

Despite giving a session at this year's Code Camp I still felt that there was a lot more I need to play with to really test the boundaries of this new technology.  An interesting scenario presented itself over the weekend, and for those of you building distributed, ocassionally connected applications this scenario might sound familiar: 

Let say I have a database which contains a table called Customers.  My mobile application wants to be able to call a webservice (eg CurrentCustomers) which will return a list/array of Customer objects.  While offline, these Customers may be modified, then when a connection is available, updates are persisted back to the database via another webservice (eg UpdateCustomer, which takes a Customer object as the parameter).

Now, lets break this into Linq/Dlinq components

Webservice
-   Create a new Linq ASP.NET application
-   Add a Dlinq object model and drag my Customers table across from Server Explorer
-   Create the Webservice methods CurrentCustomers and UpdateCustomer
-   Add code to CurrentCustomer to return the approprate Customer objects

Return (From c In db.Customers _
            Select c).ToArray

NB: Will leave code for UpdateCustomer for the moment as this is a bit tricky....

Client
-   Add web reference to the new webservice
-   Call the webservices (ie retrieve customer list, make changes and call update webservice)

So, the only part that I'm left to implement is the UpdateCustomer method in the webservice.  And here lies a problem - the way that Dlinq works is that when you access objects using a linq expression it dynamically loads them into memory.  As you make changes to these objects it tracks what has been modified so that when you call SubmitChanges on the DataContext it knows what changes to persist to the database.  Since the Client side of your application needs to be able to operated when disconnected, there is no way for this persistance manager to keep track of the objects you are working with.  When the Client submits the changes via the UpdateCustomer method somehow the persistance manager needs to be notified so that it can handle the writing to the database.

Before we jump in and look at the solution lets just delve a little into how the Dlinq persistance model operates.  The persistance model starts with a class that inherits from DataContext.  Think of this correlating to a database. This class in turn contains a number of Table(of T) objects, where T is a mapping class for a table in the database (in our case the Customer table).  T also implements the INotifyPropertyChanging and INotifyPropertyChanged interfaces.  This point is significant as it is these events that are used by the persistance manager to track changed objects. When a changed event is raised on an object, a clone of that object is created and maintained by the manager.  At a later stage the user has the option of rejecting changes (in which case the object is reverted to the clone) or submitting changes (in which case the difference between the objects is used to update the database).

The solution to our scenario is that somehow we need to a) get an unchanged version of the Customer object we have modified from the persistance manager, b) update that object with the Customer object sent from the client and finally c) persist the changes to the database.  In doing this I actually worked in reverse since a) is actually more fiddly, but I will present them here in order so that they make more sense.

a)   Get an Unchanged Customer

To retrieve a Customer object from the persistance manager we need to access the CommonDataServices object that sits within the DataContext object.  As this is a protected property we need to us a bit of reflection magic to discover it.  Once we have a reference we can call the Requery method to retrieve the Customer object.  Note that this object may be retreived from the in memory cache, or will be pulled from the database if the object doesn't already exist.

   Dim ser As Object = context.GetType.InvokeMember("Services", Reflection.BindingFlags.GetProperty Or Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic, Nothing, context, Nothing)

   Dim currentCustomerState As Object = ser.GetType.InvokeMember("Requery", Reflection.BindingFlags.InvokeMethod Or Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Public, Nothing, ser, New Object() {newCustomerState, False})

b)   Update Unchanged Customer

To update the managed Customer from the client's Customer all we need to do is iterate through each of the writable Properties of the Customer type.  The appropriate properties will also be marked with the ColumnAttribute to indicate their association with a database column.

        Dim props As PropertyInfo() = gettype(Customer).GetProperties
        For Each prop As PropertyInfo In props
            If prop.CanWrite And prop.CanRead Then
                Dim attribs As ColumnAttribute() = TryCast(prop.GetCustomAttributes(GetType(ColumnAttribute), True), ColumnAttribute())
                If attribs IsNot Nothing AndAlso attribs.Length > 0 Then
                    prop.SetValue(currentCustomerState, prop.GetValue(newCustomerState, Nothing), Nothing)
                End If
            End If
        Next

c)   Persist Changes to Database

What remains is to use the DataContext object to persist the changes to the database:

   context.SubmitChanges

And there you have it - how to persist a webservice object.  Now you can take this to the next level by extracting this out as an extension method for the DataContext class by removing all references to the Customer class, but I'll leave this discussion to another time (or to Bill's discussion on the topic).

Live Messenger gets another face lift and a KB article that laptop/tablet users should know about

As I didn't sign into Messenger over the weekend I didn't become aware of the refresh to the beta version of Live Messenger.  In my previous post on the leaked version of Live Messenger I talked about building Addins using the new managed API.  In the official update (version 8.0.0689, available via the beta program) this API is also now available for you to begin developing with.

The other piece of information I would like to share with all laptop and tablet PC users who have more than 1Gb of RAM on their machine relates to the occasional inability to hibernate.  If you have issues with hibernation then check out this knowledge base article as it might help.

Mobile Client Software Factory - Drop 7

So I've managed to allocate some time to take a quick look at the most recent community drop for the Mobile Client Software Factory.  From an initial inspection the part that I really like is that the Dynamic Resolution application block now works.  In my earlier post I discussed how this block can be used to provide different layouts for different resolutions/orientations.  At that stage there were some issues when a control was docked on a Form, as it didn't seem to apply the new layout before docking. This resulted in the layout not being appropriately resized.  In the latest drop this issue seems to have been fixed. 

I also noticed that not only can you change the resolution/orientation of your control while you are building it, but when you add your control to a form it applies the appropriate layout.  For example if you rotate your form in the designer (using the design skin introduced into VS2005) your dynamic resolution control will apply the horizontal layout so you can see what it will look like. 

Well done team, keep up the good work!

WM5 and Embedded devices @ MEDC

If you have seen the blogs by Dr Neil, Mike Hall and others about the Australian MEDC you would of course know that I’ve been invited to help the crew out and present again at the event this year.  During one of the many discussions about the event I was privy to some news that I thought you would all be interested to hear:  The team have secured a number of SP5 Windows Mobile phones and Via Single Board computers (which run Windows Embedded CE/XP).  At this stage I’m not sure of how or to whom these devices will be given, but hey what’s one more reason to attend the premier Mobility event of the year (don’t wait for TechEd to get your annual injection of developer goodness) !!!

Places at MEDC are limited, and rapidly filling up, I would recommend that you take advantage of this early notice and register as soon as possible.

Look forward to seeing as many of you as possible at the event.

Mobile Client Software Factory - Drop 6

Good news fellow mobilites, community drop 6 of the Mobile Client Software Factory (previously the Mobile Baseline Architecture Toolkit) has hit the shelves.  Actually the news is a bit old as I was trying to allocate some time to review the changes between drops.  Unfortunately time (particularly when there is work to be done) does get away from you some times.

In summary some of the changes that I have had time to notice are:

  • New Configuration Manager application block (which provides basic configuration functionality, similar to what's found in the full framework)
  • Connection Manager - now supports removing networks and connections after the manager has been created
  • Data Access - the concept of an abstract DatabaseService has been replaced with an abstract Database.  It also uses a DbProviderFactory, which should also be inherited for each database type to implement functions, CreateCommand, CreateConnection and CreateParameter.  This factory needs to be supplied in the constructor of the concrete Database implementation.
  • Data Access - the SQL Mobile implementation of the DatabaseService class also provides support for the SQLCeResultSet, which is unique to SQL Mobile.

More information will be available as I start to work more closely with this new framework.  Also, register for MEDC to see some of these application blocks in action when I take to the stage to assist fellow presenters Dr Neil Roodyn, Dr Peter Stanski and Dave Glover.

Vacant Exception Swallowers

So, I guess the question raised in Mitch's counter-post following my thoughts on checked exceptions in Java is whether we should have compiler errors for vacant exception handlers or whether we need to cull the developer population of vacant headed developers who think that empty exception handlers are acceptable. 

In the same way that enforcing coding standards (eg using code analysis/FxCop) doesn't ensure developers write good code, neither does having checked exceptions.  I guess one reason I like checked exceptions is that I have an idea of under what conditions a method call will throw an exception (is is of course assuming that framework developers use the concept properly).

More MEDC Matters

In case you haven't already seen the blogs from others, such as Dr Neil Roodyn, Mike Hall and Frank Arrigo, the list of speakers is now available for the Australian MEDC:

This is set to be a fantastic event and I highly recommend attending.  The level of presentations will be more advanced, based on customer feedback, than in previous years so it will be worth attending.

Oh to be an Exception....

After reading Mitch's discussion on throwing Exceptions and quickly refreshing my brain as to what the official Microsoft position is, I went away and was rethinking how I determine if/when I'm going to throw an exception.

I started off with the following concepts:

-   An exception should be thrown when a method/operation cannot be completed successfully.

-   Exceptions should no be used for application flow control.

-   Return values should not be used to indicate if a method/operation has been completed successfully

Now I must say that I agree with all of these.  However there is one concept that I definitely think has merit, which is:

-   An additional set of functionality should be provided to allow a developer to query whether a method/operation will be successful if called (eg "CanConnect" to be called prior to an attempt to call "Connect").

This last concept does cause me some concern though.  The main reason that you would want this functionality is to reduce the number of exceptions that are used for application flow control (see concept above) - for example in the case of the Connect method you would use a condition based on the CanConnect method to determine if Connect should be called.  So, what are the downsides:

-   Firstly, I see having these guards might lead to sloppy programming where exceptions don't get managed.  For example, just because I have called CanConnect, doesn't mean that Connect won't fail.  If it does and an exception is thrown, I still need to handle it!

-   Secondly, the query functionality may increase the time taken to call the method.  For example the CanConnect method might take as long as a call to Connect, in which case if this is routinely called everytime you need to connect it may well negatively affect performance. I guess there is a trade off here the again has to be managed.

My last thought regarding exceptions is that I still believe that .NET is missing a feature that I loved/hated in Java (and yes for my sins I did do a bit of Java programming way back when it was all the rage).  This feature is the way that methods specify which exceptions may be thrown. The reason I say loved/hated is that I loved it when I was building robust code, as it forced me to think about how I was using that method and whether I had handled the different responses (including exceptions) from the method. 

I hated this feature for two reasons.  Firstly, that it was a pain cause the compiler insisted that I rethrow exceptions that I didn't handle in my code (for example if I used a method that could throw an  IOException I either had to catch this or specify that my method could also throw this exception) - why can't the compiler be sensible and deduce this for me, after all when I use that method it's not that I look at the method itself to work out what exceptions are thrown, that's again the compilers job (or intellisense - does Java have that now??).  The second reason is that some developers are sloppy and just say that every method could throw Exception - kind of defeats the purpose of having this feature, right!!

Now it would appear that we may have missed the boat as it would be too difficult to go back and force every .NET method to specify which exceptions are thrown.  However, this is an area where tool support might provide a good compromise.  Now that both C# and VB.NET support rich xml commenting it may be an opportunity to really make use of this functionality.  By specifying in the comments which exceptions a method may throw, this could be used by the IDE to warn developers if they haven't handled theses exceptions when a method call is made.  As with most othe IDE support this could be an option that can be configured by the developer or dev team according to their preferences.

Mobile Client Software Factory (Dynamic Resolution)

The Dynamic Resolution application block is just way too cool.  So one of the on going issues with building applications for mobile devices with different screen orientations and resolutions is what to do when it changes (eg toggle between portait and landscape on a single device).  With version 2 of the .NET CF we now have anchoring and docking, but this just doesn't cut it - a screen layout that is designed for a portait device, just isn't going to be appropriate when it is in landscape.  The solution to this is to have different resource files for each orientation/resolution.  This is where the Dynamic Resolution application block is useful (class library below).

This application block is broken into two parts.  There is a device project (DynamicResolution) which you SHOULD reference in your project and there is a desktop designer project (DynamicReosltion.Designer) which you should NOT reference in your project.

In order to take advantage of this application block you need to create a control (or multiple) that inherit from the DynamicResolutionControl.  When you open this control in the designer you will see that it starts to generate additional resx files (eg Form1.240x320.resx or Form1.320x240.resx).  If you want to adjust the layout for a different orientation/resolution you can use the control properties to specify:

  • FormFactor (drop down listing all skins installed)
  • IsDefault (whether this layout should be used if no other specific layout found)
  • Orientation (Horizontal or Vertical)

Alternatively if you only want to rotate the current layout you can select Rotate from either the right-click context menu (off the control) or from the action list on the properties grid.

As you change orientation/resolution you will see that additional resource files are created.  If you also change the language/region you will see that specific language resource files are created.  For example you may end up with a list of resource files like this:

MyControl.vb
      MyControl.Designer.vb
      MyControl.resources
         MyControl.resX
         MyControl.240x240.resX
         MyControl.240x320.resX
         MyControl.320x240.resX
         MyControl.320x240.ar.resX
         MyControl.320x240.ar-EG.resX

The last two resx files are Arabic (ar) language and Arabic (Egypt) (ar-EG) language/region resource files for the 320x240 display.

Now when you use this control you will see that it changes the layout depending on the orientation/resolution of the device that it is running on.  However, there is a slight issue with the current version that is evident if you dock your control (for example if you dock your control into the main Form area).  It appears that the resources are applied after docking occurs, which means that sub-controls appear in the wrong location and the wrong size. 

The fix for this is relatively straight forward.  Modify the ApplyResource method in the DynamicResolutionControl class to include the following lines:

      private void ApplyResources()
      {
         DockStyle oldStyle=this.Dock;
         if (this.Dock != DockStyle.None)
            this.Dock = DockStyle.None;
         ....
      
   this.Dock = oldStyle;
      }

Mobile Client Software Factory (Subscription Manager)

An alternative to using webservices is to use sql replication.  The Subscription Manager application block provides a simple interface with which to manage sql replication between a sql mobile database and a sql server via a web publication (class list below).

The following example illustrates how you can create a DatabaseService to connect to a SQL Mobile database.  A SubscriptionManager is created and a SubscriptionParameters object is created to hold the properties of the publication to connect to.  The Synchronize method invokes the synchronisation process - this can be wired up to the Connection Manager to automatically synchronize when a network connection becomes available.

 'Create the database service - ie which database
        Dim ds As DatabaseService = New SqlDatabaseService("DataSource=""AWReplication.sdf"";")
        Dim credentials As ISubscriptionCredentialService = New SubscriptionCredentialService()

        Dim subs As New SubscriptionManager(ds, credentials)

        Dim subParams As New SubscriptionParamaters()
        subParams.Filter = "Mr."
        subParams.InternetUrl = "http://192.168.1.100/AWSampleWWW/sqlcesa30.dll"
        subParams.Publication = "AWSample"
        subParams.Publisher = "serverName"
        subParams.PublisherDatabase = "AdventureWorks"
        subParams.Subscriber = "CustomerListSubscription"
        subs.Add(subParams)

        subs.Synchronize(Subscriber)

In this example an instance is created of the SubscriptionCredentialService.  This is a class that we have created (that implements ISubscriptionCredentialService).  In the future this will hopefully be merged with the CredentialService block.

Public Class SubscriptionCredentialService
    Implements ISubscriptionCredentialService

    Public Function FindCredentials(ByVal subscription As Subscription) As SubscriptionCredentials Implements ISubscriptionCredentialService.FindCredentials
        Dim cred As SubscriptionCredentials = New SubscriptionCredentials()
        cred.PublisherSecurityMode = SecurityType.NTAuthentication
        Return cred
    End Function
End Class
 

Mobile Client Software Factory (Credential and Disconnected Service)

Mobile applications often want to make webservice requests to either send a message to a server or as part of the synchronisation process.  However if a connection is not available this request needs to be queued.  When a connection is available, if the request is important enough it should be sent.  Whether or not a request is important enough is dependent on the information in the request (ie the number of "stamps" allocated to the request) and how expensive the connection is (ie the "price" of the connection type").  If you read my blog article on the Connection Manager blog you will have noted that each connection type is allocated a price.  What we need now is a way to assign a number of stamps to a request and to manage a queue for requests (which should survive an application restart).  To do this we use the Disconnected Service application block (class list shown below).

This block needs to be notified when the connectivity of the device changes. When a connection becomes available it can send pending requests.  So that the block can register for connection change events we use the Connection Management block:

      Dim configuration As String = "<Connections>" & _
         "  <Connection  Type='CellConnection' Price='8'/> " & _
         "  <Connection  Type='NicConnection' Price='2'/> " & _
         "  <Connection  Type='DesktopConnection' Price='1'/> " & _
         "</Connections>"
      Dim factory As IConnectionManagerFactory = New Implementations.ConnMgrApiFactory(configuration)
      Dim conManager As ConnectionManager = factory.Create()

In order to queue requests this block uses two databases (don't try to use the database as you will get exceptions) to manage a pending queue and a dead request queue (where failed requests get placed). So we create two DatabaseServices using the Data Access block.

        Dim requestPath As String = "DataSource=""AWReplication.sdf"";"
        Dim database As DatabaseService = New SqlDatabaseService(requestPath)

        Dim deadRequestPath As String = "DataSource=""AWReplicationDead.sdf"";"
        Dim deaddatabase As DatabaseService = New SqlDatabaseService(deadRequestPath)

The next thing we need to do is create a ProxyFactory that will be used to create the web service proxy class.  As we will be queuing the web requests this block needs to be able to create the proxy class automatically.  This is done using the ProxyFactory class.  At the moment users of the block need to create their own factory class that inherits from the abstract OnlineProxyFactory class.  Hopefully this dependence will be removed in future versions.  A sample implementation is as follows:

Public Class ProxyFactory
    Inherits OnlineProxyFactory

    Public Overrides Function GetOnlineProxy(ByVal request As Microsoft.Practices.Mobile.ApplicationBlocks.DisconnectedServiceAgent.Request) As Object
        If (request.OnlineProxyType Is GetType(HelloWorldService.Service)) Then
            Dim onlineProxy As New HelloWorldService.Service()
            If (onlineProxy IsNot Nothing) Then
                onlineProxy.Url = onlineProxy.Url.Replace("/localhost/", "/" & MyBase.GetEndpointPhysicalAddress(request) & "/")
            End If
            Return onlineProxy
        End If
        Return Nothing
    End Function
End Class

We can see from this example that the url of the web request gets dynamically updated. In order for this to happen we have to load a list of endpoints that will be used for this substitution.  This list loads from an xml configuration file as shown in the following example:

        Dim pf As New OnlineProxyFactory 'ProxyFactory

        'Load the list of address endpoints
        Dim catalog As New AddressCatalog()
        catalog.Load("\Program Files\DispatcherSample\endpoints.xml")
        pf.Catalog = catalog

        'Load the list of credentials
        Dim credService As New CredentialsService()
        credService.Load("\Program Files\DispatcherSample\credentials.xml")
        pf.Credentials = credService

This example also loads a series of credentials from an alternative configuration file.  This makes use of the CredentialService application block (class file list below):

Sample configuration files:

Credentials.xml
<?xml version="1.0" encoding="Windows-1252"?>
<CredentialsCatalog>
  <Credentials>
    <Credential ServiceName="ServiceProxy://HelloWorldService" UserName="" Password="" />
  </Credentials>
</CredentialsCatalog>

Endpoints.xml
<?xml version="1.0" encoding="utf-8" ?>
<AddressCatalog>
  <Endpoints>
    <Endpoint Name="MyHost">
      <Network Name="My ISP" Address="192.168.1.100" />
    </Endpoint>
  </Endpoints>
</AddressCatalog>

So now we have a ConnectionManager, Pending and Dead request databases, and a ProxyFactory.  Now all we need to do is create the DispatchService:

      Private ds As New DispatchService

      ds.SetConnectionManager(conManager)
      ds.SetRepository(New DbQueueRepository(database))
      ds.SetDeadRequestsRepository(New DbQueueRepository(deaddatabase))
      ds.SetProxyFactory(pf)
      ds.Start()

A note of caution - make sure you place the DispatchService so that it won't get garbage collected (ie don't make it a local method variable). This DispatchService is all ready to go, so we can go ahead and create a new request.

            req = New Request()
      req.Id = Guid.NewGuid()
      req.CallParameters = New CallParameters()
      req.MethodName = "HelloWorld"
      req.OnlineProxyType = GetType(HelloWorldService.Service)
      req.Endpoint = "MyHost"
      req.Behavior.Tag = "Hello"
      req.Behavior.ReturnCallback = New CommandCallback(GetType(DispatchResponse), "ReturnCallbackMethod")
      req.Behavior.ExceptionCallback = New CommandCallback(GetType(DispatchResponse), "ExceptionCallbackMethod")
      req.Behavior.MaxRetries = 0
      req.Behavior.Stamps = 5

This creates a new web request for the HelloWorld web service.  You will notice that two call back methods are provided (specified by class and method name).  These will be invoked when the web request is executed or an exception is thrown.  We also allocate the number of "stamps" for this request.  The request will only be sent when a connection type of a price less than or equal to 5 is active.  Now all we have to do is use the DispatchService to enqueue the request.

        ds.Process(req)

 

Mobile Client Software Factory (Data Mapping)

In my previous post on the MCSF we saw how the Data Access application block can be used to simplify data access.  However, once we have retrieved the correct data rows from the database we still need to work with them.  We could either pipe them into a dataset and work with them as untyped data, or we could use the Data Mapper application block to convert the data into business objects.   The classes in this block are shown in the following image.

For anyone familiar with the work being done on the Linq/Dlinq project the way that the Data Mapping block works will look very similar.  We start of by defining our business object and by placing special attributes on the field or properties we want to map to specific columns in the database.  In the following code we use fields to keep the code sample short, but they would usually be placed on properties for proper encapsulation:

Public Class Customer

    Public Sub New()
    End Sub

    <DataMapping.DataMap("Customer Id", Data.DbType.String, 5)> _
    Public CustomerId As String
    <DataMapping.DataMap("Company Name", Data.DbType.String, 40)> _
    Public CompanyName As String
    <DataMapping.DataMap("Contact Name", Data.DbType.String, 30)> _
    Public ContactName As String

End Class

To work with the Data Mapper block we need to create an instance of the DataMapper class.  Again this is an abstract class so we need to use the concrete AttributeDataMapper class which provides the implementation details for working with attribute mapped business classes.  The DataMapper class supports a method for creating instance(s) of a particular business class.  This is illustrated in the following code example:

        Dim mapper As DataMapper(Of Customer) = New AttributeDataMapper(Of Customer)
        Dim customerSearch As String = "CustomerParameter"
        Dim sql As String = "Select * from Customers where [Customer ID] like " & ds.ParameterName(customerSearch)
        Dim para As System.Data.Common.DbParameter = ds.CreateParameter(ds.ParameterName(customerSearch))
        Dim reader As Data.Common.DbDataReader = ds.ExecuteReader(sql, para)

        Dim list As New List(Of Customer)
        list.AddRange(mapper.CreateAllInstances(reader))
        reader.Close()

        For Each c As Customer In list
            MsgBox(c.CompanyName)
        Next

Although the Data Mapper block can reduce the code you need to write to populate your business objects, it currently doesn't support a mechanism for creating, deleting or updating data in the database.  It also requires the developer to specify the sql expression used to retrieve the information from the database - since the required columns are all identified by the attributes this code could be automatically generated.  In comparison to the Dlinq model that supports class to table mapping attributes, the current DataMapper class is very limited, but could be used to build a much more flexible application block.