Scott Hanselman

Cross-Platform Portable Class Libraries with .NET are Happening

July 9, '13 Comments [28] Posted in Learning .NET
Sponsored By

imagePortable Class Libraries are the Happy Little Feature that Could. They've been chugging along, doing their thing, and it's getting to the point where they are going to pop. That's pop in a good way.

If you're not writing .NET apps for more than one target, then you likely haven't bumped into them. However for those people who are writing .NET and want it to run on everything from Watches to Phones to Tablets to Xboxen to Desktops to the Cloud, they are enjoying what PCLs can offer.

There's still a few technical and legal challenges but I'm confident they'll be dealt with and we'll be able to create great binary libraries that can be used everywhere.

There's been a bunch of recent activity in the .NET community around Portable Class Libraries and cross platform .NET.  Overall, Portable Class Libraries are starting to see wider adoption, more open source libraries are being released with portable support, and the MVVM pattern is proving to be a great way to maximize code sharing in cross platform apps.

Portable Library Releases

First of all, there have been a bunch of new libraries released as PCLs recently.  Three of them are from GitHub's own Paul Betts:

  • Reactive UI – Reactive UI is an MVVM framework built on top of the Reactive ExtensionsVersion 5.0 was released last week, which is "totally Portable-Friendly", and supports the following platforms:
    • Xamarin.iOS
    • Xamarin.Android
    • Xamarin.Mac
    • .NET 4.5 (WPF)
    • Windows Phone 8
    • Windows Store Apps (WinRT)
  • Akavache - An asynchronous, persistent key-value store.  Version 3.0, which includes PCL support, was also released last week, and now "nearly all of your serialization and network access layer can be cross-platform." Akavache supports the same set of platforms as Reactive UI. This is a really amazing piece of software that deserves its own blog post. I'll do one soon.
  • Splat – "A library to make things cross-platform that should be." It has cross platform APIs for images and colors, with platform-specific extension methods to go back and forth between the platform-specific native types.  This looks like an elegant solution to the problem you run into if you want a portable ViewModel but you want to expose an image in it.

Next, Scott LoveGrove confessed:

I might be getting a little obsessed with PCLs at the moment. #IHaveAProblem (link).

Scott has released four portable libraries that help access web services:

  • Scoreoid Portable - A Portable Class Library that gives developers access to the Scoreoid scoring system.  The library provides a friendly .NET wrapper for the Scoreoid REST APIs, and uses our portable HttpClient NuGet package.
  • FanArt Portable - A Portable Class Library that gives developers access to the fanart.tv film, TV, and music image resources.  It also uses portable HttpClient.
  • Cineworld Portable - A Portable Class Library that gives developers access to the Cineworld film and cinema listings for the UK and Ireland.  It also uses portable HttpClient.
  • LiveSDKHelper - A helper library to more easily use the Microsoft Live SDK.  Contains strong types which the responses from the Live SDK can be deserialized into.

Another new portable library release is Budgie, a library for accessing Twitter. The .NET and Azure Teams have also released a PILE of Portable Libraries.

.NET Team:

Other teams:

Not to mention all these excellent Portable Libraries that you should be familiar with as well.

MVVM

IoC

Other

and of course, my favorite, the HttpClient, making HTTP calls easier, since, well, since a few months ago.

public static async Task<HttpResponseMessage> GetTheGoodStuff() 
{
var httpClient = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://hanselman.com/blog/");
var response = await httpClient.SendAsync(request);
return response;
}

//build/

One BUILD attendee took issue with the fact that speakers were telling people that you can't use platform specific functionality from a Portable Class Library, and wrote a blog post about how you can do this with abstraction and (preferably) dependency injection.

On at least 2 occasions recently, I have heard speakers tell their audience that you cannot reference a target-specific .NET library (such as a .NET Framework 4.5 library) from a Portable Class Library. While this is technically true, it doesn't tell nearly the whole story. Even though we can't reference target-specific libraries, we can still USE these libraries. We can call their methods and access their properties under the right circumstances. We can gain access to these libraries via an abstraction. My preferred method of doing this is...Dependency Injection.

Cross Platform .NET Coolness

