Performance is the area that we probably spend the most time on in all our apps. Building apps on the phone is just way different than building desktop apps. Things that might be really minor optimizations on a desktop Silverlight can really make a difference on desktop Silverlight apps.
Developing on the phone is an issue of economics where processing power is a scarce resource. You have to be conscious of the tradeoffs of using things like binding, layout controls, dependency injection, etc with their impact on performance. When I first started building phone apps I was excited to use nRoute and it’s nice features around MVVM/Resource Location/Messaging/Navigation. I wanted to have this really perfect loosely coupled architecture that used biding for everything/minimal code behind, had great designer support and dynamically resolved the proper services and models. In practice, that is not generally high performance code on the phone. If you are using some extra frameworks, really be conscious of the impact on performance and decide if you really need that architecture. What might work wonderfully on a more complicated desktop line of business app might not work as well on the phone. You just have to expect to write more optimization in a mobile app regardless if it’s the iphone, wp7 or android.
Silverlight was billed as “same Silverlight, just on the phone”. That is mostly true in terms of the api, but not necessarily true in terms of the actual runtime. It’s really a brand new runtime based on Silverlight 3 with some extra features added, so certain pieces of code might not have the same performance characteristics.
I’ve seen a lot of articles from various other people that talk about “buttery smooth scrolling” and other performance tips. At times the tips are a little too generalized. When you try to optimize something for performance on the phone, you really need to take into account your specific circumstances and find the right combination that works for your app. Always test and benchmark. Some things are more difficult to measure without real profiling tools,but do the best you can. Also be aware that scrolling in 3rd party apps on the phone is just not great at the moment. The native OS apps use a different UI framework that is going to make all but the simplest 3rd party apps feel sluggish so don’t feel too bad if your app scrolling seems slower. It’s probably not entirely your fault. Although this guy (around 8:50) seems to disagree. Sure 3rd party apps will get better with more experience and time,but the runtime needs to also get better. It’s the v1 of a new platform for everyone.
Finally, most of my thought are based around apps like twitter or facebook or other apps that require lots of live network data and have more complicated/longer list based screens. A 2 screen unit converter app is just going to be faster because it’s a simpler app and you don’t really need to optimize much.
So here are some things that you can try think about for your application:
I posted a few methods for doing page transitions in the past that were based on some older versions of the SDK and don’t work anymore. In the post I’ll go over another method which uses a base page to handle all transitions.
[Download Sample]
Before going into the code, here are some thoughts I have on page transitions and animations on the phone in general:
- Animations are a key part of the metro experience. With the focus on text and minimal chrome it’s important to add animations to make the UI have some life. They also “surprise and delight the user” as the Metro marketing material would say.
- Aside from the visual wonder created by animations, they also server some other purposes:
- The type of transition conveys meaning: The continuum animations provide context when drilling into a detail screen or task, sliding animations signify the creation of something new, etc. Matching the way the OS does transitions makes your app seem intuitive and it can conveys ideas without taking up the limited space on a mobile device.
- Transitions can improve perceived responsiveness of the application
- Don’t over -animate.
- Avoid long, gratuitous animations just because you can easily create storyboards in xaml. The native apps use some well thought out, subtle animations so try to follow that example for UX consistency. The timings on the native animations are fairly short – usually less than 350 ms. If you have much longer animations you are probably doing something that is going to look weird and make the app seem slow (some exceptions are the pano slide in animation which is around 1 – 1.5 seconds and the feather might have a longer total duration depending on the amount of items that feather in/out).
- Animations should enhance the user’s experience, not become distracting or annoying.
- If something needs to rotate out like a turnstile, you don’t actually have to rotate a full 90 degrees. You can just rotate partially and then change the opacity to 0. Your mind will fill in the missing part of the animation. Cutting the amount of time actually animating frees the phone up to load the new UI while it appears that you are still animating. Look carefully at the native app transitions. They actually animate less than you probably think and use somewhat simple storyboards. For example the turnstile animation is somewhat close to forward out: 0 to 50 and forward in: –80 to 0. In summary, use animations to help create the illusion of performance.
- When animating between pages, it’s really important that the pages load as fast as possible. There are a few ways to do this:
- Minimize code in the constructor and loaded event. Ideally you should do nothing until the animation is complete.
- Data binding is really slow on the phone and lots of it will just cut any transition. Try to not databind until after the transition is done. For example, pass data in the querystring from the previous page and set it directly on the next page. You want to have some visuals on the page to transition to,but just enough so there is something to actually transition to. If you need to fetch more data,do it after the animation is complete. Keeping lean xaml will help the page load faster.
- Image downloading / decoding just hammers the UI thread. It’s going to be hard to animate a page in smoothly if you are setting some giant background image from a url.
- Make sure your animations run on the compositor thread. This is covered in detail in the Creating High Performing Silverlight Applications for Windows Phone. So just to be clear, if part of your storyboard does something that is not supported on the compositor thread, then your storyboard will not run on the compositor thread. (I could be wrong on that point, although it seems to be the case)
- Pick an easing function and stick with it. There are several easing function to choose from, but it looks weird if you start to mix and match. If you use exponential easing (and you should since that is the closest approximation to what the native apps do), just use that and vary the mode, duration, timing. Obviously you should use some type of easing if you want avoid an oddly robotic looking transition.
Since transitions are so important on the phone it would be great if future versions of the wp7 sdk included some prebuilt animations and events that would help actually running the transitions. At least that is what I’d prefer. Since that doesn’t exist I created a little helper framework that allows me specify a type of transition with the right elements when a page is about to navigate.
Types of animations on the phone
The phone has 4 animation directions: forward in, forward out, backward in, backward out. So if you transition to a page and click the back button, you need to have the reverse animation or at least something different that what you did on the way in.
The types of animations are:
turnstile
The default animation you see when an app launches and rotates in or when switching between tasks (choosers, launchers, certain pages)
When to use
Switching context from one task to another like opening a map for directions or when switching from one page to another that is not really a drill down detail or continuing context
Approximate storyboard
forward in: rotate on y-axis from –80 to 0 for 350ms, exponential out(exponent 6)
forward out: rotate on y-axis from 0 to 50 for 250ms, exponential in (exponent 6)
backward in: rotate on y-axis from 50 to 0 for 350ms, exponential out(exponent 6)
backward out: rotate on y-axis from 0 to -80 for 250ms, exponential in(exponent 6)
Notice the difference in timings and easing mode on the forward out of one page to the forward in of the other page. You don’t have to animate to from 90 to get that turnstile effect. Switching the easing mode creates the illusion for the swinging effect. As mentioned before, it’s really important the next page loads quickly so it appears to be one continuous motion. By not animating the full 90 and animating toward the outside portion of the viewport your mind should fill in the missing parts of the animation (the rest of the rotation that you would see and the part of the rotation that would be off-screen anyway) giving you almost a second to load the next page.
turnstile feather
The turnstile feather is basically like the turnstile except that list items each rotate out in succession. The start menu list on the phone does a turnstile feather to launch an app.
When to use
Same place as the turnstile, but for pages that are lists.
Note: This is probably obvious, but the transition out from one page should match the transition in on the next page. So don’t turnstile a page out and slide the next one in. That is just awkward. Although you can pair a turnstile with a turnstile feather since they are similar.
Approximate storyboard
forward in: rotate on y-axis from –80 to 0 for 350ms, exponential out(exponent 6)
forward out: rotate on y-axis from 0 to 50 for 250ms, exponential in (exponent 6)
backward in: rotate on y-axis from 50 to 0 for 350ms, exponential out(exponent 6)
backward out: rotate on y-axis from 0 to -80 for 250ms, exponential in(exponent 6)
Each item turnstiling out is delayed 50 ms from the previous one. It also looks cool if you save the selected item to last when you animate out. The start menu does this.
continuum
The continuum animation is used to create a sense of continuing context from one screen to another. The music + videos app does this when you click one of the initial menu options like “music” or “podcasts” and the text animates to the secondary page to become the title.
When to use
Lists of summary info like a name that when clicked go to a detail screen. Task menu options that become the pivot title of the next screen.
Approximate storyboard
The continuum animation is a little more complex than a storyboard. It has some code that creates a copy of the selected element so it can move without fading like the rest of the page.
Basically it’s something like:
forward out: the selected item drops 73px and slides 225 over with an expo ease in(exp 3 or 6) over 150ms. Page slides down 70px and the opacity goes to 0 with the same easing and time.
forward in: the page slides up 50px with and expo ease out over 150ms. The continuous element slides down 70px and over 130px with the same easing.
backward out: whole pages slides down 50px, expo ease in over 150 ms. The opacity also goes from 1 to 0. The native apps like the marketplace have a slightly different style where the continuous element slides and fades, but the whole page does not. Adjust to your liking.
backward in: The element that animated out slides in from –70px to the left with an expo ease out over 150ms
slide
The slide animations slide/fades some content over the existing content. This is used in the native apps to signify the creation of something new.
When to use
Creating or adding new items in your app. You can slide up/down left right. Whatever works for your layout. If you use separate pages, you can still slide, but the effect isn’t as good. Ideally the sliding element would be a control so it can be in a popup. In the attached example i use a fake popup that is just an element on the frame. There are 3 reasons for this:
- Animations on popups don’t seem to be on the gpu
- Sometimes i want the popup to handle both orientations and it’s easier if it’s in the frame.
- If you have larger input boxes, an element in the frame will handle scrolling better to accept input. The SIP doesn’t work the same on popups vs elements in the frame.
Approximate storyboard
forward in: 150 (left, right, up or down), exponential out(exponent 6), 350ms, opacity 0 to 1
backward out: 150 (left, right, up or down), exponential in(exponent 6), 250ms, opacity 0 to 1
rotate
Rotating is used to change orientations form landscape to portrait. David Anson has a good post on this. Otherwise the UI should rotate from 0 to +- 90 over 500ms using exponentialeaseInOut. the rotation angle should be counter to the direction hat the device was rotated.
The easing exponents might have to be adjusted. Most of the ones that are 6 could be 3. If your app lags a little between page navigations you might not see animations with an exponent of 6 clearly.
For all of these storyboards you can just look in the code.
Code
This sample uses a base page. The reason I used a base page instead of a frame is because i wanted more control of animating actual elements on the page. In general the base page cancels all navigations, does some animation and recalls the navigation method that was originally passed. The base page requires some animation context for a page (usually layoutroot, but depends on your app)
The base page adds two overrides, GetAnimation and AnimationComplete. GetAnimation lets you specify and animator like continuum or turnstile based on a direction and uri of the next page. AnimationComplete let’s you reset some things on back navigation. Ideally you would just databind on forward navigation and reuse the page from the back stack on back navigation and only do binding on forward navigations. Not doing any work before AniamtionComplete allows you to have smoother, uncut page transitions. Otherwise you are fighting for cpu/gpu time.
So it looks like:
protected override GetAnimation(AnimationType animationType, Uri toOrFrom) { if (animationType == AnimationType.NavigateForwardIn) return new TurnstileFeatherForwardInAnimator() { ListBox = List, RootElement = LayoutRoot }; else return new TurnstileFeatherBackwardOutAnimator() { ListBox = List, RootElement = LayoutRoot }; }
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
protected override void AnimationsComplete(AnimationType animationType) { switch (animationType) { case AnimationType.NavigateForwardIn: //set data contexts break;
case AnimationType.NavigateBackwardIn:
AnimationList.SelectedIndex = -1; break; }
base.AnimationsComplete(animationType); }
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
By default if you just inherit from the base page and set an animation context in the constructor, it will turnstile those pages.
The base page model might be a little more intrusive, but we’ve already been using base pages to centralize a lot of common logic we are doing like saving state.
This is definitely a work in progress and could be more efficient, but I wanted to post something since some people seem to struggle with getting started with page animations. Contact me if you have any thoughts.
,
permalink
With the iPad, e-reader and slate PC craze, I thought I’d put together some thoughts on a Microsoft tablet device that is not the Courier. Since the content is rather long I made it a word doc – Microsoft Tablet Thoughts. I have separate thoughts on the Courier concept videos that have been released, but I’ll save those for another post.
,
permalink
I use Json all the time, but I feel like it’s super annoying in .NET. Typically I’d call some web service that returns Json. In .NET it seems like the best thing to is to define a data contract and use the DataContractSerializer:
[DataContract] public class Person { [DataMember] public string FirstName { get; set; } [DataMember] public string LastName { get; set; } }
then to deserialize whatever string of Json I got back. .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
public static Person DeserializeToPerson( string jsonString ) { using( MemoryStream ms = new MemoryStream( Encoding.Unicode.GetBytes( jsonString ) ) ) { DataContractJsonSerializer serializer = new DataContractJsonSerializer( typeof( Person ) ); return ( Person )serializer.ReadObject( ms ); } }
Feels like a lot of code and I need to define the data contract beforehand which seems a little unnecessary given the dynamic nature of web services and Json. Things like the the memory stream reader and getting bytes off the string are brutal. Why can’t i just pass a string to the JsonDataContractSerializer? Some things seem way more complicated in .NET than they need to be. (cref: Calling REST services in .NET)
What I’d like is something closer to Python.
import simplejson as json person = json.loads(jsonString) print person.FirstName
That is pretty easy.
With .NET there are some options like:
System.Json
var data = JsonObject.Load(dataStream); Console.Writeline(data["FirstName"])
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
This is pretty close to what I want. The problem is having to cast sub items to things like JsonArray and what not. Secondly, System.Json only works in Silverlight so i can’t use in a web project or desktop app.
Next option is one of the Json libraries like Json.Net. Not that I mind using any 3rd party DLLs, I just think parsing Json is fairly common if you are calling a rest web service and it should be in the framework,maybe I’m the only one that uses json all the time instead of XML but I’d rather use Lotus Notes everyday than parse XML and you know I hates the Lotus Notes.
This site has an interesting approach: http://blog.petegoo.com/archive/2009/10/27/using-json.net-to-eval-json-into-a-dynamic-variable-in.aspx
2 problems for me. I still need to reference Json.Net and there is that ridiculous looking code to convert to Expando object. I just don’t feel comfortable dropping that blob in my code.
Ideally Json parsing would be something similar but handled in the framework:
dynamic person = JsonObject.Load(jsonString) Console.Writeline(person.FirstName)
That makes me happy. No pre-defining a contract and something in the framework that can take a string of Json and return back a dynamic object. There is so much stuff in the .NET framework,why can’t there be useful helpers that do common tasks like this.
I could totally be missing simpler solutions so feel free to chime in if I’m just an idiot and missing something obvious.
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
,
permalink
I feel like an idiot for not realizing this sooner, but if you have the Surface touchpack for Win7, you can reference those Microsoft.Surface.Touchpack dlls in your Surface app, remove the regular Surface references and change the namespaces and voila, your Surface app runs on Win 7. How did I not know this sooner? That seems fairly awesome to me. Surface apps running on the 3m 10-touch capacitive screen are fantastic.
,
permalink
Here are things I’ve been thinking about lately in regards to mobile advertising.
- Mobile advertising seems really underdeveloped. Maybe in part because it’s difficult to tailor ads to various devices and it’s easy to push the standard banner ad inventory or just punt on originality and buy Google ad words. (side note – who actually clicks on google ads? how does this make money for anyone? they seem so worthless)
- Local advertising also seems fairly weak. What replaces local business ads in local papers once they all die out? It doesn’t seem effective for those businesses to buy google ad words. The geographic targeting seems limited and again, who clicks on those ads. There seems to be room for someone to come in and dominate advertising on the local level similar to what google did with online ads in general. Make it super easy and cheap for local businesses to display ads to people that are within a given radius of their business.
- My ideal mobile advertising scenario is close to what Foursquare has done. I check-in at one venue and it alerts me of specials nearby. Although it’s pretty basic in Foursquare. It seems like it could be way more targeted. I check-in at a bar and it could present offers for drink specials at the bar next door. I love the market that could develop for bidding on what gets displayed when you check-in at certain venues. (Side note – I really want to see sponsored badges on Foursquare seems like a great revenue model. Bonus points if the foursquare app handles mobile payments to track actually getting those badges. Pay for 10 lattes with the foursqaure app, get the latte lover badge)
Ad words and banner ads just seem lazy. Want to target rich people? put a banner ad on forbes. Want to target people who like to ski? buy an ad word for “ski”
Here is what I want in ads:
- Contextual relevant – This is the whole reason facebook ads are worthless. Just because I like books by Michael Chabon, doesn’t mean I want to see an for his book. I probably already have it and most likely I was just browsing someone’s drunken party pics so I was too distracted to notice the ad anyway.
- Engaging not just distracting – There are a lot of talented agencies out there, do something good. Make me want to experience the ad instead of just clogging up the intertubes and my screen with your 120×240 animated gif.
- Demographically relevant – I like that Hulu let’s me choose. I’d rather watch the Smirnof ad than the trailer for the new Sex & the City movie. (Bonus points to Hulu for recognizing that if you show me a 10 second ad instead of 3 mins, I will actually pay attention because it’s not enough time for me to leave the room)
- Geographically focused – I see ads for Sonic on TV sometimes. I want that slushy and tater tots shown. There is no Sonic in San Francisco. That makes me sad. This shouldn’t happen.
- Value Added – Mint does this well. I don’t mind seeing credit card or bank ads because they are presented in a helpful manner and again are contextually relevant. The same ad for a “no limits platinum joie de vivre” card shown on espn.com just pisses me off and ad block is going to boot it off my screen
Mobile advertising seems like it could knock all these out. I’m out shopping, I check-in at the Extra Big & Tall show me an ad for a sale on husky fleece pants at Old Navy next door. Maybe include multiple product photos or a little video. You can even scan the ad when i purchase said husky fleece pants to complete the feedback loop. Contextually relevant – I’m shopping, Engaging – some multi-media action, Demographically relevant – I’m a big guy who like comfy pants, Geographically focused – It’s for the store next door and it adds value – I saved some money or you sold me on something I didn’t think I even needed.
Is this too much to ask for? I submit no. Stop wasting time on this pennies per billion impression non-sense. Advertisers should be able to get much higher ROI on ads and I shouldn’t have to be inundated with crap. Ads are always going to be a reality, let’s just make them not suck so much.
,
permalink
I’m thinking I’ll just start blogging the random ideas I have. Maybe they are good and i will eventually do it or maybe someone else will and I reap the benefits or maybe they suck and nothing happens. Either way, I get a +1 on my blogging stats.
I love my kindle and I think the demise of e-Ink in favor of reading on a tablets is overrated. The Kindle app store seemed like an obvious idea. Amazon clearly needs to grow the device and lots of people are unwilling to pay $200+ for a device that “just reads books” Not that there is anything wrong with that. Plus they can charge other people for apps without actually having to think of new uses for the Kindle themselves. Well played Amazon.
So idea #1. Facebook on the Kindle. Not original right? I don’t want a Facebook client because I rarely use Facebook anymore. The one really useful thing I like about Facebook is Facebook Connect. I really just want my list of friends and their data. I want the Kindle Facebook app to prompt me for a review after I finish a book and post that to Facebook. Then I want to be able to browse books my friends liked and click to buy. I read a fair amount of books and I’m always interested in recommendations. There are bunch of social book sites out there, but I hate having to enter stuff manually. The Kindle knows when I finish a book so I’d like to just take care of it then automagically. Cross posting the review to Amazon would be nice because I value the ratings on there, but I don’t have “friends” on Amazon so there isn’t an easy way to see what they recommend.
I have no idea what the SDK allows though. It would be great if there was some OnBookCompleted event that you could attach apps to. Also it’s Java and the thought of using Java again makes Kevin the Coder cower in fear. Maybe someone can get JRuby or Jython running on there.
That or it could just tweet the books I read automatically because you really can’t overshare enough on Twitter.
,
permalink
It’s been awhile since I’ve used Azure. The new storage libraries are a welcome addition. As a better diagnostic framework and inter-role communication. In a previous Azure project, I wanted to use ASP.NET caching on the web role, but that breaks down if you start to run multiple instances. With inter-role communication it seems like you could use caching on the server as long as you notify the other instances of updates to the cache. I wrote a little prototype to do that. It’s fairly basic and I haven’t tested it on a real deployment or benchmarked etc. Basically this may just be a terrible way of doing things.
First I defined a contract for the cache messages:
1: using System.Collections.Generic;
2: using System.ServiceModel;
3:
4: namespace MvcWebRole1.Caching
5: {
6: ///
7: /// Defines the contract for the cache service.
8: ///
9: [ServiceContract]
10: public interface ICacheService
11: {
12: [OperationContract(IsOneWay = true)]
13: void Insert(string key, object value);
14:
15: [OperationContract(IsOneWay = true)]
16: void Remove(string key);
17: }
18: }
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
Next I implemented the service for that contract.
1: using System;
2: using System.Web;
3: using System.Diagnostics;
4: using System.Linq;
5: using System.ServiceModel;
6: using System.Threading;
7: using Microsoft.WindowsAzure.Diagnostics;
8: using Microsoft.WindowsAzure.ServiceRuntime;
9:
10: namespace MvcWebRole1.Caching
11: {
12: ///
13: /// Implementation of the WCF cache service.
14: ///
15: [ServiceBehavior(
16: InstanceContextMode = InstanceContextMode.Single,
17: ConcurrencyMode = ConcurrencyMode.Multiple,
18: #if DEBUG
19: IncludeExceptionDetailInFaults = true,
20: #else
21: IncludeExceptionDetailInFaults = false,
22: #endif
23: AddressFilterMode = AddressFilterMode.Any)]
24: public class CacheService : ICacheService
25: {
26: public void Insert(string key,object value)
27: {
28: HttpRuntime.Cache.Insert(key,value);
29: Trace.TraceInformation(String.Format("Added: {0} to key: {1} from broadcast", value, key));
30: }
31:
32: public void Remove(string key)
33: {
34: HttpRuntime.Cache.Remove(key);
35: Trace.TraceInformation(String.Format("Removed key: {0} from broadcast", key));
36: }
37: }
38: }
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
That handles the inserts / deletes the cached items when one instance broadcasts a cache update.
The next bit of code is used to cache on one instance and then broadcast that info out to the other roles.
1: using System;
2: using System.Diagnostics;
3: using System.Linq;
4: using System.ServiceModel;
5: using System.Threading;
6: using System.Web;
7: using Microsoft.WindowsAzure.Diagnostics;
8: using Microsoft.WindowsAzure.ServiceRuntime;
9:
10: namespace MvcWebRole1.Caching
11: {
12: public class SynchedCache
13: {
14: private enum BroadcastType
15: {
16: Insert,
17: Remove
18: }
19:
20: public static void Insert(string key, object value)
21: {
22: HttpRuntime.Cache.Insert(key, value);
23: Trace.TraceInformation(String.Format("Added: {0} to key: {1}", value, key));
24: BroadcastCacheUpdate(BroadcastType.Insert, new object[] {key, value});
25: }
26:
27: public static void Remove(string key)
28: {
29: HttpRuntime.Cache.Remove(key);
30: Trace.TraceInformation(String.Format("Removed key: {0}", key));
31: BroadcastCacheUpdate(BroadcastType.Remove, new object[] { key });
32: }
33:
34: public static object Get(string key)
35: {
36: return HttpRuntime.Cache.Get(key);
37: }
38:
39: private static void BroadcastCacheUpdate(BroadcastType type, params object[] args)
40: {
41: // iterate over all instances of the internal endpoint except the current role - no need to notify itself
42: var current = RoleEnvironment.CurrentRoleInstance;
43: var endPoints = current.Role.Instances.Where(instance => instance != current)
44: .Select(instance => instance.InstanceEndpoints["InternalHttpIn"]);
45:
46: foreach (var ep in endPoints)
47: {
48: EndpointAddress address =
49: new EndpointAddress(String.Format("http://{0}/InternalHttpIn", ep.IPEndpoint));
50: ICacheService client = WebRole.Factory.CreateChannel(address);
51:
52: try
53: {
54: string key = args[0].ToString();
55:
56: switch (type)
57: {
58: case BroadcastType.Insert:
59: client.Insert(key, args[1]);
60: break;
61:
62: case BroadcastType.Remove:
63: client.Remove(key);
64: break;
65: }
66:
67: ((ICommunicationObject)client).Close();
68: }
69: catch (TimeoutException timeoutException)
70: {
71: Trace.TraceError("Unable to notify web role instance '{0}'. The service operation timed out. {1}",
72: ep.RoleInstance.Id, timeoutException.Message);
73: ((ICommunicationObject)client).Abort();
74: }
75: catch (CommunicationException communicationException)
76: {
77: Trace.TraceError("Unable to notify web role instance '{0}'. There was a communication problem. {1} - {2}",
78: ep.RoleInstance.Id, communicationException.Message, communicationException.StackTrace);
79: ((ICommunicationObject)client).Abort();
80: }
81: }
82: }
83: }
84: }
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
Finally in your page you can perform operations on the cache like so.
SynchedCache.Insert(key, DateTime.Now.ToString());.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
That call will then notify all the other web roles running. Of course running AppFabric Caching on Azure would be a much better solution once available, but the inter-role communication is still nice to have for other stuff.
,
permalink
Sorry for the slow response for everyone that messaged me. I didn’t think anyone would actually twitter/facebook message/email me about the app so I wasn’t really ready to release for general usage. Then I respond to some people to let them try it, doesn’t work and then they leave negative reviews on Facebook. Awesome, thanks. Anyway, there is a new version here – http://www.facebook.com/apps/application.php?id=130989934307 If you installed a previous one, just uninstall it. Please read the README in the zip file.
If this doesn’t work for people, I’m giving up. I only built this app to enter into the code7contest and I lost to an app that arguably uses no Win7 features, an old demo app from some competitor and something called “Win7 in my truck” Truly a devastating blow to my motivation to ever touch this code again.
,
permalink
TwtMyCard was down after some brief problems handling the new geo-location features in Twitter. This is what I get for using someone else’s Twitter library :,,)
While it was down I added some caching and other performance improvements. It’s at least 50% faster to send business cards. Maybe even 51%.
I also added the oomph plug-in to the app based on a suggestion from Karsten Januszewski. If you had IE with oomph installed previously, you saw a little icon in the upper left to bring out a microformat overlay. Now TwtMyCard has the oomph plug-in embedded so all browsers can get the same microformat goodness.
If you have features you’d like to see added, use the feedback tab on the site. This weekend we may make some upgrades to support web finger.
,
permalink