Thursday, May 29, 2014

Xamarin 3.0 and Xamarin.Forms - Getting Started

A while back I blogged about the possibility of Xamarin using something like XAML as a standard way to write UX because it isn't the platform specific syntax that's important; it's the platform specific look and behavior that's important.  Today Xamarin introduced Xamarin 3.0 and with it Xamarin.Forms that appears to do just that; we write in XAML and we get native controls out the other side.  The promise of Xamarin.Forms is that (for the most part) we need to know one UI syntax, XAML.

Please note, this does not mean that we want to make the same exact UI for Android, iOS and Windows Phone.  In fact that would produce a substandard user experience.  But to the extent possible, it's isn't the syntax that matters, only appearance and behavior.  Xamarin.Forms gives us a much greater possibility of sharing UI code across platforms than ever before while still maintaining a native experience.

For the most part I don't think we are going to be using Xamarin.Forms for a lot of applications that we would have considered using complex native UIs a few months ago because there are going to be some platform specific tweaks that are still going to demand a native design experience.  But that's OK because in such an application you can mix Xamarin.Forms for the more generic native experiences in the application with native forms where we need to do something very platform specific.

So where does that leave Xamarin.Forms?  Its sweet spot would seem to be when we may have considered using a hybrid tool like PhoneGap or Appcellerator for cross platform development.  Because Xamarin.Forms still produces a native UI it will produce a much better native experience for the user while giving us all the cross platform UI code sharing that we would get from these tools.  It would seem to be a far superior choice and extremely compelling.

I wanted to try this out.  Xamarin has an introduction that I found useful here:
http://developer.xamarin.com/guides/cross-platform/xamarin-forms/introduction-to-xamarin-forms/

It is day two of playing around with this for me and let me tell you Xamarin.Forms seems vast, very vast.  There is a lot to learn here and I look forward to attending next weeks Xamarin University class on Xamarin.Forms.  It is going to take a bit of time to really learn how to use it well.  For my first project I wanted to use actual XAML files and also use the new Universal Application Shared Projects.  For many reasons I believe this will be a better approach for most cross platform projects than using a PCL.

Here's what I did:

Step 1: Install Xamarin 3.0.  Just use the normal update process, no magic here.

Step 2: Create a new solution with projects for the platform specific UIs we want to support.  For my solution I selected an Android Application and an iOS empty Universal Application.




Step 3: Add a Xamarin.Forms project.  A Xamarin.Forms project is a project that provides shared code to the Android and iOS projects we just created.  This can be accomplished by using a portable class library or the new universal shared application.  Unfortunately in Visual Studio there are only three templates currently available under the Mobile Apps section.  One is used to create a multi-project solution with shared code through a portable class library, one to create a multi-project solution using a universal application shared project and one to create a new Xamarin.Form portable class library on it's own.  There is currently no template to create a Universal Application Shared Xamarin.Forms project on its own.  Luckily this is possible using the Universal Application Extension.  With this extension I created a new Universal Application Shared Project for my Xamain.Forms that I want to share with both projects and then put my Xamarin.Forms code in there.


Step 4: Add a reference to the Xamarin.Forms project to our iOS and Android projects.  This can be done by right clicking on references and selecting Add Nuget Package.  Search for the Xamarin.Forms project and add it.  Also add a Shared Project Reference for the new Universal Application Shared Project in the iOS and Android projects.


Step 5: Add a new Forms XAML Page to the Shared Project we created.  I called mine SharedForm.xaml.


Note: When I try to open the XAML file I get a designer error but I am still able to edit the XAML directly. From the Xamain.Forms forum on the Xamarin site it looks like there is currently no visual designer for this.  It was strongly hinted that one is in the works however.  I added a label and a button to make a very simple form that I called SharedForm.xaml.  The following is the code in my XAML file:


<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                       x:Class="XamarinFormsTest.Shared.SharedForm">
    <StackLayout Spacing="10">
        <Label Text="Foo" VerticalOptions="Center" HorizontalOptions="Center" />
        <Button Text="Bar" x:Name="btnBar" />
    </StackLayout>
</ContentPage>

Step 6: I want to show a popup window of some sort when they click on my new "bar" button.  It wouldn't surprise me to learn there is some sort of cross platform library for this in Xamarin.Forms but I don't know what it is.  Instead I used a Toast for Android and a UIAlertView for iOS.  This is where using a Universal Application Shared Project really shines.  Using the a conditional compilation symbol of __Android__ in the Android project and __IOS__ in the iOS project I was able to do the following:


   1:  public partial class SharedForm : ContentPage
   2:  {
   3:      public SharedForm ()
   4:      {
   5:          InitializeComponent();
   6:          btnBar.Clicked += btnBar_Click;
   7:      }
   8:   
   9:      private void btnBar_Click(object sender, EventArgs e)
  10:      {
  11:  #if __ANDROID__
  12:          Android.Widget.Toast.MakeText(Android.App.Application.Context, "Test 123", Android.Widget.ToastLength.Short).Show();
  13:  #elif __IOS__
  14:          new MonoTouch.UIKit.UIAlertView("Test", "Test 123", null, "Ok", null).Show();
  15:  #endif
  16:      }
  17:  }
  
First I made the SharedForm partial class inherit from ContentPage.  This shouldn't be necessary because the generated version of SharedForm also inherits from ContentPage but there seems to be some bug in the Universal Shared Projects where this wasn't recognized in the Visual Studio designer.  It was just easier to add it.

I also tied the click event of the button to a new method, btnBar_Click.  If we are compiled into the Android application the Toast message is used in the method, otherwise the UIAlertView is used for iOS.

Step 7: I went into the android project's main activity and changed it so it inherits from AndroidActivity instead of Activity.  I also made a call to Forms.Init() and created a new instance of my SharedFrom.  A quick call to SetPage and my XAML form is used.


   1:  [Activity(Label = "XamarinFormsTest", MainLauncher = true, Icon = "@drawable/icon")]
   2:  public class MainActivity : AndroidActivity
   3:  {
   4:      protected override void OnCreate(Bundle bundle)
   5:      {
   6:          base.OnCreate(bundle);
   7:  
   8:          Xamarin.Forms.Forms.Init(this, bundle);
   9:   
  10:          var form = new SharedForm();
  11:          SetPage(form);
  12:      }
  13:  }