There's lots of great examples of code reuse, like the podcast I did with the folks who wrote "Draw a Stickman EPIC." This app has 95%+ code reuse, all written in C# and is available in every App Store there is. Here's a few others.

Also, be sure to check out my talk from the Xamarin Evolve Conference - How C# Saved My Marriage. I talk about Portable Libraries in this talk. We'll hear more about Portable Libraries at the MonkeySpace Conference in Chicago in July of 2013.

clip_image001[6]

The British and Irish Lions app is a cross platform app targeting Windows Store, Windows Phone, iOS and Android. It uses Portable Class Libraries to share common code across platforms, Azure to host the services it uses, and the MvvmCross MVVM framework which I'm a huge fan of. The UK MSDN blog posted a case study of the development of the app, and there is also a prettier case study (with screenshots, infographics, etc) and a blog post by the developers.  In reference to Xamarin, MvvmCross, and Portable Class libraries, they state "Given the very short time-scales for the Lions apps (less than three months from the first line of code to our first release), we simply could not have delivered a rich native experience across all platforms without the common core."

Lions Rugby

Another cross platform app that uses MvvmCross is Aviva Drive.  This is an insurance company app that you can use to track your driving habits and hopefully get a discount on your insurance.  The app was featured in the Tech Ed Europe day 1 keynote (about 28:40 in), focusing on how it used Azure.

On the game side of things, Taptitude is a successful Windows Phone 7 game (or rather, a collection of minigames) which was ported to Windows Phone 8, Windows Store, iOS, and Android with the help of MonoGame and Xamarin.  The team reports that they have more than 99% shared code between all the platforms, which is especially important to them because they ship updates to the game about every week.

Xamarin

Scan.Xamarin.com

Xamarin has released an amazing .NET Mobility Scanner which analyzes code and tells you how "portable" it is and how compatible it will be with Xamarin.Android, Xamarin.iOS, Windows Phone, and Windows Store.  It lists all the APIs your code uses that aren't available on all the platforms, and an overall percentage of how portable your code is.  It's a very slick implementation and similar to what we've wanted to have for Portable Class Libraries.  Here's a sample report for the SignalR client library. The best part is that it does all this analysis without sending your code or binaries to Xamarin. It all happens in the browser. I love Xamarin.

Phil Haack (former PM for ASP.NET MVC and now working at GitHub) wrote a blog post titled Platform Limitations Harm .NET.  He argues that the Windows platform limitations should be removed from the EULAs for BCL NuGet packages.

I personally agree. Being able to reuse existing code, make portable libraries, and write apps that run in 64k or 64gigs is what makes .NET an interesting platform.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

Comparing two techniques in .NET Asynchronous Coordination Primitives

December 11, '12 Comments [13] Posted in Back to Basics | Learning .NET
Sponsored By

Last week in my post on updating my Windows Phone 7 application to Windows 8 I shared some code from Michael L. Perry using a concept whereby one protects access to a shared resource using a critical section in a way that works comfortably with the new await/async keywords. Protecting shared resources like files is a little more subtle now that asynchronous is so easy. We'll see this more and more as Windows 8 and Windows Phone 8 promote the idea that apps shouldn't block for anything.

After that post, my friend and mentor (he doesn't know he's my mentor but I just decided that he is just now) Stephen Toub, expert on all things asynchronous, sent me an email with some excellent thoughts and feedback on this technique. I include some of that email here with permission as it will help us all learn!

I hadn’t seen the Awaitable Critical Section helper you mention below before, but I just took a look at it, and while it’s functional, it’s not ideal.  For a client-side solution like this, it’s probably fine.  If this were a server-side solution, though, I’d be concerned about the overhead associated with this particular implementation.

I love Stephen Toubs's feedback in all things. Always firm but kind. Stephen Cleary makes a similar observation in the comments and also points out that immediately disabling the button works too. ;) It's also worth noting that Cleary's excellent AsyncEx library has lots of async-ready primitives and supports both Windows Phone 8 and 7.5.

