Goodbye Windows Mobile - HELLO Silverlight for Windows Phone 7 !!!!

When I downloaded and installed the Silverlight For Windows Phone 7 w/Visual Studio express application I was happy to see Mobile development was available in my VS2010 application also.  I was also glad to see Silverlight 4.0 as I was unable to play with it once I removed VS2010 Beta 2 and installed VS2010 CTP. 

Below you'll find a Silverlight 4.0 application, hosted in a ASP.NET MVC2 website, as well as the new Silverlight for Windows 7 emulator.  

The cool thing about Silverlight for Windows Phone 7 is that it is based on XAML!!   This was a pleasant surprise.  

I've been waiting patiently for Windows Mobile to emerge for VS2010 so that I could start my new framework (http://ehr.codeplex.com/) in which WPF, Silverlight and Mobile can all share the same codebase (multi-targeting).   I didn't really have XAML in mind for code sharing but it made for a fun exercise for learning - the following XAML is the exact code used for both GWN.EHR.Mobile and GWN.EHR.Silverlight MainPage views (with the exception of font sizes); the code-behind files also share identical code. 

<gwnLibrary:GWNPage

    x:Class="GWN.EHR.MainPage"

    xmlns:gwnLibrary="clr-namespace:GWN.Libary;assembly=GWN.Libary"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800" >

 

  <Grid x:Name="LayoutRoot" Background="Black">

    <Grid.RowDefinitions>

      <RowDefinition Height="Auto"/>

      <RowDefinition Height="*"/>

    </Grid.RowDefinitions>

 

    <!--TitleGrid is the name of the application and page title-->

    <Grid x:Name="TitleGrid" Grid.Row="0">

      <StackPanel>

        <TextBlock Text="MY APPLICATION" x:Name="textBlockPageTitle"

                  Foreground="White"/>

        <TextBlock Text="page title" x:Name="textBlockListTitle"

                  Foreground="White" FontSize="20"/>

      </StackPanel>

    </Grid>

 

    <!--ContentGrid is empty. Place new content here-->

    <Grid x:Name="ContentGrid" Grid.Row="1">

    </Grid>

  </Grid>

</gwnLibrary:GWNPage>

I was disappointed to find that, unlike Silverlight 4.0, Silverlight for Windows Phone 7 does not support MEF.   My initial attempts to migrate code over failed.  Research indicated that Prism support for Silverlight 4.0 is not slotted to start until April (CTP in Sept) so it looks like I'm going to be in limbo for a while...

The problem is I have aggressive goals of having modules completed for my http://EHR.CodePlex.com application by Jan 2011.  Coming out of the gate I decided to adapt the ContainerModel (Mobile DI container) for Silverlight 4.0 and Mobile; my plans are to make it look and feel like Unity to minimize refactoring when it is supported.  If MEF was supported it would have been my primary foundation however it's attribute system won't be easily emulated.  Likewise I'll use Prism concepts for XAML/Dependency properties to minimize refactoring for it when it is released.

My immediate goals are to get my GWN.EHR.POC application (bottom left in above image) into my new GWN.Library.xxxx libraries using my Unity like ContainerModel - to have WPF, Silverlight and Mobile all running from the same codebase using linked files.

 


Tags:
Categories: EHR | Silverlight | Unity


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

VS2010 RC - Azure "One of the request inputs is out of range" error

Things were starting to move rather smoothly, my base classes seemed to be pretty solid and all that remained was to add CRUD capabilities to CloudBlockBlob objects (Tables and Containers are done). 

I setup my unit test to create a new container for my Blob and I was greeted with a foreboding "One of the request inputs is out of range" with the inner exception reporting "The remote server returned an error: (400) Bad Request"; another head-banging session was about to begin....

Line 209 below is where the fun started, my container ("Images") didn't exist and the baseclasses are smart enough to create the container if it isn't available.   What had me chasing my tail for a while was "what input was wrong".   The short version - Azure only accepts lower case!!

