Camera Connection Kit + USB/SD Memory = More iPad (Virtual) Memory

After I figured out how images and movies from outside digital cameras can be imported into iPad, I don’t get that impulse to buy a big one anymore! :-)

The big question people might have after reading my earlier post is: why would anyone want to go through that painful process of renaming, copying and importing files while you can simply drag and drop them with the help of iTunes? Simple answer is more memory. If you have already stuffed up your iPad with lots of things but have more stuff to view on iPad, may be while on travel, you can simply copy those things to a large capacity SD/USB storage and use the Camera Connection Kit to view them on iPad. But mind you: you should have enough swap space on your iPad to import files. The whole idea is nothing but the memory paging concept of operating systems but applied in raw way, I don’t take the credit:-) So, in net:

[External Card Capacity] – [iPad Swap Space] = Extra iPad Virtual Memory!

In my case: [64GB USB Drive] – [Free 8GB of 16GB] = 56GB!!

On a lighter side: if you can carry more memory cards then total up their capacity so you will have even more stuff to play with :-)

iPad, Camera Connection Kit & Image File Names

This really took me for a ride!! In the past two days I burnt so much of energy trying HARD to transfer some JPEG and PNG files from my laptop to my iPad. The simple intention was to use those nice files for the "Digital Photo Frame" feature of the iPad. So, now I got my iPad Camera Connection Kit (CCK, as some people refer to it) and a 2GB SD card. I went over to my laptop, happily copied my favorite pictures to the SD card and inserted it into the SD Card connector on to the iPad. After a few seconds, the Photo application came up with a new Camera tab with a message "No photos to import". A bit baffled.

iPad not Recognizing Images

I triple-checked my SD card that the files were indeed there (underneath DCIM folder from the root) and they were readable by opening them off the card itself – no problems on that front but no luck yet. Confused enough, I deleted all the images on the card and copied a different set and repeated the procedure. To bring a little smile, this time iPad recognized some images on the card, but not all of them I copied. I went a step ahead and analyzed/compared the image properties (height, width, bit depth, file size, etc.) of the files recognized by iPad and those were not, but finally it hardly made any sense.

Frustrated enough I thought I would fool the iPad that the images were created by a camera by renaming the files on the card as DSC_NNNN.jpg where NNNN is a 0-padded number (almost all cameras save images in this file name format, numbering them sequentially) and inserted the card into the connector. WHOAAAAAAAAAAAAAAAA!!!!!!!!!! There you go!! iPad recognized all the images I copied without any fuss! Honestly, this file renaming thing occurred to me completely from nowhere and I never ever thought it would work.

Windows Explorer View

[iPad recognizes images named as per the standard naming convention - IMG_NNNN or DSC_NNNNN; ignores others.]

iPad Recognizes Properly Named Images

Sure, I know this is a Camera Connection Kit and it is intended to import stuff from a camera but isn’t too much to expect people to plug in their memory card hot out of the camera into the connector OR have dependencies on the file names!!

I usually name my pictures as descriptive as possible, just out of habit but never I would land in such a funny trouble one day!

 

I hops this helps someone.

Note-taking Application for iPad

I do a lot of scribbling/note taking and draw diagrams (how can a software Architect be without diagrams :-) ) while in meetings, reading technical books and so started looking for a decent note taking application for my new iPad. Honestly, there are many notes applications but not many satisfied my key requirements sufficiently: 1. Handwriting & 2. Free-form drawing. Many iPad notes applications support keyboard (onscreen) based typing but who will have the patience to type in notes in quick meetings or change your flow from reading to typing. After doing quite a bit of research I finally ended up with Notes Plus. Just awesome!! For me this is only next to Microsoft’s OneNote in terms of features and well worth the money. It has features much more than what I expected. If you use a stylus (iPad-compatible), then that completes it!

Notes Plus photo

