Friday, 24 August 2012

WebAPI - AddWithoutValidation method not found

If you are using WebAPI and have recently installed VS2012. Your WebAPI stuff will be broken.
Your controller method will be called then you’ll just get a 500 response. Poking VS got it to give up the underlying exception which is "Method not found System.Net.Http.HttpHeaders.AddWitoutValidation".

Several hours of spelunking, trying framework source stepping, break on exception, beating it with a big stick and compiling from a command line with “msbuild /v:d” which shows assembly reolution resulted in realising that VS was compiling against the correct assemblies (ie I’d previously grabbed the RC from nuget). But…

Using the Fusion Log Viewer (fuslogvw) showed that when I ran the project the System.Net.Http assembly was being redirected to the new framework version instead of the file reference to my copy of the dll.

Here’s my solution: Add your own assembly redirect to ensure the right version of the assembly is used.
Simply add the following section to your app.config (if you are self hosting) or to web.config (if you are hosting in IIS).

<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="1.0.0.0 - 2.0.0.0" newVersion="2.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>

Some will ask “Why bother? Why not just use the RTM?”. Well, I have a new version of our product about to RTM. I really don’t want to have to refactor a bunch of code and have it all go back through QA and regression testing.
We will move on to WebAPI RTM but not until our next version.

This is the risk that the decision to make 4.5 an in-place upgrade exposes us to. What other subtle changes in the framework are there?

I’m glad we test and deploy from build servers and not from a developers machine. You should check that your build environment is compatible with your production/runtime environment.

Wednesday, 7 September 2011

JavaScript OMG!

http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/tags/JavaScriptOMG/default.aspx

Mike Taulty shares a series of posts continuing 20 (so far) interesting and surprising aspects of the JavaScript Language he has discovered in his reading and learning about JavaScript. Each point has some code samples and references to books / articles where you can learn more.

Wednesday, 31 August 2011

It's Not Just Standing Up

http://martinfowler.com/articles/itsNotJustStandingUp.html

 

Daily stand-up meetings have become a common ritual of many teams, especially in Agile software development. However, there are many subtle details that distinguish effective stand-ups and a waste of time.

Thursday, 18 August 2011

JSONP FTW

