Back to square one

I’m a “noob”. Thats basically the feeling these days as I’m playing around with XNA for WP7. But its fun and its easy. After years of doing enterprise development this is a nice change of gears; it lets me take a break from my every day routine of SharePoint and such.

I’ve always considered game development to be the place where I could fully let loose and enjoy some cutting edge code, but the industry is hard to get into – especially for beginners. WP7 changes that, of course, as it allows everyone with varied .NET backgrounds to join in on the fun.
Full XNA development puts alot on the plate what with shaders and such, but with WP7 you get an entry level introduction to game development (and yet you get to play with advanced concepts such as sensors and touch in an easy way). I’ve done some shader coding; just enough to understand that I’m actually happy XNA for WP7 doesnt support more than what is included (for now) because otherwise I’d charge that hill as well and for now I’m happy with enjoying the basics.

While XNA is a platform that provides a lot of help its still not the big babysitter like the other platforms I use every day. It gets you started with the fun stuff and hiding all the low level code which deals with the hardware etc. My first realization was that doing input management and control UI is something that you need to handle yourself. There is a certain measure of infrastructure code that you need to put in place before you get to play with the fun stuff; not like, for example, Silverlight where you can just draw a button and attach to a click event.
But its worth it because you gain a deeper understanding of what the babysitter platforms actually do for you and leaves you a better developer. I firmly believe its important for developers to know what a framework actually does for them.

XNA for WP7 (as that is what I work with at this moment) is just easy enough to do simple games and challenging enough so that I have something to pit my mind against when doing more advanced games.

Hopefully I’ll have some good ideas worth publishing on the Marketplace soon as my number one ambition, still and always, is to create something that people enjoy whether it be for entertainment or business.

In reality this isn’t back to square one because with my .NET backround WP7 development, be it Silverlight or XNA, is easy – just enjoy it, people.

Rewriting FullTextQuery within CoreResultsWebPart

Recently I found that SharePoint advanced search used query parts like Title like ‘%querystring%’ when dealing with contains operators. When dealing with documents that had long titles this didn’t yield the expected search results and with further testing I found that using CONTAINS(Title,’”querystring”’) gave me all the results I wanted.

Problem was that the advanced search was out-of-the-box and no way to configure this (as far as I know) so I needed a way to rewrite the FullTextQuery that was being generated by SharePoint without too much custom code and changing the behavior of the CoreResultsWebPart.

Enter: Reflection. I love this tool, but it should be used sparingly in large solutions as there is a performance hit.

Anyway, basically what I did was extend the CoreResultsWebPart and override the SetPropertiesOnHiddenObject method. This method initializes a private field within CoreResultsWebPart of the type SearchResultHiddenObject and this class contains the FullTextQuery propery which we want to modify at runtime.

So, here’s the quick and dirty code (should be cleaned up before production use):

private string queryPattern = @"(?<Title>Title[\w\s]+[^%]%(?<Query>[\w\s\d]+[^%]*)%')";

protected override void SetPropertiesOnHiddenObject() { base.SetPropertiesOnHiddenObject(); try { Type t = this.GetType(); FieldInfo hiddenObjectField = t.BaseType.GetField("srho", BindingFlags.NonPublic | BindingFlags.Instance); if (hiddenObjectField != null) { object hiddenObject = hiddenObjectField.GetValue(this); Type hiddenObjectType = hiddenObject.GetType(); PropertyInfo fullTextQuery = hiddenObjectType.GetProperty("FullTextQuery", BindingFlags.Public | BindingFlags.Instance); string query = fullTextQuery.GetValue(hiddenObject, null) as string; if (query != null) { Match m = Regex.Match(query, queryPattern); if (m.Success) { string queryString = m.Groups["Query"].Value; query = Regex.Replace(query, queryPattern, "CONTAINS(Title,'\"$2\"')", RegexOptions.IgnoreCase); fullTextQuery.SetValue(hiddenObject, query, null); } } } } catch (Exception ex) { HttpContext.Current.Response.Write("Error: " + ex); } }

‘As you can see I use a regular expression to match and replace the query, but you can replace this with however you wish to modify the query.


Replace the out-of-the-box CoreResultsWebPart with this webpart and you’ll retain all the normal functionality except you gain a little more power over the actual query that is used. This works perfectly on SharePoint 2007; I haven’t tested it on SharePoint 2010 and it might not be needed there.

Bring It update

I just submitted a new version of my shipment tracking application for Windows Phone 7 for testing and hopefully it will be available within a day or two. The big new feature is push notification where you’ll get status updates on your shipment (courtesy of my new Azure service that I mentioned in my previous post).

As I don’t have the means to do large scale testing it will be interesting to see how it holds up when users get the update and start using it.

permission