When I run the application and click on the "Bar" button this is what I see:


Step 8:  I want to try the same thing for iOS.  So I go to the iOS project's AppDelegate.  In the FinishedLaunching event I again call Forms.Init() and then create an instance of my XAML form.  On the form there is a CreateViewController() method that I call to set the window's RootViewController.


   1:  public override bool FinishedLaunching(UIApplication app, NSDictionary options)
   2:  {
   3:      // create a new window instance based on the screen size
   4:      window = new UIWindow(UIScreen.MainScreen.Bounds);
   5:   
   6:      // If you have defined a view, add it here:
   7:      // window.RootViewController  = navigationController;
   8:      Forms.Init();
   9:   
  10:      var form = new SharedForm();
  11:      window.RootViewController = form.CreateViewController();
  12:   
  13:      window.MakeKeyAndVisible();
  14:   
  15:      return true;
  16:  }

I then run the project on the iOS simulator, click on the "Bar" button and this is what I see there:



Similar but different.  I used the same UI syntax for a button and in one case I got an android button and here I got an iOS 7 style button, nice and flat.  Granted this was a simple example and it looks like my label got a bit mixed up with text at the top of the iOS simulator.  There is clearly more experimentation and learning I need to do.  But the idea seems to work.  Almost all of my code was shared and I was able to do it with little fuss or muss.

Very exciting and I'm ready to learn more.

Tuesday, May 6, 2014

Universal Application Extension - Working with Xamarin

One thing I mentioned in my blog post last month was how to use the new universal shared application concept in your Xamarin applications.  At the time (all of a month ago) the only way to do add them to our Xamarin projects was through directly editing the project files to add a reference to the universal shared project.  OK, not too difficult but still a bit of a PITA.  Now there is a new extension for Visual Studio 2013 Update 2 that makes this easy and it can be obtained here:

http://visualstudiogallery.msdn.microsoft.com/315c13a7-2787-4f57-bdf7-adae6ed54450

After installing the extension here is how to use it:

  • Have a new or existing solution with two different projects where you want to share code, such as a solution that contains an iOS project and an Android project.
  • Add a new project for code sharing, use the "Shared Project (Empty)" template:
           Note: even if you don't have a Windows 8.1 project in your solution, adding a universal shared project will require you to get a Windows 8.1 developer license, at least it did for me.
  • In the universal project add any shared modules, classes, constants, etc that you want.
  • In each of the platform specific projects under references right click and select the new "Add Shared Project Reference"


  • A list of all shared projects in the solution will be displayed, select the one you want:


That's all there is to it.  You can directly create empty shared universal projects and then through the Visual Studio UI add references to them to platform specific projects.  No direct editing of the projects required.  It would be nice if adding the Universal shared project didn't require a Windows 8.1 developer license if you don't have a Windows 8.1 platform specific project in your solution, but that's a minor nit.

Thursday, April 10, 2014

Universal Apps: What Are They And Can I Use Them With Xamarin?

At Build this year the new Universal App type was announced that allows you to write apps on for both the Windows Store and Windows Phone 8.1 platforms with one code base.  There were also hints that this would be supported in Xamarin as well.  Exactly how these work was a little unclear to me so I downloaded the Visual Studio 2013 update 2 RC and did some experimentation, at least what is possible in the release candidate.  The Visual Studio 2013 Update 2 RC can be found here:

http://www.microsoft.com/en-us/download/details.aspx?id=42307

I opened up the new project window and with a little searching around this is what I found:



There are four new project types:

  • Blank App (Universal App) - Very simple solution to create two projects (Windows Store and Windows Phone 8.1) and one shared universal project with a nifty new icon
  • Hub App (Universal App) - Slightly more complex than the Blank app, it still creates a Windows Store and Windows Phone 8.1 projects both using the same shared project
  • Class Library (Portable for Universal Apps) - Creates a project to create a Portable Class Library (DLL) in the profile that supports Windows Store 8.1 and Windows Phone 8.1 applications.  Currently there are no profiles that support Windows Phone 8.1 and Xamarin so I was not able to make one of these that also supports Xamarin but I suspect this will be updated soon enough.  This project type is intended to create libraries that can be shared outside the solution.
  • Windows Runtime Component (Portable for Universal App) - Similar to the Class Library type except compiles into a winmd file instead of a dll.

Blank App (Universal App) - This creates a new universal app solution with three projects, One for a Windows Phone 8.1 UI, one with a Windows Store Application and one shared universal application which would seem to be where the interesting bits are.


The new shared app type just shows up with an xaml file and is referenced by both the Windows Store application and the Windows Phone 8.1 application.  This is a project type unlike what you may be used to, in fact it appears to be only a repository for shared code that can be used by other projects in the solution.  Here are some things that are of interest:

  • If you right click on the shared universal project and select properties all you can change is the root namespace.  That's it.
  • When compiled no DLL is generated for this project, all code in it is compiled directly into the Windows Store and Windows Phone 8.1 applications.  These projects cannot be independently be shared or used outside of the projects that directly reference them in a solution.
  • You cannot compile only the Shared project on the build menu, it cannot be built independently.  This makes sense give that it has no output and is compiled directly into a referencing project.
  • As of the time of the writing there is no references nor ability to add references to the shared project through the Visual Studio UI.  What is available to you within code of these projects is the subset of the .NET framework for this project and that's it.  That means no referencing Autofac or any third party library in code through the Visual Studio UI. 
  • EDIT TO PREVIOUS VERSION - The shared project *WILL* pickup references in the projects that reference them.  You have to select the proper project in the upper left dropdown when editing a file in the shared project and it will pickup the proper references.

Here is a screenshot of the project selection dropdown where you can select the right platform specific project and get the proper references and conditional compilation symbols:


I wasn't satisfied with the last point as it would be extremely limiting so I decided to do some experimentation.  I went out to Nuget and added the latest stable version of Windows Azure Mobile Services to the Windows Store and Windows Phone 8.1 projects.  I then opened up the Windows Store project file in Notepad and copied the following code to the shared project file from the Windows Store project file:

  <Import Project="..\..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\..