The SemaphoreSlim class was updated on .NET 4.5 (and Windows Phone 8) to support async waits. You would have to build your own IDisposable Release, though. (In the situation you describe, I usually just disable the button at the beginning of the async handler and re-enable it at the end; but async synchronization would work too).

Ultimately what we're trying to do is create "Async Coordination Primitives" and Toub talked about this in February.

Here's in layman's terms what we're trying to do, why it's interesting and a definition of a Coordinate Primitive (stolen from MSDN):

Asynchronous programming is hard because there is no simple method to coordinate between multiple operations, deal with partial failure (one of many operations fail but others succeed) and also define execution behavior of asynchronous callbacks, so they don't violate some concurrency constraint. For example, they don't attempt to do something in parallel. [Coordination Primitives] enable and promote concurrency by providing ways to express what coordination should happen.

In this case, we're trying to handled locking when using async, which is just one kind of coordination primitive. From Stephen Toub's blog:

Here, we’ll look at building support for an async mutual exclusion mechanism that supports scoping via ‘using.’

I previously blogged about a similar solution (http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx), which would result in a helper class like this:

Here Toub uses the new lightweight SemaphoreSlim class and indulges our love of the "using" pattern to create something very lightweight.

public sealed class AsyncLock
{
private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
private readonly Task<IDisposable> m_releaser;

public AsyncLock()
{
m_releaser = Task.FromResult((IDisposable)new Releaser(this));
}

public Task<IDisposable> LockAsync()
{
var wait = m_semaphore.WaitAsync();
return wait.IsCompleted ?
m_releaser :
wait.ContinueWith((_, state) => (IDisposable)state,
m_releaser.Result, CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}

private sealed class Releaser : IDisposable
{
private readonly AsyncLock m_toRelease;
internal Releaser(AsyncLock toRelease) { m_toRelease = toRelease; }
public void Dispose() { m_toRelease.m_semaphore.Release(); }
}
}

How lightweight and how is this different from the previous solution? Here's Stephen Toub, emphasis mine.

There are a few reasons I’m not enamored with the referenced AwaitableCriticalSection solution. 

First, it has unnecessary allocations; again, not a big deal for a client library, but potentially more impactful for a server-side solution.  An example of this is that often with locks, when you access them they’re uncontended, and in such cases you really want acquiring and releasing the lock to be as low-overhead as possible; in other words, accessing uncontended locks should involve a fast path.  With AsyncLock above, you can see that on the fast path where the task we get back from WaitAsync is already completed, we’re just returning a cached already-completed task, so there’s no allocation (for the uncontended path where there’s still count left in the semaphore, WaitAsync will use a similar trick and will not incur any allocations).

Lots here to parse. One of the interesting meta-points is that a simple client-side app with a user interacting (like my app) has VERY different behaviors than a high-throughput server-side application. Translation? I can get away with a lot more on the client side...but should I when I don't have to?

His solution requires fewer allocations and zero garbage collections.

Overall, it’s also just much more unnecessary overhead.  A basic microbenchmark shows that in the uncontended case, AsyncLock above is about 30x faster with 0 GCs (versus a bunch of GCs in the AwaitableCriticalSection example.  And in the contended case, it looks to be about 10-15x faster.

Here's the microbenchmark comparing the two...remembering of course there's, "lies, damned lies, and microbenchmarks," but this one is pretty useful. ;)

class Program
{
static void Main()
{
const int ITERS = 100000;
while (true)
{
Run("Uncontended AL ", () => TestAsyncLockAsync(ITERS, false));
Run("Uncontended ACS", () => TestAwaitableCriticalSectionAsync(ITERS, false));
Run("Contended AL ", () => TestAsyncLockAsync(ITERS, true));
Run("Contended ACS", () => TestAwaitableCriticalSectionAsync(ITERS, true));
Console.WriteLine();
}
}

static void Run(string name, Func<Task> test)
{
var sw = Stopwatch.StartNew();
test().Wait();
sw.Stop();
Console.WriteLine("{0}: {1}", name, sw.ElapsedMilliseconds);
}

static async Task TestAsyncLockAsync(int iters, bool contended)
{
var mutex = new AsyncLock();
if (contended)
{
var waits = new Task<IDisposable>[iters];
using (await mutex.LockAsync())
for (int i = 0; i < iters; i++)
waits[i] = mutex.LockAsync();
for (int i = 0; i < iters; i++)
using (await waits[i]) { }
}
else
{
for (int i = 0; i < iters; i++)
using (await mutex.LockAsync()) { }
}
}

static async Task TestAwaitableCriticalSectionAsync(int iters, bool contended)
{
var mutex = new AwaitableCriticalSection();
if (contended)
{
var waits = new Task<IDisposable>[iters];
using (await mutex.EnterAsync())
for (int i = 0; i < iters; i++)
waits[i] = mutex.EnterAsync();
for (int i = 0; i < iters; i++)
using (await waits[i]) { }
}
else
{
for (int i = 0; i < iters; i++)
using (await mutex.EnterAsync()) { }
}
}
}

Stephen Toub is using Semaphore Slim, the "lightest weight" option available, rather than RegisterWaitForSingleObject:

Second, and more importantly, the AwaitableCriticalSection is using a fairly heavy synchronization mechanism to provide the mutual exclusion.  The solution is using Task.Factory.FromAsync(IAsyncResult, …), which is just a wrapper around ThreadPool.RegisterWaitForSingleObject (see http://blogs.msdn.com/b/pfxteam/archive/2012/02/06/10264610.aspx).  Each call to this is asking the ThreadPool to have a thread block waiting on the supplied ManualResetEvent, and then to complete the returned Task when the event is set.  Thankfully, the ThreadPool doesn’t burn one thread per event, and rather groups multiple events together per thread, but still, you end up wasting some number of threads (IIRC, it’s 63 events per thread), so in a server-side environment, this could result in degraded behavior.

All in all, a education for me - and I hope you, Dear Reader - as well as a few important lessons.

  • Know what's happening underneath if you can.
  • Code Reviews are always a good thing.
  • Ask someone smarter.
  • Performance may not matter in one context but it can in another.
  • You can likely get away with this or that, until you totally can't. (Client vs. Server)

Thanks Stephen Toub and Stephen Cleary!

Related Reading

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

Back to Basics: Dynamic Image Generation, ASP.NET Controllers, Routing, IHttpHandlers, and runAllManagedModulesForAllRequests

April 7, '12 Comments [33] Posted in ASP.NET | ASP.NET MVC | Back to Basics | Learning .NET
Sponsored By

Warning, this is long but full of info. Read it all.

Often folks want to dynamically generate stuff with ASP.NET. The want to dynamically generate PDFs, GIFs, PNGs, CSVs, and lots more. It's easy to do this, but there's a few things to be aware of if you want to keep things as simple and scalable as possible.

You need to think about the whole pipeline as any HTTP request comes in. The goal is to have just the minimum number of things run to do the job effectively and securely, but you also need to think about "who sees the URL and when."

A timeline representation of the ASP.NET pipeline

 

This diagram isn't meant to be exhaustive, but rather give a general sense of when things happen.

Modules can see any request if they are plugged into the pipeline. There are native modules written in C++ and managed modules written in .NET. Managed modules are run anytime a URL ends up being processed by ASP.NET or if "RAMMFAR" is turned on.

RAMMFAR means "runAllManagedModulesForAllRequests" and refers to this optional setting in your web.config.

<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>

You want to avoid having this option turned on if your configuration and architecture can handle it. This does exactly what it says. All managed modules will run for all requests. That means *.* folks. PNGs, PDFs, everything including static files ends up getting seen by ASP.NET and the full pipeline. If you can let IIS handle a request before ASP.NET sees it, that's better.

Remember that the key to scaling is to do as little as possible. You can certainly make a foo.aspx in ASP.NET Web Forms page and have it dynamically generate a graphic, but there's some non-zero amount of overhead involved in the creation of the page and its lifecycle. You can make a MyImageController in ASP.NET MVC but there's some overhead in the Routing that chopped up the URL and decided to route it to the Controller. You can create just an HttpHandler or ashx. The result in all these cases is that an image gets generated but if you can get in and get out as fast as you can it'll be better for everyone. You can route the HttpHandler with ASP.NET Routing or plug it into web.config directly.

Works But...Dynamic Images with RAMMFAR and ASP.NET MVC

A customer wrote me who was using ASP.NET Routing (which is an HttpModule) and a custom routing handler to generate images like this:

routes.Add(new Route("images/mvcproducts/{ProductName}/default.png", 
new CustomPNGRouteHandler()));

Then they have a IRouteHandler that just delegates to an HttpHandler anyway:

public class CustomPNGRouteHandler : IRouteHandler
{
public System.Web.IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new CustomPNGHandler(requestContext);
}
}

Note the {ProductName} route data in the route there. The customer wants to be able to put anything in that bit. if I visit http://localhost:9999/images/mvcproducts/myproductname/default.png I see this image...

A dynamically generated PNG from ASP.NET Routing, routed to an IHttpHandler

Generated from this simple HttpHandler:

public class CustomPNGHandler : IHttpHandler
{
public bool IsReusable { get { return false; } }
protected RequestContext RequestContext { get; set; }

public CustomPNGHandler():base(){}

public CustomPNGHandler(RequestContext requestContext)
{
this.RequestContext = requestContext;
}

public void ProcessRequest(HttpContext context)
{
using (var rectangleFont = new Font("Arial", 14, FontStyle.Bold))
using (var bitmap = new Bitmap(320, 110, PixelFormat.Format24bppRgb))
using (var g = Graphics.FromImage(bitmap))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
var backgroundColor = Color.Bisque;
g.Clear(backgroundColor);
g.DrawString("This PNG was totally generated", rectangleFont, SystemBrushes.WindowText, new PointF(10, 40));
context.Response.ContentType = "image/png";
bitmap.Save(context.Response.OutputStream, ImageFormat.Png);
}
}
}