This feature brings with it the possibility to turn on and off push notification (as required by Microsoft) and for every shipment you wish to track you can specify the level of notification you wish to have. This is configured at the edit screen displayed below.

addpackagelevels

Tile update only specifies that only the number of updates available will be displayed on the tile itself (requires that the application is pinned to the start menu). The rest will send toast notifications.

Also, I added a little graphical update just to freshen up the UI a bit. This is also theme dependant like the rest of the application.

mainscreendetailsevents

 

Any feedback would be appreciated Smilefjes

Azure impressions

So, I decided to do something proper with my free Azure subscription (bundled with my MSDN account) and create a cloud service for my Windows Phone 7 application. It’s been a while since I worked with Azure and I was really impressed by the current version; the ease of deployment and online management.

The Silverlight management tools at http://windows.azure.com is very comfortable to work with and creating simple SQL Azure databases via a web browser is just, well, easy Smilefjes The Visual Studio 2010 Azure templates are equally great and gets you up and running within minutes.

In simple terms: Created a web service role for my WP7 application to talk to, used Entity Framework to connect to the Azure SQL database, created a worker role that (in this case) checks shipment statuses and sends push notifications back to the WP7 app and voila: Cloud-enabled appSmilefjes

The local debugging capabilities (Compute and Storage emulators) are all wired up for you and a quick F5 gets you going.

Basically, that’s my impressions for the current version of Azure and thus far I’m (obviously) pleased with itSmilefjes

SharePoint FBA & Reactive Extensions

Some of the dangers with new toys is to overuse them, I fear I might be doing that with reactive extensions but oh well.. It’s all about the learningSmile

Today I did a test to do Form Based Authentication with SharePoint using reactive extensions. This is the first attempt, it can probably be made more streamlined as I figure out more about Rx.

Oh, apologize for the syntax coloring in the code, I really need to find some better CSS for this…

I have two classes: One for doing the FBA (which also holds the cookie jar as we will get a cookie once the FBA is successful and need to pass this along to the next web service call) and one for doing web service calls.

public class FormsBasedAuthentication {
    public static CookieContainer CookieJar = new CookieContainer();
    private const string AuthEnvelope = @"<?xml version=""1.0"" encoding=""utf-8""?>
                <soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
                  <soap:Body>
                    <Login xmlns=""http://schemas.microsoft.com/sharepoint/soap/"">
                      <username>{0}</username>
                      <password>{1}</password>
                    </Login>
                  </soap:Body>
                </soap:Envelope>";

    public static IObservable<string> Authenticate(string server, string username, string password) {
        Uri authService = new Uri(string.Format("{0}/_vti_bin/authentication.asmx", server));
        HttpWebRequest authRequest = WebRequest.Create(authService) as HttpWebRequest;
        authRequest.CookieContainer = CookieJar;
        authRequest.Headers["SOAPAction"] = "http://schemas.microsoft.com/sharepoint/soap/Login";
        authRequest.ContentType = "text/xml; charset=utf-8";
        authRequest.Method = "POST";
        return (from request in Observable.FromAsyncPattern<Stream>(authRequest.BeginGetRequestStream, authRequest.EndGetRequestStream)().Do(stream => {
            UTF8Encoding encoding = new UTF8Encoding();
            string envelope = string.Format(AuthEnvelope, username, password);
            byte[] bytes = encoding.GetBytes(envelope);
            stream.Write(bytes, 0, bytes.Length);
            stream.Close();
        })
                from response in Observable.FromAsyncPattern<WebResponse>(authRequest.BeginGetResponse, authRequest.EndGetResponse)()
                select HandleResponse(response, authRequest));
    }

    private static string HandleResponse(WebResponse response, HttpWebRequest request) {
        var httpResponse = response as HttpWebResponse;
        if (httpResponse != null){
            var result = XDocument.Load(response.GetResponseStream());
            var code = result.Descendants(XName.Get("ErrorCode", "http://schemas.microsoft.com/sharepoint/soap/")).FirstOrDefault();
            if (code != null)
                return code.Value;
        }
        return "ErrorOccured";
    }

}

This will return an observable that will return the authentication result – if the login was successful, the published value will be NoError.

Next we have our web service class:

public class BaseWebService {
       private static string soapEnvelope =
           @"<soap:Envelope
                           xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
                           xmlns:xsd='http://www.w3.org/2001/XMLSchema'
                           xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>
                   <soap:Body>{0}</soap:Body></soap:Envelope>";

       private XDocument soapEnvelopeXml;
       public string BaseUrl { get; set; }
       #region Helper methods
       private XDocument CreateSoapEnvelope(string content) {
           var envelope = string.Format(soapEnvelope, content);
           XDocument soapEnvelopeXml = XDocument.Parse(envelope);

           return soapEnvelopeXml;
       }

