Automattic’s Worldwide WordPress 5K – 2012

This year I’ve started to run. To guide me I purchased the Nike+ sensor + receiver. These are great for running on a treadmill. After a little while I bought the Nike+ GPS app and started to run on the road. A world of difference compared to indoor running.

Nike+ Maps of my WWWP5K 2012 When I got the tweet from @wordpressdotcom about the Automattic’s Worldwide WP 5K, I decided to post this. As a Nike+ member my 5K are registered on
Nike+ Mapes. Actually I ran over 11K to have a little slack and to help out others that could not complete the 5K (have some of mine 😉 )

To add something extra to this run I used iTimeLapse to record some shots every 1K I ran. The resulting video is below:

Posted in Uncategorized | Tagged , , , , , | 2 Comments

Video Mirroring IOS Apps with MonoTouch

ipad vga adapterFor an on-stage demo of an iPad app I needed to build in video mirroring. Luckily I found this code and everything worked within 10 minutes, waiting for compile – package – deploy took that long 😉

This code is not mine. Original post on sharpthoughts.

public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
    // other code you need here

    // start monitoring for adapter and output when connected
    IPadClient.Controls.TvOutManager.SharedInstance().StartTvOut();
    return true;
}

TvOutManager sourcecode on https://gist.github.com/819268 and clone below (click to unfold)

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using MonoTouch.CoreGraphics;
using MonoTouch.Foundation;
using MonoTouch.ObjCRuntime;
using MonoTouch.UIKit;

namespace IPadClient.Controls {
    public class TvOutManager : NSObject {
        private static TvOutManager sharedInstance;
        UIWindow deviceWindow;
        private UIWindow tvoutWindow;
        NSTimer updateTimer;
        UIImage image;
        UIImageView mirrorView;
        bool done;
        bool tvSafeMode;
        CGAffineTransform startingTransform;
        private int kFPS = 15;
        private bool kUseBackgroundThread = true;
        public bool UsePrivateAPI = false;
        

        public static TvOutManager SharedInstance() {
            if (sharedInstance == null) {
                sharedInstance = new TvOutManager();
            }
            return sharedInstance;
        }

        public TvOutManager()
            : base() {
            NSNotificationCenter.DefaultCenter.RemoveObserver(this);

            NSNotificationCenter.DefaultCenter.AddObserver(this, new Selector("ScreenDidConnectNotification:"), "UIScreenDidConnectNotification", null);
            NSNotificationCenter.DefaultCenter.AddObserver(this, new Selector("ScreenDidDisconnectNotification:"), "UIScreenDidDisconnectNotification ", null);
            NSNotificationCenter.DefaultCenter.AddObserver(this, new Selector("ScreenModeDidChangeNotification:"), "UIScreenModeDidChangeNotification ", null);

            UIDevice.CurrentDevice.BeginGeneratingDeviceOrientationNotifications();
            NSNotificationCenter.DefaultCenter.AddObserver(this, new Selector("DeviceOrientationDidChange:"),
                                                           "UIDeviceOrientationDidChangeNotification", null);
        }

        public void SetTvSafeMode(bool val) {
            if (tvoutWindow != null) {
                if (tvSafeMode && val == false) {
                    UIView.BeginAnimations("zoomIn");
                    tvoutWindow.Transform = CGAffineTransform.MakeScale(1.25f, 1.25f);
                    UIView.CommitAnimations();
                    tvoutWindow.SetNeedsDisplay();
                } else if (tvSafeMode == false && val == true) {
                    UIView.BeginAnimations("zoomOut");
                    tvoutWindow.Transform = CGAffineTransform.MakeScale(.8f, .8f);
                    UIView.CommitAnimations();
                    tvoutWindow.SetNeedsDisplay();
                }
            }
            tvSafeMode = val;
        }