The benefits of using MVC is that handler is integrated into your routing table. The bad thing is that doing this simple thing requires RAMMFAR to be on. Every module sees every request now so you can generate your graphic. Did you want that side effect? The bold is to make you pay attention, not scare you. But you do need to know what changes you're making that might affect the whole application pipeline.

(As an aside, if you're a big site doing dynamic images, you really should have your images on their own cookieless subdomain in the cloud somewhere with lots of caching, but that's another article).

So routing to an HttpHandler (or an MVC Controller) is an OK solution but it's worth exploring to see if there's an easier way that would involve fewer moving parts. In this case the they really want the file to have the extension *.png rather than *.aspx (page) or *.ashx (handler) as it they believe it affects their image's SEO in Google Image search.

Better: Custom HttpHandlers

Remember that HttpHandlers are targeted to a specific path, file or wildcard and HttpModules are always watching. Why not use an HttpHandler directly and plug it in at the web.config level and set runAllManagedModulesForAllRequests="false"?

<system.webServer>
<handlers>
<add name="pngs" verb="*" path="images/handlerproducts/*/default.png"
type="DynamicPNGs.CustomPNGHandler, DynamicPNGs" preCondition="managedHandler"/>
</handlers>
<modules runAllManagedModulesForAllRequests="false" />
</system.webServer>