\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
  <Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
    <Error Condition="!Exists('..\..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This 

project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more 

information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
    <Error Condition="Exists('..\..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build 

restored NuGet packages. Build the project again to include these packages in the build. For more information, see 

http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
  </Target>

When I refreshed the shared project I still had no references section visible in the project on the Visual Studio UI.  However, I then created a new class in the Shared project with the following code:

using Microsoft.WindowsAzure.MobileServices;

namespace App1
{
    class ReferenceTest
    {
        private MobileServiceClient Test1()
        {
            return new MobileServiceClient("");
        }
    }
}

Granted this code is rather useless but Visual Studio now recognized that Microsoft.WindowsAzure.MobileServices is valid in the shared project.  I was able to compile both projects using the shared project just fine.  So there may not be support in the Visual Studio UI for this at the present time but it does appear possible to reference other assemblies in your shared project.  Of course when I removed the Windows Azure Mobile Services reference from my Windows Phone 8.1 project, it no longer compiled though the Windows Store project continued to compile so any references added to the shared project also need to be added to any project that reference it, which makes perfect sense.

How about Xamarin?  As I stated before I couldn't create a Portable Class Library for Universal Apps that also referenced either Xamarin iOS or Android as there did not seem to be a profile for that combination.  What about the shared project?  I went ahead and added Xamarin iOS and a Xamarin Android UI projects to the solution.  I then went to the references section of the Android project and tried to add a reference to App1.Shared like there was in the Windows Store and Windows Phone 8.1 projects.  No luck, that wasn't an option when looking at the solution nor could I browse out to a DLL because one does not exist.



I did, however, find the following blog post that states how to modify the project file:

https://medium.com/p/141c2b7bae4f

I took the advice and added the following code to my Android project file in Notepad (As noted in the blog, be careful about the path being correct or your project will not load):

<Import Project="..\App1\App1.Shared\App1.Shared.projitems" Label="Shared" />

When I then reloaded the Android project as the blog post indicated I suddenly has a reference to the shared universal app project.


When I tried to compile I couldn't for two reasons.  First the default Blank App added a Xaml file to the shared app, App.xaml. Currently xaml isn't going to be usable by the Android or iOS projects and so can't exist in App1.Shared.  I moved this to the individual Windows Store and Windows Phone 8.1 applications (I could also have used pre-compilation directives so it wouldn't be visible to the Android project to the same effect). 

The second reason is because the shared project uses the Windows Azure Mobile Services component and my Android project does not reference it.  I added this and the problem was resolved (Note: sometimes when getting the Windows Azure Mobile Services package for Xamarin from Nuget it drags along some extra system DLLs that I have to delete: System.IO, System.Runtime and System.Threading.Tasks).

With these issues resolved I am able to use the shared project in Xamarin Android.  By following the same steps I am able to do it with the Xamarin iOS project as well.

In conclusion, what have I learned about the present state of Universal Apps and Xamarin?

  • Universal PCLs and winmd projects won't work with Xamarin at the present time because there is no profile that supports Windows Phone 8.1 and Xamain project types.  I expect that to be resolved.
  • Creating a Universal Blank App or Hub app creates a shared project type
    • The shared project cannot be created directly through the Visual Studio UI and instead must be created through one of those two project types
    • Code in the shared project does not create a DLL or winmd file but instead is compiled directly into the projects that reference the project
    • There is no way through the Visual Studio UI to add a reference to an external dll to a shared universal project but references can still be added by editing the project file directly
    • You do not need references in the shared project because it picks up references form the projects that use it.  When in a code file you can switch between projects to pick up their references and conditional compilation constants
    • All projects that reference the shared universal project must reference and be able to use any code in the shared project or measures such as pre-compilation directives must be used
    • Xamarin iOS and Android UI projects can use the shared project but only if their project files are edited directly as there is not currently any way to do it through the Visual Studio UI

In general the shared universal projects would seem to be a new alternative to the old method of simple linking a shared code file between two or more different projects.  As is common with that method platform specific differences can be handled via pre-compilation directives.  Any sharing of the UX may work on projects that use xaml but of course such code is not currently workable in Xamarin Android and Xamain iOS and would have to be hidden from those project types.

UPDATE: If you want to create a PCL today that targets Windows Phone 8.1 and Xamarin Android and/or Xamarin iOS @danrigby has a great blog post that explains how to do it until an update is released:

http://danrigby.com/2014/04/10/windowsphone81-pcl-xamarin-fix/

Friday, April 4, 2014

The .NET Foundation and Xamarin

Miguel put this post on his blog discussing the joint announcement of The .NET Foundation:

http://blog.xamarin.com/xamarin-and-the-.net-foundation/

The .NET Foundation is an attempt to create cross platform language syntax for the features of the platforms where they operate similarly.  This is similar to what Microsoft has done with Azure's Mobile Service's Identity.  With Mobile Services Identity Microsoft realized that as a developer I don't care if I'm trying to authenticate against a Live account, Google, Twitter or Facebook.  All I care about is what service the user is authenticated with and the token returned.  The differences in syntax were not of interest to me, in fact as a developer they created a harmful knowledge barrier.  So Microsoft takes care of the differences in syntax and I just write against one unified syntax.

The .NET Foundation is bringing us more of the same for mobile platforms.  Do I care about the syntactical differences in Geolocation or the contact systems?  No probably not, so we have Xamarin Mobile.   Do we care about differences in how mail is sent out?  No probably not, so we have MailKit and MimeKit.  Ultimately anything that has common functionality between systems can be abstracted out behind a common language library to give common syntax.  This is big, huge in fact, for cross platform development.  The more knowledge barriers that can be removed between platforms, the less expensive and more maintainable native cross platforms solutions can be.

This got me thinking, what can't easily be abstracted out across platforms to a common syntax for a truly engaging and flexible native applications?  Two things quickly come to mind:

- The user experience.  Applications running on iOS that look like Android applications or Windows Phone apps do not create an engaging user experience and vice-versa.  The users on those platforms expect things to look a act in certain ways.  This isn't just the look and feel of the controls, it may be the general design of the screens themselves and the flow between screens, how menus operate, etc.

- Platform specific features and flow.  It's important to know that you can pass reference types between controllers on iOS but not between activities in Android.  Sometimes you need access to those properties, methods and events that exist on one platform and not the other.  It is similarly important to understand the lifecycle differences between the platforms, the fact that JIT code won't work on iOS, etc.  This type of platform specific knowledge will always be needed to write an application that looks, feels and acts like a native application and performs well on that platform.

If we look at these one at a time what do they mean?  For the user experience what is important is that we can create difference views on each platform with different layouts and a different look and feel.  What isn't as important is the syntactical differences in what the controls are.  Most of the time when I want to display some text I don't care if what I need to create is called a TextView or a UILabel.  I just want some control to display some text.  Similarly when I'm laying out the view I know that I want controls to appear in a certain order and usually be responsive to changes in the size of the UI.  Do I care if I'm using the XCode designer, some controls created and positioned in code or a LinearLayout for that?  Probably not.  So I can envision some sort of common designer with common syntax being created that will have a different look and feel (i.e. the correct native controls being used) when I'm in a Windows Phone project, an Android project or an iOS project.  But that will only take you so far which brings me to platform specific features and flow.

The platforms are different.  Whether it be fragments in Android or the TouchUpOutside event in iOS.  Activities and iOS controllers behave differently.  Those types of behavioral and feature differences will be hard to get away from and still create a native application that behaves and runs well on the individual platforms.  To the extent that they may be able to make a common syntax name for a button that actually creates the correct button on the native platform, that's great.  To the extent that they can use a common layout scheme like XAML that creates the appropriate native specific controls and layout, that's even better.  A single designer that works the same but looks differently on Andoird, iOS, Windows Phone and WinRT, that would be better still.  But at the end of the day we are still likely to need some sort of platform specific extensions to get at the control features and layout capabilities that are unique to one platform or the other.

I don't even know if common control syntax or designer while preserving native look, feel and flow is truly feasible.  Even then, we will likely still be creating multiple versions of the views that look/behave correctly on each platform even if the syntax is mostly the same.  It will be fun and interesting to see how this plays out; what things can have standardized language syntax while still preserving the platform specific look, feel, features and flow and what things can't.  I'd love to see that single UX designer that is emitting the correct native platform code.  Sure I still may be creating platform specific layouts but my tool and syntactic knowledge will be similar; that is, the platform specific knowledge barriers will be lowered. 

We will still need to know about how the individual platforms work, I don't think we will be able to move away from that and make native applications that look, feel and operate like native applications.  The .NET Foundation is clearly moving in the right direction to lower many of those barriers.  In the final analysis this clearly strengthens the value proposition of Xamarin and C#/.NET in cross platform development, which is kind of interesting in that it was one of the original thought processes behind .NET.  It just took us a while (and some people with vision and perseverance) to make it happen.

Sunday, March 23, 2014

Conditional Deployment of Resources in Xamarin Android


I was recently out at a client site and they asked me how to conditionally deploy resources in Xamarin Android.  They have a situation where they have one base application that they are creating and depending on the brand deploy a completely different set of resources.  It is important to note that they only want to deploy the resources that would be particular to that brand so as not to bloat the overall application with a bunch of images/strings that would never be used.  At the time this seemed like an interesting problem but one that I had never tried.  With a little digging I found an answer on the Xamarin site: 

Xamarin - Build Process

The Xamarin instructions are at a pretty high level and sometimes they need some experimentation to figure out all the wrinkles.  I decided to try this out and I wanted a solution that would meet the following criteria:

- It should allow for one set of resources to be shared for all brands and some resources to be brand specific
- It should be easy to specify building for one brand or the other
- It should support all types of resources, strings, views, images, etc
- It should be easy to setup and maintain

From the above article this will require some manual editing of the project file in something like notepad.  This means right off the bat my fourth requirement of "It should be easy to setup and maintain" is going to be a bit tenuous (note to self: perhaps a Visual Studio plugin could be made for this so it can be done through the UX?). 

First thing I did was set up a new project called MyResourceTest and renamed Activity1.cs to MainActivity.  That creates an Android project that looks like this:














I want to have a shared image and a shared string.  I use the default icon as my shared image and in the default strings.xml I change the string resources to contain a single value, SharedString:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string name="SharedString">Shared string used by all</string>
</resources>

Then I modify the Main.axml to display the shared string:
 


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
  <TextView
      android:id="@+id/lblShared"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="@string/SharedString" />
</LinearLayout>

Finally I remove the code for the button that was created by default in the MainActivity.cs:

using Android.App;
using Android.OS;

namespace MyResourceTest
{
    [Activity(Label = "", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity
    {

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.Main);
        }
    }
}

When I run this I get a very unexciting application, nothing new here:


























This is where the fun starts.  I want to add an image and a couple of strings that vary as far as what gets deployed based on what configuration I choose.  My application brands are going to be named AppOne and AppTwo and so I need to create four new configurations Debug-AppOne, Debug-AppTwo, Release-AppOne and Release-AppTwo.  I copy the default Debug and Release configurations to my new configurations as appropriate.  When I’m done I remove the default Debug and Release configurations because I won’t need them anymore.  The complete configuration setup looks like this:





















Now I’ll set up the directory structure to support my new applications.  In the project I’m going to create two new directories from the root of the project, Resources-AppOne, Resources-AppTwo.  Under each of these projects will be a Drawable and Values folder:


























Note: That there are now three resources directories, one for  our shared resources, one for the brand resources specific to AppOne and one for resources specific to AppTwo.  I could just as easily add a Layout folder to each of the new resources folders to have brand specific views.

To the Resources-AppOne\Drawable folder I add an image for AppOne called MainLogo.png and add an AppTwo MainLogo.png picture to the Resources-AppTwo\Drawable folder.  These will be two different images with the same name.  Be careful, if you add an image to one brand specific folder you will have to have an equivalent version with the same name in the other brand specific folders or have code in your application to handle the case where it might be missing.