        public void StartTvOut() {
            if (UIApplication.SharedApplication.KeyWindow == null)
                return;

            var screens = UIScreen.Screens;
            if (screens.Count() <= 1) {
                Console.WriteLine("TVOutManager: startTVOut failed (no external screens detected)");
                return;
            }

            if (tvoutWindow != null)
                tvoutWindow.Dispose();
                tvoutWindow = null;

            if (tvoutWindow == null) {
                deviceWindow = UIApplication.SharedApplication.KeyWindow;

                SizeF max = new SizeF();
                max.Width = 0;
                max.Height = 0;
                UIScreenMode maxScreenMode = null;
                UIScreen external = UIScreen.Screens[1];


                for (int i = 0; i < external.AvailableModes.Count(); i++) {

                    UIScreenMode current = UIScreen.Screens[1].AvailableModes[i];
                    if (current.Size.Width > max.Width) {
                        max = current.Size;
                        maxScreenMode = current;
                    }
                }

                external.CurrentMode = maxScreenMode;
                tvoutWindow = new UIWindow(new RectangleF(0, 0, max.Width, max.Height));
                tvoutWindow.UserInteractionEnabled = false;
                tvoutWindow.Screen = external;

                // size the mirrorView to expand to fit the external screen
                var mirrorRect = UIScreen.MainScreen.Bounds;
                var horiz = max.Width / mirrorRect.Width;
                var vert = max.Height / mirrorRect.Height;

                var bigScale = horiz < vert ? horiz : vert;
                mirrorRect = new RectangleF(mirrorRect.X, mirrorRect.Y, mirrorRect.Size.Width * bigScale, mirrorRect.Size.Height * bigScale);

                mirrorView = new UIImageView(mirrorRect);
                mirrorView.Center = tvoutWindow.Center;

                // TV safe area -- scale the window by 20% -- for composite / component, not needed for VGA output
                if (tvSafeMode) tvoutWindow.Transform = CGAffineTransform.MakeScale(.8f, .8f);
                tvoutWindow.AddSubview(mirrorView);
                tvoutWindow.MakeKeyAndVisible();
                tvoutWindow.Hidden = false;
                tvoutWindow.BackgroundColor = UIColor.DarkGray;
                
                //orient the view properly
                if (UIDevice.CurrentDevice.Orientation == UIDeviceOrientation.LandscapeLeft) {
                    mirrorView.Transform = CGAffineTransform.MakeRotation((float)Math.PI * 1.5f);
                } else if (UIDevice.CurrentDevice.Orientation == UIDeviceOrientation.LandscapeRight) {
                    mirrorView.Transform = CGAffineTransform.MakeRotation((float)Math.PI * -1.5f);
                }

                startingTransform = mirrorView.Transform;
                deviceWindow.MakeKeyAndVisible();
                this.UpdateTvOut();

                if (kUseBackgroundThread){
                    new Thread(UpdateLoop).Start();
                    }
                else{
                    updateTimer = NSTimer.CreateScheduledTimer(1.0/kFPS,this,new Selector("UpdateTvOut:"),null, true );
                }
                

            }
        }

        public void StopTvOut(){
            done = true;
            if (updateTimer != null){
                updateTimer.Invalidate();
                updateTimer.Dispose();
                updateTimer = null;
            }
            if (tvoutWindow != null){
                tvoutWindow.Dispose();
                tvoutWindow = null;
                mirrorView = null;
            }
        }
        [Export("UpdateTvOut:")]
        public void UpdateTvOut(){
            // UIGetScreenImage() is no longer allowed in shipping apps, see https://devforums.apple.com/thread/61338
            // however, it's better for demos, since it includes the status bar and captures animated transitions

            if (UsePrivateAPI){
                CGImage cgScreen = UIGetScreenImage();
                if (cgScreen != null){
                    var sImage = UIImage.FromImage(cgScreen);
                    mirrorView.Image = sImage;
                    cgScreen.Dispose();
                }
            }
            else{

                UIGraphics.BeginImageContext(deviceWindow.Bounds.Size);
                var context = UIGraphics.GetCurrentContext();

                foreach (var window in UIApplication.SharedApplication.Windows) {
                    if ((!window.RespondsToSelector(new Selector("screen"))) || (window.Screen == UIScreen.MainScreen)) {
                        context.SaveState();
                        context.TranslateCTM(window.Center.X, window.Center.Y);
                        context.ConcatCTM(window.Transform);
                        context.TranslateCTM(-window.Bounds.Size.Width * window.Layer.AnchorPoint.X, -window.Bounds.Size.Height * window.Layer.AnchorPoint.Y);
                        window.Layer.RenderInContext(context);
                        context.RestoreState();
                    }
                }
                image = UIGraphics.GetImageFromCurrentImageContext();
                UIGraphics.EndImageContext();
                mirrorView.Image = image;
            }
        }

        private CGImage UIGetScreenImage(){
            return CGImage.ScreenImage;
        }

        [Export("UpdateLoop:")]
        public void UpdateLoop(){
            using (NSAutoreleasePool pool = new NSAutoreleasePool()){
                done = false;

                while (!done){
                    this.InvokeOnMainThread(UpdateTvOut);
                    Thread.Sleep(67);
                }
            }
        }

        [Export("ScreenDidConnectNotification:")]
        public void ScreenDidConnectNotification(NSNotification notification){
            Console.WriteLine("Screen Connected: " + notification.Object);
            this.StartTvOut();
        }