Worth mentioning features are:

  • Palm Pad (grey area at the bottom in the above screenshot) – help you rest your palm on the touch surface for comfortable handwriting (palm pad area becomes insensitive to your palm touch)
  • Excellent drawing support (though not extensive, I can do my mind-mapping diagrams in quick & dirty way )
  • Integration with Google Docs
  • You can mix handwriting, voice recording, freehand drawing, keyboard typing to any extent – something I love in Microsoft’s OneNote also!

There is one big compliant however: if you do lot of complex drawings then later delete them, the application simply crashes! I think it is because it over-does drawing pattern recognition, handwriting manipulation, etc.

I only wish Microsoft had developed iPad version of its OneNote application, but I am well settled with Notes Plus now.

I highly recommend this iPad app for those who are looking for a ‘value-for-money’ notes app for iPad.

 

Note: I am just one among the satisfied users of Notes Plus application and no way connected to the company developed it.

Exposing Data via OData

In an earlier post I discussed what OData is all about and how you can consume OData services using plain HTTP requests. In this post I will talk about the other side of the story: exposing data using OData protocol.

With WCF Data Services (DS for short), providing data using OData is simple and easy too. Out of the box, DS can pull data in two ways and expose it as one or more feeds:

  1. ADO.NET Entity Framework – DS integrates with ADO.NET Entity Framework (EF) well and as such it can provide an OData layer on top of an existing EF model and expose data from the underlying relational database. In this way, each entity in the model may be given a unique URI by DS and exposed as a feed (in OData terms, Entity Set – collection of business entities). The advantage with this is that DS itself gives the plumbing for CRUD operations that you may want to perform on the entities exposed.
  2. Plain .NET classes – Lets you expose plain .NET classes as WCF Data Services. For example you can expose your plain-old-C#-class (POCO) libraries as OData feeds simply using DS. Behind the scenes, DS uses .NET reflection to detect IQueryable collections on a target class and exposes them as feeds. The advantage is that you have better control over the actual CRUD operations when invoked via HTTP. The downsides are many:
    1. Obviously, you have to write extra code to expose your object collection as IQueryable.
    2. DS supports only Select operation by default for this type of data source and Atom formatted output. If you want to provide Update, Delete and Insert operations as well on the feeds then you should implement IUpdatable interface.
    3. Only Atom-formatted results are supported. If you need JSON-formatted response, you have to again write more code.

Nevertheless, OData is platform neutral and as such WCF Data Services can provide data irrespective of its underlying physical storage or model. The above are just two options that come out of the box with WCF Data Services but you can expose data from anywhere: XML files, Excel data, file system, another data feed, etc. For this post, let me start with exposing POCO collection as OData feeds using DS because it is simple to implement (with Select operation alone).

The following code sample requires references to System.Data.Services.Client.dll and System.Data.Services.dll assemblies for WCF Data Services specific types.

Let us say we want to expose a feed for lawyer data. The following is a simple class to represent the lawyer data. In order for the DS to identify an object uniquely, we should specify which property of the class should be treated as the key using the attribute DataServiceKey:


[DataServiceKey ("LawyerID")]

public class LawyerInfo
{
    public int LawyerID {get; set;}
    public string Name {get; set;}
    public string OfficeCode {get; set;}
    public AddressInfo Address {get; set;}
}

The complex property AddressInfo is defined as follows:

[DataServiceKey ("AddressID")]
public class AddressInfo
{
    public int AddressID {get; set;}
    public string AddressLine {get; set;}
    public string City {get; set;}
    public string State {get; set;}
}

Now we need a container class to expose a collection of the above class as IQueryable; DS will at runtime perform reflection on this class to find properties of type IQueryable and expose them as feeds (the name of such properties will be the name of the feeds from the base service URI as we would see them later).