Note how I have a * there in part of the URL? Let's try hitting http://localhost:37865/images/handlerproducts/myproductname/default.png. It still works.

A dynamically generated PNG from an ASP.NET IHttpHandler

This lets us not only completely bypass the managed ASP.NET Routing system but also remove RAMMFAR so fewer modules are involved for other requests. By default, managed modules will only run for requests that ended up mapped to the managed pipeline and that's almost always requests with an extension. You may need to be aware of routing if you have a "greedy route" that might try to get ahold of your URL. You might want an IgnoreRoute. You also need to be aware of modules earlier in the process that have a greedy BeginRequest.

The customer could setup ASP.NET and IIS to route request for *.png to ASP.NET, but why not be as specific as possible so that the minimum number of requests is routed through the managed pipeline? Don't do more work than you need to.

What about extensionless URLs?

Getting extensionless URLs working on IIS6 was tricky before and lots of been written on it. Early on in IIS6 and ASP.NET MVC you'd map everything *.* to managed code. ASP.NET Routing used to require RAMFARR set to true until the Extensionless URL feature was created.

Extentionless URLs support was added in this KB http://support.microsoft.com/kb/980368 and ships with ASP.NET MVC 4. If you have ASP.NET MVC 4, you have Extentionless URLs on your development machine. But your server may not. You may need to install this hotfix, or turn on RAMMFAR. I would rather you install the update than turn on RAMMFAR if you can avoid it. The Run All Modules options is really a wildcard mapping.