We’ve been looking at how to integrate our stuff with MS Dynamics CRM. Dynamics does not play nice with others. I won’t go into the details here but I think we’re going to end up using javascript as a proxy to get things done. As a result I’ve been looking at the new (ish) WebAPI bits from the WCF team (http://wcf.codeplex.com). The basic motivation behind this project is to make WCF talk HTTP like a native. Things like content format negotiation are baked in. So you can write a single service and have different clients receive differently formatted responses. So a JQuery ajax call will see JSON another client might see XML. You can even point a browser at your service and get HTML via Razor templates (very useful if you want to add an admin UI to your service.
The point of this post is about content format negotiation and dealing with JsonP.
A lot (errr most) of this is taken from Alexander Zeitlers article. He mentions part way through to grab a file from the WebAPI project. I’ve added a little of my own flavour to this part.

WebAPI has the concept of MediaTypeFormatters. When a request comes in it will have an “accept” header which tells the server which media types the client can handle. A JQuery ajax request would send “application/json”, a browser would send “text/html”.
The accept header value is used to look up which formatter to use to format the response.
There are times, however, when you want to force the format. Testing via a browser is one. But more importantly when using JsonP the request has an accept header of “*/*”. In this case you always want the response in json.
In the ContactManager_Advanced project in the samples included in the codeplex project there is an example of a “MessageChannel” that inspects the uri and sets the accept header. I’ve customised this a little so that it also looks for a “format” parameter in the querystring. It also forces to json if the is a “callback” parameter in the querystring.
Lastly I’ve changed the fluent interface. It made little sense to me to have an extension method on HttpApplication.
Here’s the listing:
    public static class UriFormatExtensionMessageChannelExtensions
    {
        public static IHttpHostConfigurationBuilder AddUriFormatExtension(this IHttpHostConfigurationBuilder builder)
        {
            return builder.AddMessageHandlers(typeof(UriFormatExtensionMessageChannel));
        }
    }

    public class UriFormatExtensionMessageChannel : DelegatingChannel
    {
        public UriFormatExtensionMessageChannel(HttpMessageChannel handler) : base(handler) { }

        private static Dictionary<string, MediaTypeWithQualityHeaderValue> extensionMappings = new Dictionary<string, MediaTypeWithQualityHeaderValue>();

        public static FluentExtensionMappings SetUriExtensionMapping(string extension, string mediaType)
        {
            extensionMappings[extension] = new MediaTypeWithQualityHeaderValue(mediaType);
            return new FluentExtensionMappings();
        }

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (!TryGetLastSegmentFormat(request))
                TryGetQSFormat(request);

            return base.SendAsync(request, cancellationToken);
        }

        /// <summary>
        /// Try to get the format from the last segment of the Uri
        /// </summary>
        /// <example>http://example.com/product/1/json</example>
        /// <param name="request"></param>
        /// <returns>true if a format was found</returns>
        private static bool TryGetLastSegmentFormat(HttpRequestMessage request)
        {
            var segments = request.RequestUri.Segments;
            var lastSegment = segments.LastOrDefault();

            MediaTypeWithQualityHeaderValue mediaType;
            if (extensionMappings.TryGetValue(lastSegment, out mediaType))
            {
                var newUri = request.RequestUri.OriginalString.Replace("/" + lastSegment, "");
                request.RequestUri = new Uri(newUri, UriKind.Absolute);
                request.Headers.Accept.Clear();
                request.Headers.Accept.Add(mediaType);
                return true;
            }

            return false;
        }

        /// <summary>
        /// Try to get the format from the query string of the Uri.
        /// If it's a JsonP callback then force to json
        /// </summary>
        /// <example>http://example.com/product/1?format=json</example>
        /// <param name="request"></param>
        /// <returns>true if a format was found</returns>
        private static bool TryGetQSFormat(HttpRequestMessage request)
        {
            var qsValues = HttpUtility.ParseQueryString(request.RequestUri.Query);
            var format = qsValues["format"];
            bool rebuildUri = false;
            if (!string.IsNullOrEmpty(format))
                rebuildUri = true;

            // if it's a JsonP callback then force to json
            if (!string.IsNullOrEmpty(qsValues["callback"]))
                format = "json";

            MediaTypeWithQualityHeaderValue mediaType;
            if (!string.IsNullOrEmpty(format) && extensionMappings.TryGetValue(format, out mediaType))
            {
                if (rebuildUri)
                {
                    var newUriBuilder = new UriBuilder(request.RequestUri);
                    qsValues.Remove("format");
                    newUriBuilder.Query = qsValues.ToString();
                    request.RequestUri = newUriBuilder.Uri;
                }

                request.Headers.Accept.Clear();
                request.Headers.Accept.Add(mediaType);
                return true;
            }

            return false;
        }

        protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public sealed class FluentExtensionMappings
        {
            public FluentExtensionMappings SetUriExtensionMapping(string extension, string mediaType)
            {
                extensionMappings[extension] = new MediaTypeWithQualityHeaderValue(mediaType);
                return this;
            }
        }
    }



So now your global.asax Application_Start will have a snippet like this.


UriFormatExtensionMessageChannel
  .SetUriExtensionMapping("xml", "application/xml")
  .SetUriExtensionMapping("json", "application/json")
  .SetUriExtensionMapping("png", "image/png")
  .SetUriExtensionMapping("odata", "application/atom+xml");

var config = HttpHostConfiguration.Create()
  .AddUriFormatExtension()
  .AddJsonpHandler();



The AddJsonpHandler line is a simple extension method to wrap Alex’s JsonpResponseHandler.


    public static class JsonpResponseHandlerExtensions
    {
        public static IHttpHostConfigurationBuilder AddJsonpHandler(this IHttpHostConfigurationBuilder builder)
        {
            return builder.AddResponseHandlers(c => c.Add(new JsonpResponseHandler()), (s, d) => true);            
        }
    }



Although this example is using IIS to host the service all of this is equally applicable to self hosted services.

Tuesday, 15 February 2011

Hidden Features of C#?

http://stackoverflow.com/questions/9033/hidden-features-of-c

 

This is kind of a meta answer that lists a set of answers related to features/keywords etc that you may already know about but there is some interesting debate and further links to some of them.

Thursday, 2 December 2010

Google Beatbox

http://kottke.org/10/11/google-beatbox

The latest big thing from Google: beatboxing. Just go to this page on Google Translate and press "Listen"

Wednesday, 23 June 2010

Building without Visual Studio


If you don’t have Visual Studio installed, maybe because this is a build server, then you will almost certainly get msbuild errors because it cannot find some tool or other from the Windows SDK.

Like:

C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(1835, 9):
error MSB3454: Tracker.exe is required to correctly incrementally generate resources
in some circumstances, such as when building on a 64-bit OS using 32-bit MSBuild.
This build requires Tracker.exe, but it could not be found. The task is looking for
Tracker.exe beneath the InstallationFolder value of the registry key
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A. To solve the
problem, either: 1) Install the Microsoft Windows SDK v7.0A or later. 2) Install
Microsoft Visual Studio 2010. 3) Manually set the above registry key to the correct
location. Alternatively, you can turn off incremental resource generation by setting
the "TrackFileAccess" property to "false".

You may also get a similar message regarding LC.EXE.

The v7.0A version of the Windows SDK is installed when you install Visual Studio 2010 and is expected by the .Net 4.0 version of msbuild. However, you don’t seem to be able to get it as a separate download!

A bit of Googling shows a few “solutions. Such as adding “TrackFileAccess=false” as a configuration option for msbuild (http://bradwilson.typepad.com/blog/2010/05/working-around-build-error-msb3454.html).

This works fine for the TRACKER.EXE problem but not for the LC.EXE version.

Here’s my solution:

  1. Download the v7.1 version of Windows SDK (for .Net 4.0 and good for all version of Windows)
    http://www.microsoft.com/downloads/details.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b&displaylang=en
    Other versions are available from the Windows SDK MSDN Developer Center (http://msdn.microsoft.com/en-us/windowsserver/bb980924.aspx)
  2. This is a web installer. If you decide to go find the full ISO of the SDK it’s around 1.6GB. The web installer lets you only select the bits you want and should download/install in a few minutes.
  3. Run winsdk_web.exe you downloaded above. Click through until you get to the “Installation Options” page.
  4. De-select everything except the .NET Development – Tools. The page should look like this

  5. On Windows 2008 server it will let you also completely unselect the Intellisense assemblies too
  6. Select next until it starts installing.
    Even on a slow connection it should only take a few minutes.
  7. Lastly you need to convince msbuild to use this version of the SDK
  8. On the Start menu you will have a “Microsoft Windows SDK v7.1” folder
  9. Select “Windows SDK 7.1 Command Prompt”
  10. Enter the following commands
    > cd Setup
    > WindowsSdkVer –version:v7.1

    See http://msdn.microsoft.com/en-us/library/ff660764.aspx (Configuring Visual Studio for Visual C++ Development with the Windows SDK) for info
  11. Done. Msbuild will now be able to find the tools it needs

You will also run into problems is you’re trying to compile web apps with an error like

error MSB4019: The imported project "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.

Simply copy the folder “C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0” from your dev machine with VS2010 installed onto your build server.

YMMV but this is what works for me.
Good luck