public class LawyerDataProvider
{
    private static List<LawyerInfo> _ds;
    public LawyerDataProvider ()
    {
        _ds = new List<LawyerInfo> ();
        _ds.Add (new LawyerInfo ()
        {
            LawyerID = 89,
            Name = "James Horner",
            OfficeCode = "NY921",
            Address = new AddressInfo ()
            {
                AddressID = 8,
                AddressLine = "100 Park Ave",
                City = "New York",
                State = "NY"
            }
        });
        _ds.Add (new LawyerInfo ()
        {
            LawyerID = 61,
            Name = "Mathew Perry",
            OfficeCode = "IL017",
            Address = new AddressInfo ()
            {
                AddressID = 15,
                AddressLine = "625 West Madison",
                City = "Chicago",
                State = "IL"
            }
        });
        _ds.Add (new LawyerInfo ()
        {
            LawyerID = 17,
            Name = "Samatha Mathis",
            OfficeCode = "NJJC",
            Address = new AddressInfo ()
            {
                AddressID = 35,
                AddressLine = "Journal Square",
                City = "Jersey City",
                State = "NJ"
            }
        });
    }

    public IQueryable<LawyerInfo> Lawyers
    {
        get {return _ds.AsQueryable<LawyerInfo>();}
    }
}

Given the above class, you get the lawyers list as returned by the Lawyer property using http://service_base_uri/Lawyers /Lawyers once the service is up and running.

The final step in creating the data service provider is to create a DataService instance (in loose terms, the Entity Framework’s ObjectContext counterpart in WCF Data Service) specifying the class that has the IQueryable properties:

public class LawyerDs : DataService<LawyerDataProvider>
{
    public static void InitializeService(DataServiceConfiguration config)
    {
        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
        config.SetEntitySetAccessRule ("Lawyers", EntitySetRights.All);
    }
}

SetEntitySetAccessRule method sets desired permissions for an entity set, in the above case Lawyers. For now, let give all the access rights for Lawyers.

Now, we have to host this service at a known URI location for consumption. Logically, this step is same as hosting a normal WCF service but for simplicity sake I am going to host the service using IIS. So, create an ASP.NET web application (at say, http://localhost/wapcs) and a new WCF Data Service item – Lawyers.svc:

Add WCF Data Service Item

This will create a class definition file (Lawyers.cs) underneath the web application’s App_Code folder and a corresponding Lawyers.svc file at the root. Assuming you put all the entity, entity set provider and data service classes in a single source file (say LawyerDsp.cs), remove the auto-created class definition file and modify the .svc file to point to the data service class as below:

<%@ ServiceHost Language="C#" Factory="System.Data.Services.DataServiceHostFactory" Service="LawyerDs" %>

If everything compiles without error, open up Internet Explorer and navigate to http://localhost/wapcs/lawyers.svc and the browser should display this:

Service Output

This basically indicates that our service exposes one feed called Lawyers at location Lawyers. The location is relative to the service base URI http://localhost/wapcs/Lawyers.svc. Now, go to http://localhost/wapcs/Lawyers.svc/Lawyers and you would get the LawyerInfo entity set (for display purpose, I have expanded only the first item):

Entity Set Collection

You can now request a single entity by specifying the key in the request URI as in http://localhost/wapcs/Lawyers.svc/Lawyers(17):

Single Entity

You can do association navigation to see the Address details of a lawyer: http://localhost/wapcs/Lawyers.svc/Lawyers(17)/Address

Navigation Property 

Having shown all HTTP request operations from a browser, doing the same programmatically is not any different from consuming a typical web service or a WCF service. From Visual Studio’s Service Explorer, simply add a service reference to the service base URI:

Add OData Ref

Visual Studio will automatically create the required proxy classes as usual and you can straightway get into the business.

DS Client Code

If everything goes right, the above code will produce the following console output:

DS Client Console

You can apply other query string options such as filtering ($filter), paging ($top, $skip), etc. on the feed to get the desired results.

That’s it.

I know I have not shown adding support for update, delete and insert options for this POCO-based data service provider but I will reserve it for a future post. The purpose of this post is to show you how easy it is to develop an OData service using WCF Data Services infrastructure.