       private HttpWebRequest CreateWebRequest(string url, string action) {
           Uri serviceUrl = new Uri(url, UriKind.Absolute);
           var webRequest = WebRequest.Create(serviceUrl) as HttpWebRequest;
           webRequest.Headers["SOAPAction"] = action;
           webRequest.ContentType = "text/xml;charset=\"utf-8\"";
           webRequest.Accept = "text/xml";
           webRequest.Method = "POST";
           webRequest.CookieContainer = FormsBasedAuthentication.CookieJar;
           return webRequest;
       }
       #endregion

       public IObservable<XDocument> CallService<T>(string url, string action, string soapContent) {
           soapEnvelopeXml = CreateSoapEnvelope(soapContent);
           HttpWebRequest webRequest = CreateWebRequest(url, action);
           var call = (from request in Observable.FromAsyncPattern<Stream>(webRequest.BeginGetRequestStream, webRequest.EndGetRequestStream)().Do(stream => {
                                                                                                                                                       soapEnvelopeXml.Save(stream);
                                                                                                                                                       stream.Close();
                                                                                                                                                   })
                       from response in Observable.FromAsyncPattern<WebResponse>(webRequest.BeginGetResponse, webRequest.EndGetResponse)()
                       select Handle(response));
           return call;
       }
       private XDocument Handle(WebResponse response){
           var doc = XDocument.Load(response.GetResponseStream());
           return doc;
       }
   }

This produces an observable which will publish a XDocument with the result of the web service call. As you can see, we are using our cookie jar from the FBA class (see the CreateWebRequest method) so that our authentication token gets passed along.

To put this together and do an authenticated call to the Lists.asmx web service in SharePoint, we need two small methods.

private static void GetList(string authStatus){
            if (authStatus == "NoError"){
                BaseWebService webService = new BaseWebService();
                webService.CallService<XDocument>(“<url>/_vti_bin/Lists.asmx”, ActionGetList, string.Format(SoapGetList, "Pages")).Subscribe(Handle);
            }
        }

This method gets the published value from the FBA class and checks that we can proceed with our next call.

Oh, must not forget the SoapAction and content of the envelope:

private const string ActionGetList = "http://schemas.microsoft.com/sharepoint/soap/GetList";
private const string SoapGetList = @"<GetList xmlns='http://schemas.microsoft.com/sharepoint/soap/' xmlns:i='http://www.w3.org/2001/XMLSchema-instance'><listName>{0}</listName></GetList>";

 

private static void Handle(XDocument doc){
            Console.WriteLine(doc.ToString());
        }

And this one handles the result from the call to Lists.asmx (not doing much at this point).

So, to start it all off, we need to get our FBA observable set up:

var auth = FormsBasedAuthentication.Authenticate("<url to sharepoint site>", "<user>", "<password>");

Next we start it off:

auth.Do(GetList).Start();

What this does is that our FBA observable will call GetList for every published value that the FBA observable gives us (which should be just one) and to fire the entire process off we turn the ignition and .Start() Smile

This is all then done asynchronously.

Getting controls from inside a DataTemplate

Today I had to access a control which resided inside a DataTemplate used by a PivotItem (WP7) and there’s no straight forward way to do this as far as I know.

Thing is that pivotControl.Items[idx] returns the databound item and pivotControl.ItemContainerGenerator.ContainerFromItem(item) yields a PivotItem. But I figured that pivotItem.Content would contain the controls defined in the DataTemplate – wrong, it gives back the databound item.

So, my next try was to use the pivotItem.ContentTemplate.LoadContent() which actually did give me my controls – but LoadContent() actually creates a new object and doesn’t give you the reference to the actual live object on your screen.

Of course, the solution is rather simple if you can just think of it right off the batWinking smile

First, get the container:

DependencyObject container = pivotControl.ItemContainerGenerator.ContainerFromItem(item);

Then we use the VisualTreeHelper to take a walk around and find the control we want (by name).

var details = container.GetChild<Detail>("details");

This is all possible with this little extension method:

public static T GetChild<T>(this DependencyObject parent, string name) where T:DependencyObject{
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) {
                DependencyObject child = VisualTreeHelper.GetChild(parent, i);

                if (child.GetType() == typeof(T) && ((FrameworkElement)child).Name == name)
                    return (T)child;

                if (child.GetChild<T>(name) != null)

                    return child.GetChild<T>(name);
            }
            return null;
        }

If there’s a simpler solution to this, please let me knowSmile

Bring It preview

Just a quick little preview of my package tracking app. Added a little fun gimmick where you can see where the last transport event took place using Bing maps. Still some styling left to do and get it all prettified, but it’s starting to come together.

http://player.vimeo.com/video/16043460

Bring It Preview from Frode Hus on Vimeo.

Follow

Get every new post delivered to your Inbox.