        [Export("ScreenDidDisconnectNotification:")]
        public void ScreenDidDisconnectNotification(NSNotification notification) {
            Console.WriteLine("Screen disconnected: " + notification.Object);
            this.StopTvOut();
        }

        [Export("ScreenModeDidChangeNotification:")]
        public void ScreenModeDidChangeNotification(NSNotification notification) {
            Console.WriteLine("Screen mode changed: " + notification.Object);
            this.StartTvOut();
        }

        [Export("DeviceOrientationDidChange:")]
        public void DeviceOrientationDidChange(NSNotification notification){
            if (mirrorView == null || done == true)
                return;

            if (UIDevice.CurrentDevice.Orientation == UIDeviceOrientation.LandscapeLeft){
                UIView.BeginAnimations("turnLeft");
                mirrorView.Transform = CGAffineTransform.MakeRotation((float)Math.PI * 1.5f);
                UIView.CommitAnimations();
            }else if (UIDevice.CurrentDevice.Orientation == UIDeviceOrientation.LandscapeRight){
                UIView.BeginAnimations("turnRight");
                mirrorView.Transform = CGAffineTransform.MakeRotation((float)Math.PI * -1.5f);
                UIView.CommitAnimations();
            }else{
                UIView.BeginAnimations("turnUp");
                mirrorView.Transform = CGAffineTransform.MakeIdentity();
                UIView.CommitAnimations();
            }
            
        }
    }
}
Posted in Development | Tagged , , , , , , , | Leave a comment

Microsoft Web Camp

Web Camp
Microsoft uses (boot)camps to promote new products. The website devcamps.ms contains the curriculum. At the writing of this post there is Windows Phone, Windows Azure, Web and Windows. It’s free so I registered for the Web Camp and signed up for the accessibility and Webmatrix hands-on-labs. Turns out I wasn’t alone.

The keynote was done by Kris van der Mast, a Microsoft MVP and Azug.be board member. He talked about Webmatrix, Web API and HTML5. He gave some usefull tips and demo’s and even shed some light on SignalR.

After the lunch the hands-on-laps started.

My first lab was about accessibility. Turned out Jeroen Hulscher gave the same presentation as on Devdays 2011. But he updated the “undress-my-site” bookmarklet and someone in the audience gave the tip of using Fangs when developing for the screenreader.

The last lab was with Webmatrix. Never used it before, but the demo looked promising. Marcel Nieuwpoort created a WordPress site from scratch and changed the theme. Updating sites like WordPress could be difficult when using plugins and the data in the database will be erased, be sure to backup before you go there! The hands-on-lab failed with the message “This type of page is not served”. At the end I figured it out: open the folder containing the index.html, not the topmost with all the demos in subfolders. I my case I had to open “C:\WebCampsTrainingKit\Demos\WebMatrix – Part 1\Source\Code\DatabaseWithData”. Just a small tip 🙂
The razor syntax is very nice for quick website developement. Go check it out!

Download WebMatrix
Browse or Download trainingskit.

Server Error in ‘/’ Application.
——————————————————————————–

This type of page is not served.
Description: The type of page you have requested is not served because it has been explicitly forbidden. The extension ‘.cshtml’ may be incorrect. Please review the URL below and make sure that it is spelled correctly.

Requested URL: /Code/Page.cshtml

——————————————————————————–
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.272

Posted in Conference, Development | Tagged , , , , , , , , , | Leave a comment

DataContract weird characters and Mono

My solution will run on dotNET and Mono in a variety of mixes. Connecting the pieces of the Service Oriented Architecture design using WCF. Testing some setups showed me
another difference between dotNET and Mono. The returntype of an operation is Generic Dictionary with a string and a custom type. Would we have used standard System types this would not have been a problem.

I’ll demonstrate this by using a small service that returns authors and books. See code below. The client will receive the information and display the number of items in the result (and some other details). Implementation in the sample project at the end of my post.

[ServiceContract(Namespace = "http://my.solution/2012/04")]
public interface IBookService
{
    [OperationContract]
    Dictionary<string, BookData> GetOneBookPerAuthor();
}

[DataContract(Namespace = "http://my.solution/2012/04")]
public class BookData
{
    [DataMember]
    public string Title { get; set; }

    [DataMember]
    public int Id { get; set; }
}

Depending on the framework (dotNET or Mono) the results differ:

Service Client Result
.NET .NET 2 items
.NET Mono 2 items
Mono Mono 2 items
Mono .NET 0 items

The problem is in the serialization of datacontracts. Where Mono uses the same name as the class for the intermediate type: KeyValueOfstringBookData the dotNET framework does it a little different: KeyValueOfstringBookData6LZ3tCpf (notice the weird stuff at the end). This post on mono-for-android forum of Ximian shed some light.

