SharePhone continues on

Just wanted to inform that I’ll be adding Forms Based Authentication as well as Basic Authentication modes as options in SharePhone so that the library can be used for those that has these kinds of authentication methods configured for their SharePoint sites.

Advertisements

WP7 API disappointment…

So, as I wrote in earlier posts (and resulted in a CodePlex project), it was possible to circumvent WebClient’s lack of support for Windows Authentication by using HttpWebRequest.
While using the latest SDK refresh and developing my SharePoint WP7 app, I found that I could no longer access SharePoint (the connection failed with a NotFound error).

After trying to research this and find yet another workaround, I turned to the WP7 forums and the answer was that Windows Authentication is not supported (which I already knew, but thought I had a workaround for) and that the emulator sometimes might trick you into thinking it works as it uses your desktop as a proxy.

So basically, unless someone figures out something, the previous workaround only worked because the emulator was yanking your chain.

So my work on this is put on hold for the time being, maybe Microsoft will update this functionality when/if they gear WP7 towards the enterprise.

Addendum: If you’re willing to enable Basic authentication on your SharePoint site, that will work by setting the Authorization header yourself. Of course, it’ll all be sent in clear text unless sent over https.

User profiles and search in SharePhone

So, version 1.0.3 is out and contains a couple of new features.

User profiles

ClientContext now offers two methods for dealing with user profiles, GetUserProfile and UpdateUserProfile.

Here’s a quick example of their usage:

 

ctx.GetUserProfile(@"sharepointdev\testuser", (UserProfile profile) => {
    profile.Title = "Test user";
    ctx.UpdateUserProfile(profile, null);
});

The UserProfile class only contains a couple of quick access properties so far, to access all of them you need to access the Properties property and read your values there. Here’s an example how:

from property in profile.Properties where property.Name == "PreferredName" select property

You can also use a simple utility method when you want to update a property:

profile.UpdateSingleValueProperty("PreferredName", "Santa");

Keep in mind that updating a user profile is subject to access restrictions set by the site administrator (some properties can only be updated by administrator, others by the owner of the profile).

Search

Again, the ClientContext class has been expanded to include some search functionality. This is the built-in SharePoint search (not sure how this will work with FAST in SharePoint 2010).

ctx.SearchProvider.KeywordSearch("Test", (SearchResult result) => {
    int numberOfHits = result.TotalAvailable;
    //access the hits via result.Results
});

You can also do advanced search via the Search(..) method and the QueryPacket class.

QueryPacket query = new QueryPacket();
query.EnableStemming = true;
query.QueryType = QueryType.MSSQLFT;
query.Query = "select * from Scope() where FREETEXT('test')";
ctx.SearchProvider.Search(query, (SearchResult result) => { });

Reading/writing list items using SharePhone

Ok, so, a quick example how to load in all items in a list and update a property, then save it back to SharePoint:

list.Items.ItemsLoaded += (object se, EventArgs ev) => {
    BaseItem item = list.Items[0];
    item.Title = "NewTitle";
    item.Update();
    list.Items.Update((object obj, EventArgs ea) => {
        
    });
};
list.Items.LoadAllItems();

There’s a few things going on here. As this works asynchronously, we add a event handler which will run when the items have been loaded into the list then we take the first item and updates the title before saving it back.

Whenever updating an item, be sure to call Update() on the item afterwards to tag it for updating. This is yet again a way to ensure that only required data is transferred, hopefully making the payload smaller. When all updates are ready, call the Update() method on the item collection (list.Items.Update(.. )).

The latter update method requires a callback delegate which will be called when the update is complete – this may change in future releases.

Remember, these properties can be databound to your WP7 controls.

If you don’t want to load the entire item collection, you can specify which items you want loaded using a CAML query.

CamlExpression titleQuery = ExpressionFactory.CreateExpression("Title", SharePhone.Query.Expression.FieldType.Text, SharePhone.Query.Expression.Operator.Eq, "NewTitle");
list.GetItemsByQuery(titleQuery, 0, (BaseItemList<BaseItem> items) => {
    if (items.Count > 0) {
        //query successfull
    }
});

The CAML builder classes in SharePhone lets you build queries rather easily, like for example using JOINs:

CamlExpression titleQuery = ExpressionFactory.CreateExpression("Title", SharePhone.Query.Expression.FieldType.Text, SharePhone.Query.Expression.Operator.Eq, "NewTitle");
CamlExpression dateFilter = ExpressionFactory.CreateExpression("PublishedDate", SharePhone.Query.Expression.FieldType.DateTimeWithTimeIncluded, SharePhone.Query.Expression.Operator.Geq, DateTime.Now);
CamlExpression query = ExpressionFactory.JoinExpression(SharePhone.Query.Expression.Conjunction.And, new CamlExpression[] { titleQuery, dateFilter });
list.GetItemsByQuery(query, 0, (BaseItemList<BaseItem> items) => {
    if (items.Count > 0) {
        //query successfull
    }
});