To each of the brand specific Values folder I add a new xml file for my strings called strings-app.xml.  This needs to have a different name than any of the files under the default Resources\Values folder or you will have a collision at compile time.  In each of the files I set up two string values, ApplicationName, AppDescription.
File for Resources-AppOne\Values\Strings-App.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="ApplicationName">First Application</string>
    <string name="AppDescription">The First Application</string>
</resources>

File for Resources-AppTwo\Values\ Strings-App.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string name="ApplicationName">Second Application</string>
  <string name="AppDescription">The Second Application</string>
</resources>


Note: I make sure the build action for all of these files is set to AndroidResource for them to be used as Android Resources by the compiler.

I want to use my new image and strings in my view, Main.xml.  I change it to be as follows:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
  <TextView
      android:id="@+id/lblShared"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="@string/SharedString" />
  <TextView
      android:id="@+id/lblDescription"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="@string/AppDescription" />
  <ImageView
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:id="@+id/imgMain"
      android:src="@drawable/MainLogo"
      android:scaleType="fitCenter"/>
</LinearLayout>

Finally I also want the application’s title to use my brand specific ApplicationName string resource.  To do this I override the MainActivity’s OnAttachedToWindow event to use the ApplicationName string resource:

public override void OnAttachedToWindow()
{
    base.OnAttachedToWindow();
    this.Window.SetTitle(GetString(Resource.String.ApplicationName));
}

If I decide to try and run this now I’m going to get a couple of errors, the compiler doesn’t know how to deal with the Resources-AppOne or Resources-AppTwo folders.  Errors similar to the following appear:










This is where it gets a little difficult.  We can’t do what we want in the IDE, instead we need to edit the project file directly in a tool like Notepad.  If I open the project in Notepad and view my newly added brand specific files this is what I find:









I want to pull out the AppOne and AppTwo resources into their own ItemGroups that are conditionally included in the project if one of the AppOne or AppTwo configurations we added before are selected.  When done your project file should look similar to this:

<ItemGroup Condition="'$(Configuration)'=='Debug-AppOne'Or'$(Configuration)'=='Release-AppOne'">
    <AndroidResource Include="Resources-AppOne\Drawable\MainLogo.png" />
    <AndroidResource Include="Resources-AppOne\Values\Strings-App.xml">
      <SubType>Designer</SubType>
    </AndroidResource>
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug-AppTwo'Or'$(Configuration)'=='Release-AppTwo'">
    <AndroidResource Include="Resources-AppTwo\Drawable\MainLogo.png" />
    <AndroidResource Include="Resources-AppTwo\Values\Strings-App.xml">
      <SubType>AndroidResource</SubType>
    </AndroidResource>
</ItemGroup>
<ItemGroup>
    <Content Include="Properties\AndroidManifest.xml" />
</ItemGroup>

There is one more thing we need to do.  If you recall the compiler won’t see the Resources-AppOne or Resources-AppTwo directories as being valid.  We need to map them correctly in the project file.  Add two new conditional PropertyGroups, one for AppOne and one for AppTwo, to correctly map the directories:

<PropertyGroup Condition="'$(Configuration)'=='Debug-AppOne'Or'$(Configuration)'=='Release-AppOne'">
    <MonoAndroidResourcePrefix>Resources;Resources-AppOne</MonoAndroidResourcePrefix>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug-AppTwo'Or'$(Configuration)'=='Release-AppTwo'">
    <MonoAndroidResourcePrefix>Resources;Resources-AppTwo</MonoAndroidResourcePrefix>
</PropertyGroup>

If I save the project file and reopen it, the project will use the correct resources for the configuration I have selected.  If I select Debug-AppOne and run the application this is what I see:
























If I then select the Debug-AppTwo profile I see this:
























Remember, this is doing more than just using the correct resources at run time like when you have language specific resources, it is only compiling in the resources specified by the selected configuration.  To verify this you can examine the obj output folders for the appropriate configuration.  Compiling in an alternate set of resources is as simple as changing the selected configuration from Debug-AppOne to Debug-AppTwo.  In general this satisfies all my conditions other than it does take some time to setup and to maintain.  That is, if new drawable resources are added to the brand specific resource directories you will still need to modify the project file directly and make sure they show up under the correct conditional ItemGroups. 

There are probably other ways to do this such as using your source control solution with some sort of branching strategy but that seems too difficult to manage.  As I indicated earlier at some point a Visual Studio plugin could be added to make this easier to do through the UX but at the present time as indicated on the Xamarin site this would seem to be the easiest way to do it.

Tuesday, February 18, 2014

The High Cost of Cross Platform Standards