Extensionless URLs exists so you can have URLs like /home/about and not /home/about.aspx. It exists to get URLs without extensions to be seen be the managed pipelines while URLs with extensions are not seen any differently. The performance benefits of Extensionless URLs over RAMMFAR are significant.

If you have static files like CSS, JS and PNG files you really want those to be handled by IIS (and HTTP.SYS) for speed. Don't let your static files get mapped to ASP.NET if you can avoid it.

Conclusion

When you're considering any solution within the ASP.NET stack (or "One ASP.NET" as I like to call it)...

The complete ASP.NET stack with MVC, Web Pages, Web Forms and more called out in a stack of boxes

...remember that it's things like IHttpHandler that sit at the bottom and serve one request (everything comes from IHttpHandler) while it's IHttpModule that's always watching and can see every request.

In other words, and HttpHandler sees the ExecuteRequestHandler event which is just one event in the pipeline, while HttpModules can see every event they subscribe to.

HttpHandlers and Modules are at the bottom of the stack

I hope this helps!


Sponsor: Thank you to my friends at Axosoft for sponsoring the Hanselman feed this week. Do check out their product! Imagine agile project management software that is brilliantly easy to use, blazingly fast, totally customizable, and just $7 per user. With OnTime Scrum, you won't have to imagine. Get started free.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

Hidden Gems in Visual Studio 11 Beta - .NET Portable Class Libraries

April 5, '12 Comments [28] Posted in Learning .NET
Sponsored By

.NET Portable SubsetI'm realizing there's a number of subtle but important new things in the next version of VS that streamline some previously difficult tasks. For example, there's the .NET Framework, but .NET is also in Silverlight, the Windows Phone, the Xbox, etc.

If you create a regular Class Library it has a single Target Framework. However, if you are doing a multi-platform application and you want to maximize your code reuse, you can run into trouble as you may not have all libraries available on the smaller platforms.

Thus, Portable Class Libraries were created. You can get Portable Class Libraries via an extension on Visual Studio 2010 or they are built into Visual Studio 11 Beta.

These Portable Class Libraries (PCLs) will generate a managed assembly that can be referenced by Windows Phone 7, Silverlight, the Microsoft .NET Framework and Xbox 360 platforms. This really helps to maximize reuse of code and reduce the number of projects in multi-targeted application solutions.

I talked about multi-targeting a little in the .NET Versioning and Multi-Targeting - .NET 4.5 is an in-place upgrade to .NET 4.0 post. Visual Studio is smart enough to tell you before compilation what APIs are available. The compiler knows and Intellisense knows. The Reference Assemblies down in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\ tell you a lot.

Reference Assemblies include .NET Portable Assemblies

If you create a new Portable Class Library, right click on it and hit Properties. You can target specific frameworks and the build system and Intellisense will adjust. Some libraries are on some device. For example, XML Serialization isn't on the Xbox 360, but WCF is on the Windows Phone.

Select the Frameworks you want

Bill Kratochvil has an article in MSDN Magazine that includes the source for a project that targets Windows Phone 7, Silverlight and WPF with shared libraries. David Kean has an article this month in MSDN Mag on how to Create a Continuous Client Using Portable Class Libraries.

Remember that Portable Class Libraries are constrained by design. You're targeting the lowest common denominator to maximize what you can use between projects. The MSDN article on Portable Class Libraries has a table that show what's available on each platform. You can do MVVM work across Windows, Metro style aopps, Silverlight and Windows Phone, for example.

Here's some good advice that David Kean sent me:

One thing [about] using portable [is that it] doesn’t mean you can’t use platform specific features, you just need to spend a little more time thinking about your dependencies. For example, instead of having a low level class that handles your persistence layer using the File APIs (which aren’t usable/available on Phone, Silverlight, etc), have it instead take work on an abstraction such as a stream, which these gets passed that from the platform specific project. Or have it call through an platform adapter (called out in my article), or inject the abstraction using your favorite IoC container (in my case Autofac, just published a portable version)

MSDN Help also shows what works with Portable Libraries as well so you're supported when looking at Help, Intellisense, and at Build time.

image

The BCL Blog mentioned that they are talking to the Mono guys about this as well. It'd be great to get Mono for Android and other frameworks as appropriate in here as well. I was excited to discover that this work was happening, even though it's been over a year in the making.

For folks like my friends at Rowi who have a great Windows Phone 7 application, or MetroTwit with a great WPF app, I wonder how Portable Class Libraries might change the architecture of their applications and enable cleaner builds and reuse scenarios they haven't thought of.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

.NET Versioning and Multi-Targeting - .NET 4.5 is an in-place upgrade to .NET 4.0

April 2, '12 Comments [89] Posted in Learning .NET
Sponsored By

Say what you will about the past ridiculousness of .NET Framework versioning, since the confusion of .NET 3.5SP1 they've  been trying to get it right. It's not the magic of Java Version 6 Update 31 (build 1.6.0_31-b05) but it's a start. O_o

Back in July of 2011 I wrote a post on Issues with .NET and Microsoft Product Versioning that got the attention of some folks. I was most concerned about some "platform updates" to .NET 4 and the way they were named. Meetings were had and those small updates now have simpler names versions like NET 4.0.1, etc.

I'm not going to tell you it's not confusing today. I do think that things are getting better and becoming less confusing. .NET 4.5 is a step in the right direction of transparency in versioning.

The .NET Framework can version in two ways. There are "side by side installs" and there are "in place upgrades." A major version means side-by-side and a minor version means in-place.

Side-by-side means that different versions of .NET can live together on the same machine.

Diagram: .NET CLRs can live side by side

In-place upgrade means that the CLR is the same but new libraries are added as well as bug fixes and performance improvements:

Diagram: .NET 4.5 builds on top of .NET 4

There's been some concern about how .NET 4.5 is an "in-place upgrade" of .NET 4. That means .NET 4.5 is still the v4CLR and adds new libraries as well as improvements to the core CLR itself.

Rick Strahl said on his blog:

Note that this in-place replacement is very different from the side by side installs of .NET 2.0 and 3.0/3.5 which all ran on the 2.0 version of the CLR. The two 3.x versions were basically library enhancements on top of the core .NET 2.0 runtime. Both versions ran under the .NET 2.0 runtime which wasn’t changed (other than for security patches and bug fixes) for the whole 3.x cycle. The 4.5 update instead completely replaces the .NET 4.0 runtime and leaves the actual version number set at v4.0.30319.

Rick has a great post with a lot of detail and information. However, respectfully, I don't think .NET 4.5 vs. .NET 4 is as different as Rick implies. In fact .NET 3 and .NET 3.5 both upgraded the system (and CLR) in place as well.

Perhaps if 3 and 3.5 were called .NET 2.5 and .NET 2.8 it would have made more sense. The community is always concerned about breaking changes, much like we are here with .NET 4 and .NET 4.5. Unfortunately reality and marketing names haven't always matched, but going forward I think we all agree that:

  • Major Version = New CLR
  • Minor Version = Bug fixes, new libraries
  • Revision = Bug fixes, no breaking changes, small improvements

.NET 4.5 is not a radically different side-by-side CLR. A new CLR would be a theoretical .NET 5 In my opinion.

Could something break with .NET 4.5? This is why it's in beta now, so now is the time to speak up. It's possible something could break but unlikely according the .NET Blog. Here are the known .NET 4.5 breaking changes - most are pretty obscure. The kinds of breaking changes I've seen myself in the wild have been primarily when folks are relying on reflection or internal data structures. These internals aren't public contracts so they may have changed. I realize that when a change breaks YOU it feels like a situation when "100% of applications will break....mine did!" situation. It sucks, but in fact there are minimal breaking changes in .NET 4.5.

Can I get .NET 2.0, 3.5, 4 and 4.5 apps all running together on my system? Yes.