My solution is to alter the message before it is send to the client when the service is hosted in Mono. For this I’ll use the IDispatchMessageInspector from WCF. In the BeforeSendReply method the KeyValueOfStringBookData tag is replaced with KeyValueOfstringBookData6LZ3tCpf.

public void BeforeSendReply(ref Message message, object instance)
{
    // get the message body
    var bodyReader = message.GetReaderAtBodyContents();
    bodyReader.Read();
    // replace to get the weird characters needed for dotNET clients
    var msg = bodyReader.ReadOuterXml().Replace("KeyValueOfstringBookData>", "KeyValueOfstringBookData6LZ3tCpf>");
    // construct the new message
    var stringreader = new StringReader(msg);
    var xmlreader = XmlReader.Create(stringreader);
    var xmldictionaryreader = XmlDictionaryReader.CreateDictionaryReader(xmlreader);
    var replacedMessage = Message.CreateMessage(message.Version, null, xmldictionaryreader);
    replacedMessage.Headers.CopyHeadersFrom(message.Headers);
    replacedMessage.Properties.CopyProperties(message.Properties);
    // set the new message as THE message
    message = replacedMessage;
}

To find the weird characters for your implementation, host the service in dotNET and request the WSDL. You’ll propably need to dig a little deeper by requesting the ?xsd=xsd0-9 stuff but the information is there


sample project

Posted in Development | Tagged , , , , , , , , , , , , | Leave a comment

BasicHttpBinding blocking under Mono

Hosting services in Mono using the BasicHttpBinding will block incomming requests until the previous request is handled. In dotNET this is not the case. Another difference between dotNET and Mono.

I’ll demonstrate this by using a self calling service. See code below. The service will call itself when some other value than 99 is submitted.

class Program
{
    static void Main(string[] args)
    {
        // host the service
        var host = new ServiceHost(typeof(SelfService));
        host.AddServiceEndpoint(typeof(ISelfService), 
                new BasicHttpBinding(), 
                "http://localhost:666/SelfService");
        host.Open();
        try
        {
            // Subsequal calls will be blocked until this call is ready
            var result = SelfServiceProxy.CreateDefault().CallMe(0);
            Console.WriteLine(result);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Main thread exception");
        }
        Console.ReadLine();
        host.Close();
    }
}

[ServiceContract]
public interface ISelfService
{
    [OperationContract]
    string CallMe(int value);
}

// serviceimplementation
public class SelfService : ISelfService
{
    public string CallMe(int value)
    {
        if (value == 99) return "Hello recursive";
        // recursive call with the correct value (will be blocked on BasicHttpBinding under Mono)
        else return SelfServiceProxy.CreateDefault().CallMe(99);
    }
}

Running this in dotNET will result in the text “Hello recursive” in the console. In Mono the execution takes a long time and eventualy prints the “Main thread exception” from the catch-block. Inspecting the exception shows it’s a System.TimeoutException.

What’s happening? The main thread proxy will call the CallMe operation with value = 0. The service will try to call itself with value = 99, the channel is opened and the request is made, but the execution is blocked by the first call (the main thread) Now whe have a deadlock, everybody is waiting for the service to complete but it can’t. Eventually the default timeout of 1 minute kicks in and the main thread gets an exception. The blocked recursive call from the service (value=99) actually gets executed, but the calling code is no longer there.

The only real solution to this problem is to use some other binding (like net.tcp) that doesn’t use the HttpListener. Or to use another address for each subsequal call but then you’ll need to know the number of subsequal requests. In my sample project I will also show the use of OperationTimeout to make the recursive call fail before the main thread fails. To set the OperationTimeOut in Mono you should hack a little bit in your proxy, see code below

public class SelfServiceProxy : ClientBase<ISelfService>, ISelfService
{
    public SelfServiceProxy(Binding binding, EndpointAddress address) : base(binding, address){}
    public static SelfServiceProxy CreateShortTimeout()
    {
        var address = new EndpointAddress("http://localhost:666/SelfService");
        var binding = new BasicHttpBinding() { ReceiveTimeout = TimeSpan.FromSeconds(4) };
        var result = new SelfServiceProxy(binding, address);
        // timeout should be set by binding ReceiveTimeout, but manual set is needed
        result.InnerChannel.OperationTimeout = TimeSpan.FromSeconds(4);
        return result;
    }    
}

The idea of setting the OperationTimeout is to use a shorter timeout for the subsequal calls than for the main thread proxy. That way the main thread will continue without an exception.

Posted in Development | Tagged , , , , , | 2 Comments