Recently Jason Bock posed a question to our company about where should validation happen in an application; on the client, on the server, both?  In the past the pendulum in the world of application development has swung back and forth between thin and thick client and as it has the location of validation has shifted.  Green screen terminals with heavy logic on the back end, one and two tier applications with the majority of validation in the client.  The rise of COM with the ability of creating n-tier applications where the same business logic could be written on the client and the server (I'll ignore the fact that so many people did this poorly).

How did this all happen?  Companies were able to unilaterally innovate and proprietary systems reigned supreme.  With the rise of the PC companies made DBase, FoxPro, VB; each was independently successful on the PC platform.  Several years later MS could unilaterally put COM in place and later .Net.  These were more than just languages, frameworks and syntactic sugar, they were designed to allow new paradigms.

Since the late '90s we are now also in the world of HTML and JavaScript.  These represented a cross platform standard which is great.  Theoretically we can write applications once and they will run anywhere.  Of course in practice this is more like write once and tweak everywhere but the promise is there.  When web applications first started being written they were amazingly primitive.  Mostly just simple validation with much of the complex validation and business logic happening on the server.  But, as has happened in the past the people using the applications wanted a richer experience.  Over time, in a glacially slow progression, we started getting tools to allow this such as AJAX, JQuery and eventually a whole plethora of new JavaScript frameworks like Knockout and Angular.

Now we have all kinds of cool things like TypeScript and SPA frameworks all is good in the world, right?  Maybe, but maybe not.  The agreement on and adoption of HTML5 has been glacially slow.  Without a change to JavaScript or the HTML standard any new innovations must be layered on top of what is already there.  It is very hard with something like HTML and JavaScript to do fundamental changes like creating COM or the .Net framework.  For example, Google has been working on native object binding in HTML with Object.Observe() but of course it's not that easy to get something like that in the standard.  What do they have to do instead?  Build binding in Angular which of course is written in JavaScript and much slower than native data binding would have been.  How long do we wait for new JavaScript extensions and HTML 6?

In answer to Jason's question: the users will continue to demand richer and richer applications.  This means that business logic will have to be written in the browser in JavaScript or something layered on top of JavaScript.  To make sure that the information being sent to the web server is correct we will end up writing it again in C#, emiting simple JavaScript based on logic written in C# or running to node.js to write our server side validation so we only write the business logic once in JS.  What is not easily possible is to quickly make a major change in the underlying technologies of HTML and JavaScript to make a better, easier language to meet these demands. 

For better or for worse we have the cross platform advantages that JavaScript represents while we work around the slow pace of change that the cross platform also represents.  The people we write applications for are not going to be willing to wait for the language to change on its own so there will continue to be a place for Node.js, Angular, JQuery, Knockout and TypeScript.  Constructs written on top of JavaScript will do their best to make up for what the language can't do or isn't optimized to do.  A cross platform language like JavaScript cannot directly keep up with the pace of change that our industry demands.

Tuesday, December 17, 2013

CSLA, Inversion of Control and Unit Testing: Part 1 Sending an interface to the CSLA Data Portal

This post is part one in a multi part series on Inversion of Control (IoC) and unit testing in the CSLA framework. 

As most of you know, IoC can reduce coupling within our applications.  CSLA has many new features that support this.  For the purposes of this blog post I'm using CSLA version 4.5.4.

How do we get started?  I'll start with creating the interfaces that we will use.  The five most common stereotypes in CSLA are BusinessBase, BusinessListBase, ReadOnlyBase, ReadOnlyListBase and CommandBase.  With each of these we can make an interface for our concrete classes that in turn inherits from the appropriate CSLA interfaces for these types:

A sample interface for BusinessBase:

   1:  public interface ITestBusinessBase : Csla.IBusinessBase
   2:  {
   3:      int Id { get; }
   4:      string Name { get; set; }
   5:      void SomeMethod(string someParameter);
   6:  }


A sample interface for BusinessListBase and a leaf:

   1:  public interface ITestBusinessBaseLeaf : Csla.IBusinessBase
   2:  {
   3:      int Id { get; }
   4:      string Name { get; set; }
   5:  }
   6:      
   7:  public interface ITestBusinessCollectionBase : Csla.IBusinessListBase<ITestBusinessBaseLeaf>
   8:  {
   9:  }

A sample interface for ReadOnlyBase:

   1:  public interface ITestReadOnlyBase : Csla.IReadOnlyBase
   2:  {
   3:      int Id { get; }
   4:      string Name { get; }
   5:  }

A sample interface for ReadOnlyListBase:

   1:  public interface ITestreadOnlyBaseLeaf : Csla.IReadOnlyBase
   2:  {
   3:      int Id { get; }
   4:      string Name { get; set; }
   5:  }
   6:   
   7:  public interface ITestReadOnlyListBase : Csla.IReadOnlyListBase<ITestreadOnlyBaseLeaf>
   8:  {
   9:  }

A sample interface for CommandBase:

   1:      public interface ITestCommandBase : Csla.ICommandBase
   2:      {
   3:          bool SomeResult();
   4:      }

One thing to notice here is there are no static methods and the CSLA samples generally use static factory methods.  Why is this?  Unfortunately static methods are not able to be added to an interface in C# so if we still use factory methods we need to be aware that any code that uses them may be tied to the concrete class that defines them.  This may, or may not, be OK depending on what we are trying to do.  It is important to note that the static factory method could still use an IoC container to resolve out the object factory and instance that it is creating.

Ok, so what's next?  I use an IoC container, for the purposes of this posting I'll use Autofac.  Generally in our production code we are going to use the same IoC container for all operations.  I use a Service Locator pattern for this.  There are some schools of thought that declare this pattern to be somehow wrong but I don't subscribe to that philosophy.  Generally if you use ASP MVC you are already using service locators to resolve out the routes and to bind your post backs to your models.  I'm not going to get too far into why the Service Locator pattern may in some cases be appropriate but suffice it to say if you are using CSLA, you will need to buy into the idea that Service Locators are at least not harmful. 

The following static class gives me program wide reference to my IoC container.  At some point I need to set the Container property for use:

   1:  public static class IoC
   2:  {
   3:      public static Autofac.IContainer Container { get; set; }
   4:  }

Another CSLA component that we may take a dependency on is the DataPortal itself.  I generally abstract this out behind my own implementation using CSLA's IDataPortal<T> interface.  For the purpose of this post, I created an IObjectFactory interface to also expose out the "child" DataPortal methods that are not part of the IDataPortal<T> interface:

   1:  public interface IObjectFactory<T> : IDataPortal<T>
   2:  {
   3:      TC CreateChild<TC>();
   4:      TC CreateChild<TC>(params object[] parameters);
   5:      TC FetchChild<TC>();
   6:      TC FetchChild<TC>(params object[] parameters);
   7:      void UpdateChild(object child);
   8:      void UpdateChild(object child, params object[] parameters);
   9:  }

The concrete implementation of the ObjectFactory class would be as so:

   1:  public sealed class ObjectFactory<T> : Common.Interfaces.IObjectFactory<T> where T : class, IMobileObject
   2:  {
   3:      public void BeginCreate(object criteria, object userState)
   4:      {
   5:          DataPortal.BeginCreate(criteria, CreateCompleted, userState);
   6:      }
   7:   
   8:      public void BeginCreate(object criteria)
   9:      {
  10:          DataPortal.BeginCreate(criteria, CreateCompleted);
  11:      }
  12:   
  13:      public void BeginCreate()
  14:      {
  15:          DataPortal.BeginCreate(CreateCompleted);
  16:      }
  17:   
  18:      public void BeginDelete(object criteria, object userState)
  19:      {
  20:          DataPortal.BeginDelete(criteria, DeleteCompleted, userState);
  21:      }
  22:   
  23:      public void BeginDelete(object criteria)
  24:      {
  25:          DataPortal.BeginDelete(criteria, DeleteCompleted);
  26:      }
  27:   
  28:      public void BeginExecute(T command, object userState)
  29:      {
  30:          DataPortal.BeginExecute(command, ExecuteCompleted, userState);
  31:      }
  32:   
  33:      public void BeginExecute(T command)
  34:      {
  35:          DataPortal.BeginExecute(command, ExecuteCompleted);
  36:      }
  37:   
  38:      public void BeginFetch(object criteria, object userState)
  39:      {
  40:          DataPortal.BeginFetch(criteria, FetchCompleted, userState);
  41:      }
  42:   
  43:      public void BeginFetch(object criteria)
  44:      {
  45:          DataPortal.BeginFetch(criteria, FetchCompleted);
  46:      }
  47:   
  48:      public void BeginFetch()
  49:      {
  50:          DataPortal.BeginFetch(FetchCompleted);
  51:      }
  52:   
  53:      public void BeginUpdate(T obj, object userState)
  54:      {
  55:          DataPortal.BeginUpdate(obj, UpdateCompleted, userState);
  56:      }
  57:   
  58:      public void BeginUpdate(T obj)
  59:      {
  60:          DataPortal.BeginUpdate(obj, UpdateCompleted);
  61:      }
  62:   
  63:      public T Create()
  64:      {
  65:          return DataPortal.Create<T>();
  66:      }
  67:   
  68:      public TC CreateChild<TC>()
  69:      {
  70:          return DataPortal.CreateChild<TC>();
  71:      }
  72:   
  73:      public TC CreateChild<TC>(params object[] parameters)
  74:      {
  75:          return DataPortal.CreateChild<TC>(parameters);
  76:      }
  77:   
  78:      public T Create(object criteria)
  79:      {
  80:          return DataPortal.Create<T>(criteria);
  81:      }
  82:   
  83:      public async Task<T> CreateAsync(object criteria)
  84:      {
  85:          return await DataPortal.CreateAsync<T>(criteria);
  86:      }
  87:   
  88:      public async Task<T> CreateAsync()
  89:      {
  90:          return await DataPortal.CreateAsync<T>();
  91:      }
  92:   
  93:      public event EventHandler<DataPortalResult<T>> CreateCompleted;
  94:   
  95:      public void Delete(object criteria)
  96:      {
  97:          DataPortal.Delete<T>(criteria);
  98:      }
  99:   
 100:      public Task DeleteAsync(object criteria)
 101:      {
 102:          return DataPortal.DeleteAsync<T>(criteria);
 103:      }
 104:   
 105:      public event EventHandler<DataPortalResult<T>> DeleteCompleted;
 106:   
 107:      public T Execute(T obj)
 108:      {
 109:          return DataPortal.Execute<T>(obj);
 110:      }
 111:   
 112:      public async Task<T> ExecuteAsync(T command)
 113:      {
 114:          return await DataPortal.ExecuteAsync<T>(command);
 115:      }
 116:   
 117:      public event EventHandler<DataPortalResult<T>> ExecuteCompleted;
 118:   
 119:      public T Fetch()
 120:      {
 121:          return DataPortal.Fetch<T>();
 122:      }
 123:   
 124:      public T Fetch(object criteria)
 125:      {
 126:          return DataPortal.Fetch<T>(criteria);
 127:      }
 128:   
 129:      public async Task<T> FetchAsync(object criteria)
 130:      {
 131:          return await DataPortal.FetchAsync<T>(criteria);
 132:      }
 133:   
 134:      public async Task<T> FetchAsync()
 135:      {
 136:          return await DataPortal.FetchAsync<T>();
 137:      }
 138:   
 139:      public TC FetchChild<TC>()
 140:      {
 141:          return DataPortal.FetchChild<TC>();
 142:      }
 143:   
 144:      public TC FetchChild<TC>(params object[] parameters)
 145:      {
 146:          return DataPortal.FetchChild<TC>(parameters);
 147:      }
 148:   
 149:      public event EventHandler<DataPortalResult<T>> FetchCompleted;
 150:   
 151:      public ContextDictionary GlobalContext
 152:      {
 153:          get { return ApplicationContext.GlobalContext; }
 154:      }
 155:   
 156:      public T Update(T obj)
 157:      {
 158:          return DataPortal.Update<T>(obj);
 159:      }
 160:   
 161:      public async Task<T> UpdateAsync(T obj)
 162:      {
 163:          return await DataPortal.UpdateAsync<T>(obj);
 164:      }
 165:   
 166:      public event EventHandler<DataPortalResult<T>> UpdateCompleted;
 167:   
 168:      public void UpdateChild(object child)
 169:      {
 170:          DataPortal.UpdateChild(child);
 171:      }
 172:   
 173:      public void UpdateChild(object child, params object[] parameters)
 174:      {
 175:          DataPortal.UpdateChild(child, parameters);
 176:      }
 177:  }

This object factory implementation requires that our IoC container understand the concept of generics and the type of object that we pass in must implement CSLA's IMobileObject interface.  The IBusinessBase, IBusinessListBase, IReadOnlyBase, IReadOnlyListBase and ICommandObject all implement this interface and will be usable for our custom object factory.  If I always make sure to use the IObjectFactory interface to resolve out my DataPortal call I will be able to mock the entire thing out when writing unit tests.

To create our concrete classes we can follow this pattern:

   1:  public class TestBusinessBase : BusinessBase<TestBusinessBase>, ITestBusinessBase
   2:  {
   3:      public static readonly PropertyInfo<int> IdProperty = RegisterProperty<int>(c => c.Id);
   4:      public int Id
   5:      {
   6:          get { return GetProperty(IdProperty); }
   7:          private set { LoadProperty(IdProperty, value); }
   8:      }
   9:   
  10:      public static readonly PropertyInfo<string> NameProperty = RegisterProperty<string>(c => c.Name);
  11:      public string Name
  12:      {
  13:          get { return GetProperty(NameProperty); }
  14:          set { SetProperty(NameProperty, value); }
  15:      }
  16:   
  17:      public void SomeMethod(string someParameter)
  18:      {
  19:          throw new NotImplementedException();
  20:      }
  21:   
  22:      public static ITestBusinessBase CreateTechBusinessBase()
  23:      {
  24:          return IoC.Container.Resolve<IObjectFactory<ITestBusinessBase>>().Create();
  25:      }
  26:   
  27:      public async static Task<ITestBusinessBase> GetTestBusinessBaseByIdAsync(int id)
  28:      {
  29:          return await IoC.Container.Resolve<IObjectFactory<ITestBusinessBase>>().FetchAsync(id);
  30:      }
  31:  }

This is a sample of an implementation for our BusinessBase interface and all the stereotypes will generally look the same.  There are a few of things to notice here:

- Our concrete class still inherits from CSLA's BusinessBase class as well as our ITestBusinessBase interface
- Using the static factory methods will tie anything using it to the concrete class TestBusinessBase to locate the factory method
- We always return our interface instead of the concrete class type
- We use the global IoC class to resolve by interface instead of calling the concrete object factory or the concrete TestBusinessBase.  This allows us to return any implementation of the IObjectFactory and/or ITestBusinessBase we desire from the IoC container.  This will be very useful when it comes to creating unit tests.

If you don't like the idea of using the static factory methods, any code that would call the factory method can call the object factory instead.  The downside of this is if we have our factory methods abstract out knowledge of the criteria and parameters allowed to make it easy for the consumers of our classes.  The person using our classes will instead need to know the particulars of the allowed parameters for the factory.  For the above class we could call the following instead of calling the GetTestBusinessBaseByIdAsync factory method:

   1:  await IoC.Container.Resolve<IObjectFactory<ITestBusinessBase>>().FetchAsync(id);

To understand what we need to do next we have to understand a little about how CSLA's data portal works.  When we ask it to create, fetch or save an object it creates an instance of that type (unless using the object factory pattern which is not covered here).  The type to create is determined by the type set in the data portal generic.  For example if I call the following:

   1:  DataPortal.Create<TestBusinessBase>()

The CSLA data portal will attempt to create an instance of the TestBusinessBase object and then call it's DataPortal_Create method.  But that's not what our code ends up doing.  What our code ultimately will call on the CSLA data portal is this:

   1:  DataPortal.Create<ITestBusinessBase>()

CSLA's data portal won't know what concrete class to create in this case.  ITestBusinessBase is just an interface.  So what do we do?  This is where CSLA's IDataPortalActivator interface comes into play.  This interface allows us to do two things:

- Tell CSLA what instance to create (CreateInstance method)
- Set any properties on that instance after it is created (InitializeInstance method)

There are a few items to note here.  The CreateInstance method only receives one parameter, the type that is being requested.  In normal CSLA operation this would be a concrete type but in our case we are going to be passed in the ITestBusinessBase interface.  There is an implication to this as we do not have access to any other parameters sent along with the data portal call.  This means we only have a few ways to create the required instance from the type information:

- A convention that given the type of the interface we are able to determine the concrete type we want to create

   1:  public object CreateInstance(Type requestedType)
   2:  {
   3:      if (requestedType == null)
   4:      {
   5:          throw new ArgumentNullException("requestedType");
   6:      }
   7:   
   8:      return requestedType.IsInterface ? CreateConcreteTypeByConvention(requestedType) : Activator.CreateInstance(requestedType);
   9:  }

- Pulling something out of global scope, such as an IoC container, to resolve out the concrete type we want to create

   1:  public object CreateInstance(Type requestedType)
   2:  {
   3:      if (requestedType == null)
   4:      {
   5:          throw new ArgumentNullException("requestedType");
   6:      }
   7:   
   8:      return requestedType.IsInterface ? IoC.Container.Resolve(requestedType) : Activator.CreateInstance(requestedType);
   9:  }

The InitializeInstance method allows us to set and initialize properties on the newly created instance but it only receives a reference to the instance of the class that was created in the CreateInstance method.  Like the CreateInstance method, any information that we sent along with the initial data portal request is not directly available to us.  For example, we cannot pass in the IoC container as a parameter to a factory method that uses the CSLA data portal and then use that parameter in the CreateInstance method to create an instance of the class we want without somehow storing it in a global context. 

CSLA does provide a way to set up parameters in a global context that can be used in the CreateInstance and InitializeInstance methods.  Implementing the IInterceptDataPortal interface will provide us with methods we can use for this purpose. This interface has Initialize and Complete methods that happen at the start of and end of our data portal call and allow us to set up and then clean up any global context needed.  Be aware that the are some complications around the cleanup, particularly if an error occurs in the request.  I won't be covering using the IInterceptDataPortal interface in this blog post.  The best person to ask about using it is Jason Bock.

A sample IDataPortalActivator class may look like this:

   1:  public sealed class ObjectActivator : IDataPortalActivator
   2:  {
   3:      public object CreateInstance(Type requestedType)
   4:      {
   5:          if (requestedType == null)
   6:          {
   7:              throw new ArgumentNullException("requestedType");
   8:          }
   9:   
  10:          return requestedType.IsInterface ? IoC.Container.Resolve(requestedType) : Activator.CreateInstance(requestedType);
  11:      }
  12:   
  13:      public void InitializeInstance(object obj)
  14:      {
  15:      }
  16:  }


To tell CSLA to use our new activator instead of the default CSLA implementation call the following line in code:

   1:  Csla.ApplicationContext.DataPortalActivator = new ObjectActivator();

Notice this is also a service locator pattern.  I want to reiterate this idea.  Like ASP MVC, CSLA is built on top of service locators.  This call is no different.  In order to use frameworks like ASP MVC or CSLA you have to buy into the idea that the service locator pattern is sometimes desirable.

In this post we learned how to create and pass around CSLA objects as interfaces instead of concrete classes using the CSLA data portal.  This will allow us much greater flexibility when it comes to unit testing and mocking.  In my next post we will talk about how to similarly abstract away data access calls to assist in unit testing and mocking.