Can I develop apps with different versions with Visual Studio 11 Beta? Sure, you can multi-target all these versions and even plugin more targeting packs. I'll do a blog post later this week on Portable Libraries, a new version in .NET 4.5 that makes creating libraries for any CLR (including Xbox, Phone, Mono and others).

Screenshot of the multi-targeting dropdown in Visual Studio

Developing Safely for both .NET 4 and .NET 4.5

It's been implied on blogs that if you install .NET 4.5 on your machine that you can't safely develop for .NET 4. In Rick's post, he compares two DLLs on a .NET 4 machine and again after the .NET 4.5 in place upgrade. How can you target safely against .NET 4 if you've installed .NET 4.5? You don't have those .NET 4 DLLs anymore, right?

Actually you do. They are in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework.

Reference Assemblies

Let's prove it on a machine with Visual Studio 11 Beta. I'll make a DLL and reference System.Web and make use of one of the added types in that assembly. Yes, it's a screenshot of code, but hang in there.

Using the .NET 4.5 ModelBinderDictonary Type

Now I'll change the properties of my project from .NET 4.5 to .NET 4. I won't change anything else. I'll build. Note that the type isn't there, I get a build error and I can't reference the namespace. You will know if you're using new .NET 4.5 functionality. The multi-targeting build system was designed for this and existed as far back as .NET 3.5. Those reference assemblies are there to catch this kind of thing.

Referencing .NET 4 and using a type we don't have will cause a compiler error

So while .NET 4 and .NET 4.5 don't live side by side on your system at runtime, Visual Studio knows about all the different versions of .NET and the compiler will reference different versions when you build.

If you are making a client app, like WinForms, Console, WPF, etc, this is all automatic. Your app.config contains that fact that you need .NET 4.5 and you'll even get a prompt to install it.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

So if I run my .NET 4.5 Console App on a .NET 4.0 machine now I get a nice dialog.

A dialog that pops up when running .NET 4.5 apps on .NET 4 to prompt an update

Looks like this technique doesn't work on ASP.NET (I would expect a Yellow Screen of Death)...I will talk to the team about that. I think this is a good thing and ASP.NET should respect it also.

UPDATE #2: The system will throw an error when an ASP.NET 4.5 application is deployed to an ASP.NET 4 system. The default templates on for ASP.NET 4.5 applications include the targetFramework attribute set to 4.5 like this:

<configuration>
<system.web>
<compilation debug="true" strict="false" explicit="true" targetFramework="4.5" />
</system.web>
</configuration>

This will throw a YSOD if you deploy a 4.5 to a 4 machine like this: "The 'targetFramework' attribute currently references a version that is later than the installed version of the .NET Framework."

UPDATE: If you really, really want to detect .NET 4.5 at runtime, don't check versions or build numbers. Check for the existence of the feature you want to use. For example, from this Stackoverflow question by Christian K, here's how to detect .NET 4.5 programmatically.

However, David from the CLR team (in the comments) says that this is not a good idea. He says to check if an important feature is there and use it. Don't cheat and infer .NET versions.

"The IsNet45OrHigher example is not what we'd recommend. By feature detection, we mean 'detecting the presence of a feature before you use that feature', <i>not</i> 'using the presence of a feature to determine what version of .NET you are runnning on."

public static bool IsNet45OrNewer()
{
// Class "ReflectionContext" exists from .NET 4.5 onwards.
return Type.GetType("System.Reflection.ReflectionContext", false) != null;
}

Microsoft has said the same thing about Operating System features:

Identifying the current operating system is usually not the best way to determine whether a particular operating system feature is present. This is because the operating system may have had new features added in a redistributable DLL. Rather than using GetVersionEx to determine the operating system platform or version number, test for the presence of the feature itself.

Related Posts


Sponsor: My sincere thanks to Axosoft for sponsoring this week's Hanselman.com feed! Imagine agile project management software that is brilliantly easy to use, blazingly fast, totally customizable, and just $7 per user. With OnTime Scrum, you won't have to imagine. Get started free.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web
Page 1 of 29 in the Learning .NET category Next Page

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.