Once I figured this out I updated by baseclasses to ensure that key points would convert to lowercase so that I would no longer be greeted by this obscure message in the future - I can use whatever I like and it will ensure nothing reaches the backend in anything other than lowercase.

 

  189 /// <summary>

  190 /// Determines whether this instance [can create cread update delete

          BLOB from file name].

  191 /// </summary>

  192 [TestMethod]

  193 [DeploymentItem("Images\\Jesus.jpg")]

  194 [DeploymentItem("Images\\AngelRays.jpg")]

  195 public void CanCreateCreadUpdateDeleteBlobFromFileName()

  196 {

  197     string imageName = "Jesus.jpg";

  198     string imageName2 = "AngelRays.jpg";

  199 

  200     string container = "Images";

  201 

  202     Assert.IsTrue(File.Exists(imageName));

  203 

  204     string fullName = new FileInfo(imageName).FullName;

  205     string fullName2 = new FileInfo(imageName2).FullName;

  206 

  207     //::::[ CREATE ]:::::

  208 

  209     string uniqueName = client.CreateBlob(container, fullName);

  210     Assert.IsNotNull(uniqueName);

  211 

  212 

  213     // ::::[ READ ]::::::

  214 

  215     using (MemoryStream stream = client.ReadBlobStream(container, uniqueName))

  216     {

  217         Assert.IsNotNull(stream);

  218         Bitmap image = new Bitmap(stream);

  219 

  220         // Save image as file

  221         image.Save("_"+imageName, ImageFormat.Jpeg);

  222         Assert.IsTrue(File.Exists("_"+imageName));

  223     }

  224 

  225     // ::::[ UPDATE ]:::::

  226 

  227     client.UpdateBlob(container, uniqueName, fullName2);

  228     using (MemoryStream stream = client.ReadBlobStream(container, uniqueName))

  229     {

  230         Assert.IsNotNull(stream);

  231         Bitmap image = new Bitmap(stream);

  232 

  233         // Save image as file

  234         image.Save("-" + imageName, ImageFormat.Jpeg);

  235         Assert.IsTrue(File.Exists("-" + imageName));

  236     }

  237     byte[] bytes1 = File.ReadAllBytes("_" + imageName);

  238     byte[] bytes2 = File.ReadAllBytes("-" + imageName);

  239     Assert.AreNotEqual(bytes1.Length, bytes2.Length);

  240 

  241 

  242     //:::[ DELETE ]:::::

  243     bool deleted = client.DeleteBlob(container, uniqueName);

  244     Assert.IsTrue(deleted);

  245 

  246     var deletedFileIsNull = client.ReadBlob(container, uniqueName);

  247     Assert.IsNull(deletedFileIsNull);

  248 }

Source code available at http://EHR.CodePlex.com  (GWN.Contrib.Azure project) 


Tags: , ,
Categories: Azure | Visual Studio 2010 | EHR


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

VS2010 RC - Unit Testing Azure Create, Read, Update and Delete (CRUD)

I did some head-banging this morning while writing a unit test for Azure table storage CRUD operations.   My WebRole application uses the PersonDataSource (line 8) as an ObjectDataSource and works without issue so I was perplexed as to why my unit test kept crashing on line 40.   The UpdateItem(testdata) was successfully executing but the value was not being updated to "TestOrganization" as expected.

    1 /// <summary>

    2 /// Determines whether this instance can create read update delete

    3 /// azure table records.

    4 /// </summary>

    5 [TestMethod]

    6 public void CanCreateReadUpdateDeleteAzureTableRecords()

    7 {

    8     PersonDataSource mockData = new PersonDataSource();

    9     EHRPerson testData = null;

   10 

   11     string uniqueId = Guid.NewGuid().ToString();

   12 

   13     //:::::[ CREATE ]:::::::

   14     bool isSuccessful = mockData.CreateItem(new EHRPerson

   15     {

   16         ID = uniqueId,

   17         Name = "EHRTest",

   18         Organization = "EHROrganization",

   19         PersonType = "EHRPersonType",

   20         ProfessionalTraining = "EHRProfessionalTraining"

   21     });

   22     Assert.IsTrue(isSuccessful);

   23 

   24     //:::::[ READ ]:::::::

   25     testData = new List<EHRPerson>(mockData.Read())

   26         .FirstOrDefault<EHRPerson>(p => p.ID.Equals(uniqueId));

   27 

   28     Assert.IsNotNull(testData);

   29     Assert.AreEqual("EHRTest", testData.Name);

   30     Assert.AreEqual("EHROrganization", testData.Organization);

   31     Assert.AreEqual("EHRPersonType", testData.PersonType);

   32     Assert.AreEqual("EHRProfessionalTraining", testData.ProfessionalTraining);

   33 

   34     //:::::[ UPDATE ]:::::::

   35     testData.Organization = "TestOrganization";

   36 

   37     mockData.UpdateItem(testData);

   38     testData = new List<EHRPerson>(mockData.Read())

   39         .FirstOrDefault<EHRPerson>(p => p.ID.Equals(uniqueId));

   40     Assert.AreEqual("TestOrganization", testData.Organization);

   41 

   42     //:::::[ DELETE ]:::::::

   43     mockData.DeleteItem(testData);

   44 

   45     testData = new List<EHRPerson>(mockData.Read())

   46         .FirstOrDefault<EHRPerson>(p => p.ID.Equals(uniqueId));

   47     Assert.IsNull(testData);

   48 

   49 }

What I found was that my item (TItem) parameter was being reset to default items on line 330 (image below) effectively overwriting my changes with original values.    However, if I ran my Cloud application it successfully updated the data (PersonDataSource as ObjectDataSource).   

I discovered that I was being returned the reference of the item that was read previously (line 25 above) which meant I was passing around a reference so line 330 below effectively replaced it with the original contents thus entry = item.  This wasn't a problem with the ObjectDataSource because I trust that ASP.NET creates a new instance and populates it with form values prior to sending it to the ObjectDataSource.