Strong typed list item classes in SharePhone

Usually when dealing with SharePoint through its object model, you get a SPListItem object which can be annoying to work with, especially when you want to databind in Silverlight. This is why I went for a strong typed version in SharePhone and hopefully it will be easier to use for non-SharePoint developers or those just starting out with SharePoint.

A SharePhone list item starts with the BaseItem class. When creating your own classes, you need to extend BaseItem. This class contains basic list item properties which are standard for all SharePoint list items (such as Title, Name, Created date, modified date, author, etc). If you only want to work with these basic properties, then you can use BaseItem as is and not implement your own class.

Let’s say you’ve created a content type which contains the text field MyField.

Create a new class, let’s call it MyContentType:

public class MyContentType : BaseItem{

}

Then we add our MyField property:

public class MyContentType : BaseItem{
    public string MyField { get; set; }
}

However, for SharePhone to know how to map this property to fields in your SharePoint list, you need to tag the property with some information.

public class MyContentType : BaseItem{
    [CoreField(FieldName="MyFieldName", Importance=FieldImportance.Optional, PopulateRule=CorePopulateRule.Sharepoint)]
    public string MyField { get; set; }
}

The CoreField attribute tells the SharePhone library a few key pieces of information:

  • FieldName specifies the internal name of the field in SharePoint
  • Importance is either Optional or Required, specifying whether or not the field requires a value or not.
  • PopulateRule states how the property should be treated

    SharePoint says the value of the property comes from SharePoint and allows for saving the value back.

    SharePointReadOnly says the value should be read from SharePoint but never written back.

    None states that this property should be ignored when reading/writing to SharePoint.

As BaseItem implements INotifyPropertyChanged, you can also support this in your custom properties like so:

private string myField;
[CoreField(FieldName = "MyFieldName", Importance = FieldImportance.Optional, PopulateRule = CorePopulateRule.Sharepoint)]
public string MyField {
    get {
        return myField;
    }
    set {
        myField = value;
        OnPropertyChanged("MyField");
    }
}

(I had a transparent way of dealing with this before so that custom properties would automagically support this, but due to WP7 lacking the System.Reflection.Emit namespace, I had to remove this feature – hopefully I can add it back in at some point).

Now, to use our new class, we make use of our generic methods in SharePhone:

web.Lists.GetListByName<MyContentType>("TestList", (SPList<MyContentType> list) => {
    string myText = list.Items[0].MyField; 
});

Remember, to get the items you first need to load them into the collection using list.Items.LoadAllItems();

I was going to show an example of reading and writing data from/to SharePoint but I’ll save that for the next post so this one doesn’t turn into a lengthy read.

SharePhone

Today I released a basic version of SharePhone, my WP7 library for working with SharePoint sites. Binaries and source code can be found here: Codeplex

I’m currently porting this code from a more functional Silverlight project so I apologize if the source is a bit messy.

Anyway, the current release lets you open up any SharePoint 2007/2010 web and its sub webs and work with their lists and list items.

Here’s a short example how:

First we instantiate our context and supply the URL for the root web.

ClientContext ctx = new ClientContext("http://sharepointdev");
//supply credentials if needed
ctx.Settings.Credentials = new CredentialSettings { Domain = "<domain>", UserName = "<user>", Password = "<password>" };

Then we get our root web object (remember, Silverlight requires any web service call to be made asynchronously which is why this is the only method available in this library).

ctx.GetRootWeb((object s, SPWebLoadCompletedEventArgs result) => {
    SPWeb rootWeb = result.Webs[0];               
});

Next, let’s load all the lists available at the root web:

web.Lists.LoadCompleted += (object sender, SPListLoadCompletedEventArgs e) => {
    Deployment.Current.Dispatcher.BeginInvoke(() => {
        list1.ItemsSource = e.Lists;
    });
};
web.Lists.LoadAll();

list1 is a ListBox and it’s defined like this in XAML:

            <ListBox Name="list1">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Title}" Style="{StaticResource PhoneTextNormalStyle}"/>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>

And we have our lists neatly listed out on our phone, ready to continue working with them. sample

Most of the operations on collections, such as sub webs on a web or lists or even list items in a list requires you first to load the collection like in the previous example (web.Lists.LoadAll()). The reason why I don’t load this data on first call is because I want to keep the data traffic at a minimum. Basically you load what you need and nothing more.

Next post I’ll show an example how to read list items, update the data and post them back to SharePoint using strong typed custom classes.