I resolved the issue by updating my TableServiceEntity base class to implement ICloneable so that I don't have to manage it at higher levels.    All of my table entities, i.e., EHRPerson will be POCO so this should work well.  

Source code available at http://ehr.codeplex.com/ (GWN.Contrib.Azure project) 

 


Tags: , ,
Categories: Azure | Visual Studio 2010 | EHR


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

MSBUILD Copy Task - Upgrading PRISM to Unity 2.0

I'm preparing to start an Electronic Health Record (EHR) Management System (http://EHR.CodePlex.com). To ensure that the application's infrastructure is not obsolete before it is completed I am using the newest techologies available (VS2010, Azure, PRISM, MEF, Unity, etc).  

The process that follows will ensure all Third-Party libraries are built and available for the new EHR application. 

Unity 2.0 and MEF Beta 2 are not yet released but I'll want to take advantage of their new features.  When they are released I'll have to perform this process again so I'll simplify it now.  Since PRISM is dependent on Unity I'll have to upgrade it so that it is compatible with Unity 2.0.  There are no dependencies on MEF but some changes have to be made because Beta 2 clashes with the version of MEF that resides in .NET 4.0.

Once I get all issues resolved so that the various projects and solutions will build I'll use a MSBuild's Copy task to transfer the .DLLs to a unified Binaries folder (c:\_\source\Binaries\Desktop).  My EHR application will reference this Binaries folder as required. 

I could simply place the ItemGroup and Target element directly into the applicable projects but it will be far easier to create a "CopyToBin.Desktop.Targets" file and reference it with one line of code. 

 

 

[CopyToBin.Desktop.Targets] contents follow: 

http://msdn.microsoft.com/en-us/library/3e54c37h.aspx

 

<Project DefaultTargets="AfterBuild"

    xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <ItemGroup>

      <AllDll Include=".\**\*.dll" />

    <CopyToBin Include="c:\_\source\Binaries\Desktop"/>

  </ItemGroup>

 

  <Target Name="AfterBuild">

    <Message Text="Processing Copy Task"/>

      <MakeDir Directories="@(CopyToBin)"/>

      <Copy

          SourceFiles="@(AllDll)"

          DestinationFolder="@(CopyToBin)"  />

  </Target>

</Project>

 

I'll place the .targets files in the root of my source folder (where all my third-party source code files reside).

To easily edit the project file simply right click on the project and "Unload" it.  Once unloaded you can right click on the unloaded project and select "Edit" (reference right pane in the image below).   Note that I have a snippet in my Toolbox so that I can simply go to the end of the project file and insert the location of my CopyToBin.Desktop.Targets file.   I'll then "Reload" the project

I'll do the above steps for all of the Unity projects and then build the project.   The resulting DLLs will be copied to the Binaries\Desktop folder where I can now transfer them to the applicable PRISM folder.

PRISM stores the Unity files in it's LIB\Desktop\Unity folder.  You'll have to delete the existing files and copy the newly created Unity DLLs from the Binaries folder to the above PRISM folder (later I'll have a batch file do this).

You are now ready to load the PRISM solution and compile it.  There are only a few differences in Unity 1.2 and Unity 2.0 that will break the build.

  1. Two projects will complain that you require a reference to System.Xaml (assuming you are also upgrading PRISM to VS2010).
  2. There are a few Mock objects that do not implement interfaces correctly - simply implement the interfaces as applicable.
  3. There will be two sections where you'll have to remark out code for objects that no longer exists (this is okay - I verified it with the PRISM team)

You should now be able to build PRISM using the newly compiled Unity 2.0 DLLs.

Note: To build MEF under VS2010 you'll need to follow the few steps I noted in the MEF Developers forum (CLICK HERE)

Once I have all of my projects setup with the new CopyToBin.Desktop.target I can run the batch files I created.   The first, BuildBinaries.cmd, will launch the Visual Studio 2010 command window - its contents follow:

@ECHO OFF
echo Type - and hit ENTER
call %comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"" x86

This batch file is the one provided by Visual Studio which sets up the environment (otherwise the second batch file won't find MSBuild).   It effectively opens a Visual Studio Command window so that you can easily run the second batch file "-.cmd"  (dash - keep it quick/simple). 

The -.cmd batch file is based on folder structures compatible with the third-party applications.  The batch file will change directories to each of the applicable solutions and then run MSBuild against it.

Note: I renamed the folders since doing the above screenshot to ensure I wouldn't have to modify the batch file later (I'll just simply ensure updates use the names used).

The end results is a I have a Binaries folder that is populated with all of the Third-Party DLLs that I will be using for my application.  When new releases are provided I simply have to ensure they compile and then run my batch file again.


Tags: , ,
Categories: CompositeWPF | EHR


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know