Wednesday, May 04 2011
CoffeScript vs Script# vs JavaScript, and why it’s funny to me

I’ve seen a lot of buzz around CoffeScript lately, mainly because it’s now bundled with Rails 3.1 and there’s been a lot of positive and negative reactions to it.  Let me just start out by saying I’ve written a good amount of JavaScript code, and while I’m mainly a .NET developer I’ve played around with other frameworks so I’m not totally ignorant of what is out there. 

Here is the problem I see with most JavaScript code.  It’s really hard to do it right.  There are enough bad parts in the language, that it takes probably a good 6 months practice and learning to really grasp all the good parts.   Even then I think most people, myself included, end up writing a weird mix of object oriented and functional style goo that it becomes really tiresome to get good.  It reminds of when I first tried to play racquetball, I was a tennis man for years, and racquetball seemed like an easy transition, but the style of swing and racquet were different enough that it was apparent the better I got at racquetball the worse I would be at tennis and vice-versa.  I think some people pick it up really well, but for others they either don’t take the time, are scared, or just don’t know any better.

This is where something like CoffeeScript comes in.  It’s promise is that if you write your code with us than we’ll convert to professional quality JavaScript.  The problem I’ve always had is that you have to learn a new language/tool to get good at another language.   What I find sort of laughable is that the same people that are loving CoffeeScript are the ones that scoff at using Script#.  Both are basically doing the same thing, taking one language and compiling it down into another.  Then it really becomes a question of, which language would you rather write your abstracted JavaScript in C# or CoffeeScript?  The answer to this probably depends on what you are more comfortable with, but my main point is the two are conceptually the same. 

imageimage 

VS

image

 

Obviously the tooling behind C# is way more advanced, and all the good things that come with that like refactoring and intellisense.  The other benefit is that you don’t need to learn a new language (assuming you know C# already).   The main benefit I see with CoffeeScript is that it exposes the “Good Parts” of JavaScript a lot better than C# does, but if you know those good parts wouldn’t you prefer to write in plain ole JavaScript anyways?

So here is my takeaway, abstractions aren’t always a bad thing, as long as what is produced is of equal or better quality than you could do yourself.  With that in mind, I think both options are viable and will be for a long time to come, so go out and support the one that fits your style the most.

https://github.com/NikhilK/scriptsharp

https://github.com/jashkenas/coffee-script

Posted by Greg Roberts on Wednesday, May 04 2011 No Commentskick it on DotNetKicks.com Bookmark and Share

Tuesday, January 25 2011
Fixing the Asp.Net MVC 3 OutputCacheAttribute for Partial Views to Honor some web config settings

While working today I thought I would try out caching a partial view action in my controller.  Seems like an easy enough thing and was described as one of the nice new features of MVC 3 release.  I quickly ran into issues in my assumption of how this feature would work, and went to the Usual  Suspects for trying to figure out what happened.

Now lets get one thing out… The feature works, but it has a couple hidden gotchas that took a while to figure out.

Gotcha #1

The only supported options are Duration and VaryByParam.  This seems reasonable at first, but there is a big one missing which is CacheProfile.  Taken from the MSDN site itself, and I quote:

Using a Cache Profile

To avoid code duplication, you can set a cache profile in the Web.config file instead of setting cache values individually in pages. You can then reference the profile by using theCacheProfile property of the OutputCache attribute. The following example shows a section of a Web.config file that sets a cache profile. This cache profile will apply to all pages unless the page overrides these settings.

 

<system.web>
  <caching>
    <outputCacheSettings>
      <outputCacheProfiles>
        <add name="MyProfile" duration="60" varyByParam="*" />
      </outputCacheProfiles>
    </outputCacheSettings>
  </caching>
</system.web>
Seems like the right way to go, who would want to hard code all of those values in the attribute if you could modify them in the web.config... Sold.

If you try this in your controller on a partial view or “child action”, you will get a very nice error saying that the “Duration must be a positive number”. Um ok. 

Gotcha #2

When using this feature it will not honor the outputCache setting enableOutputCache. But Greg, didn’t you just say you wanted that controller cached, why would you turn it off?  Well in short, I want it all off in debug mode, but I want it enabled everywhere else.  This is perfect example of a setting you modify in a web.config transform.

What’s even more frustrating is that all these settings are enabled for normal controller actions, just not partial views.  Of course, I understand that there is a big difference, but you are using the same attribute.

 

Ok, Ok, so what do I do if I want to enable cacheprofiles and the enableOutputCache setting?  Well, crack open the MVC source and prepare for writing your own version of the OutputCacheAttribute…

I’m going to show just the changes that enable this setting, and then I’ll post the whole class for you.  Keep in mind some of the classes in the source were internal and so we had to copy those too.  If I had more time maybe this could be done a different way, but I just want it to work:

public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }
            var configSection = (OutputCacheSection)ConfigurationManager.GetSection("system.web/caching/outputCache");

            if (configSection.EnableOutputCache)
            {

                if (filterContext.IsChildAction)
                {
                 
                    ValidateChildActionConfiguration();
Here we are just adding the check if caching is enabled or not.

Next we will modify the validate configuration method:

private void ValidateChildActionConfiguration()
        {

            if (!String.IsNullOrWhiteSpace(CacheProfile))
            {
                var cacheSettings =
                    (OutputCacheSettingsSection)
                    ConfigurationManager.GetSection("system.web/caching/outputCacheSettings");
                if ((cacheSettings != null) && (cacheSettings.OutputCacheProfiles.Count > 0))
                {
                    var profile = cacheSettings.OutputCacheProfiles[CacheProfile];
                    if (profile == null)
                    {
                        throw new HttpException("Cache Profile Not found");
                    }
                    if (!string.IsNullOrWhiteSpace(profile.SqlDependency) ||
                        !String.IsNullOrWhiteSpace(profile.VaryByContentEncoding) ||
                        !string.IsNullOrWhiteSpace(profile.VaryByControl) ||
                        !String.IsNullOrWhiteSpace(profile.VaryByCustom) || profile.NoStore)
                    {
                        throw new InvalidOperationException("OutputCacheAttribute ChildAction UnsupportedSetting");
                    }
                    //overwrite the parameters
                    VaryByParam = profile.VaryByParam;
                    Duration = profile.Duration;
                }
                else
                {
                    throw new HttpException("Cache settings and profile not found");
                }
            }

            if (!String.IsNullOrWhiteSpace(SqlDependency) ||
                !String.IsNullOrWhiteSpace(VaryByContentEncoding) ||
                !String.IsNullOrWhiteSpace(VaryByHeader) ||
                _locationWasSet || _noStoreWasSet)
            {
                throw new InvalidOperationException("OutputCacheAttribute ChildAction UnsupportedSetting");
            }

            if (Duration <= 0)
            {
                throw new InvalidOperationException("Invalid Duration");
            }

            if (String.IsNullOrWhiteSpace(VaryByParam))
            {
                throw new InvalidOperationException("Invalid vary by param");
            }


        }
Key point here is that we first try to get the options from a profile if it is set, and if we don’t find it or it’s using unsupported attributes then we throw.

The other issue is that we reversed the checking for invalid properties followed by required properties, this was the main issue in the original source that would give you bad exceptions.


And here is the final class, now it still has the limitations of only allowing Duration and VaryByParam, but it allows the settings to be pulled from the web.config and most importantly it honors whether caching is on or not.

 

    [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "Unsealed so that subclassed types can set properties in the default constructor.")]
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
    public class CustomOutputCacheAttribute : ActionFilterAttribute, IExceptionFilter
    {

        private OutputCacheParameters _cacheSettings = new OutputCacheParameters { VaryByParam = "*" };
        private const string _cacheKeyPrefix = "_MvcChildActionCache_";
        private static ObjectCache _childActionCache;
        private Func<ObjectCache> _childActionCacheThunk = () => ChildActionCache;
        private static object _childActionFilterFinishCallbackKey = new object();
        private bool _locationWasSet;
        private bool _noStoreWasSet;

        public CustomOutputCacheAttribute()
        {
        }

        internal CustomOutputCacheAttribute(ObjectCache childActionCache)
        {
            _childActionCacheThunk = () => childActionCache;
        }

        public string CacheProfile
        {
            get
            {
                return _cacheSettings.CacheProfile ?? String.Empty;
            }
            set
            {
                _cacheSettings.CacheProfile = value;
            }
        }

        internal OutputCacheParameters CacheSettings
        {
            get
            {
                return _cacheSettings;
            }
        }

        public static ObjectCache ChildActionCache
        {
            get
            {
                return _childActionCache ?? MemoryCache.Default;
            }
            set
            {
                _childActionCache = value;
            }
        }

        private ObjectCache ChildActionCacheInternal
        {
            get
            {
                return _childActionCacheThunk();
            }
        }

        public int Duration
        {
            get
            {
                return _cacheSettings.Duration;
            }
            set
            {
                _cacheSettings.Duration = value;
            }
        }

        public OutputCacheLocation Location
        {
            get
            {
                return _cacheSettings.Location;
            }
            set
            {
                _cacheSettings.Location = value;
                _locationWasSet = true;
            }
        }

        public bool NoStore
        {
            get
            {
                return _cacheSettings.NoStore;
            }
            set
            {
                _cacheSettings.NoStore = value;
                _noStoreWasSet = true;
            }
        }

        public string SqlDependency
        {
            get
            {
                return _cacheSettings.SqlDependency ?? String.Empty;
            }
            set
            {
                _cacheSettings.SqlDependency = value;
            }
        }

        public string VaryByContentEncoding
        {
            get
            {
                return _cacheSettings.VaryByContentEncoding ?? String.Empty;
            }
            set
            {
                _cacheSettings.VaryByContentEncoding = value;
            }
        }

        public string VaryByCustom
        {
            get
            {
                return _cacheSettings.VaryByCustom ?? String.Empty;
            }
            set
            {
                _cacheSettings.VaryByCustom = value;
            }
        }

        public string VaryByHeader
        {
            get
            {
                return _cacheSettings.VaryByHeader ?? String.Empty;
            }
            set
            {
                _cacheSettings.VaryByHeader = value;
            }
        }

        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Param", Justification = "Matches the @ OutputCache page directive.")]
        public string VaryByParam
        {
            get
            {
                return _cacheSettings.VaryByParam ?? String.Empty;
            }
            set
            {
                _cacheSettings.VaryByParam = value;
            }
        }

        private static void ClearChildActionFilterFinishCallback(ControllerContext controllerContext)
        {
            controllerContext.HttpContext.Items.Remove(_childActionFilterFinishCallbackKey);
        }

        private static void CompleteChildAction(ControllerContext filterContext, bool wasException)
        {
            Action<bool> callback = GetChildActionFilterFinishCallback(filterContext);

            if (callback != null)
            {
                ClearChildActionFilterFinishCallback(filterContext);
                callback(wasException);
            }
        }

        private static Action<bool> GetChildActionFilterFinishCallback(ControllerContext controllerContext)
        {
            return controllerContext.HttpContext.Items[_childActionFilterFinishCallbackKey] as Action<bool>;
        }

        internal string GetChildActionUniqueId(ActionExecutingContext filterContext)
        {
            StringBuilder uniqueIdBuilder = new StringBuilder();

            // Start with a prefix, presuming that we share the cache with other users
            uniqueIdBuilder.Append(_cacheKeyPrefix);

            // Unique ID of the action description
            uniqueIdBuilder.Append(filterContext.ActionDescriptor.UniqueId);

            // Unique ID from the VaryByCustom settings, if any
            uniqueIdBuilder.Append(MyDescriptorUtil.CreateUniqueId(VaryByCustom));
            if (!String.IsNullOrEmpty(VaryByCustom))
            {
                string varyByCustomResult = filterContext.HttpContext.ApplicationInstance.GetVaryByCustomString(HttpContext.Current, VaryByCustom);
                uniqueIdBuilder.Append(varyByCustomResult);
            }

            // Unique ID from the VaryByParam settings, if any
            uniqueIdBuilder.Append(GetUniqueIdFromActionParameters(filterContext, SplitVaryByParam(VaryByParam)));

            // The key is typically too long to be useful, so we use a cryptographic hash
            // as the actual key (better randomization and key distribution, so small vary
            // values will generate dramtically different keys).
            using (SHA256 sha = SHA256.Create())
            {
                return Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(uniqueIdBuilder.ToString())));
            }
        }

        private static string GetUniqueIdFromActionParameters(ActionExecutingContext filterContext, IEnumerable<string> keys)
        {
            // Generate a unique ID of normalized key names + key values
            var keyValues = new Dictionary<string, object>(filterContext.ActionParameters, StringComparer.OrdinalIgnoreCase);
            keys = (keys ?? keyValues.Keys).Select(key => key.ToUpperInvariant())
                                           .OrderBy(key => key, StringComparer.Ordinal);

            return MyDescriptorUtil.CreateUniqueId(keys.Concat(keys.Select(key => keyValues.ContainsKey(key) ? keyValues[key] : null)));
        }

        public static bool IsChildActionCacheActive(ControllerContext controllerContext)
        {
            return GetChildActionFilterFinishCallback(controllerContext) != null;
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            // Complete the request if the child action threw an exception
            if (filterContext.IsChildAction && filterContext.Exception != null)
            {
                CompleteChildAction(filterContext, wasException: true);
            }
        }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }
            var configSection = (OutputCacheSection)ConfigurationManager.GetSection("system.web/caching/outputCache");

            if (configSection.EnableOutputCache)
            {

                if (filterContext.IsChildAction)
                {
                 
                    ValidateChildActionConfiguration();

                    // Already actively being captured? (i.e., cached child action inside of cached child action)
                    // Realistically, this needs write substitution to do properly (including things like authentication)
                    if (GetChildActionFilterFinishCallback(filterContext) != null)
                    {
                        throw new InvalidOperationException("Cannot nest child cache");
                    }

                    // Already cached?
                    string uniqueId = GetChildActionUniqueId(filterContext);
                    string cachedValue = ChildActionCacheInternal.Get(uniqueId) as string;
                    if (cachedValue != null)
                    {
                        filterContext.Result = new ContentResult() { Content = cachedValue };
                        return;
                    }

                    // Swap in a new TextWriter so we can capture the output
                    StringWriter cachingWriter = new StringWriter(CultureInfo.InvariantCulture);
                    TextWriter originalWriter = filterContext.HttpContext.Response.Output;
                    filterContext.HttpContext.Response.Output = cachingWriter;

                    // Set a finish callback to clean up
                    SetChildActionFilterFinishCallback(filterContext, wasException =>
                    {
                        // Restore original writer
                        filterContext.HttpContext.Response.Output = originalWriter;

                        // Grab output and write it
                        string capturedText = cachingWriter.ToString();
                        filterContext.HttpContext.Response.Write(capturedText);

                        // Only cache output if this wasn't an error
                        if (!wasException)
                        {
                            ChildActionCacheInternal.Add(uniqueId, capturedText, DateTimeOffset.UtcNow.AddSeconds(Duration));
                        }
                    });
                }
            }
        }

        public void OnException(ExceptionContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            if (filterContext.IsChildAction)
            {
                CompleteChildAction(filterContext, wasException: true);
            }
        }

        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            if (!filterContext.IsChildAction)
            {
                // we need to call ProcessRequest() since there's no other way to set the Page.Response intrinsic
                using (OutputCachedPage page = new OutputCachedPage(_cacheSettings))
                {
                    page.ProcessRequest(HttpContext.Current);
                }
            }
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            if (filterContext.IsChildAction)
            {
                CompleteChildAction(filterContext, wasException: filterContext.Exception != null);
            }
        }

        private static void SetChildActionFilterFinishCallback(ControllerContext controllerContext, Action<bool> callback)
        {
            controllerContext.HttpContext.Items[_childActionFilterFinishCallbackKey] = callback;
        }

        private static IEnumerable<string> SplitVaryByParam(string varyByParam)
        {
            if (String.Equals(varyByParam, "none", StringComparison.OrdinalIgnoreCase))
            {  // Vary by nothing
                return Enumerable.Empty<string>();
            }

            if (String.Equals(varyByParam, "*", StringComparison.OrdinalIgnoreCase))
            {  // Vary by everything
                return null;
            }

            return from part in varyByParam.Split(';'// Vary by specific parameters
                   let trimmed = part.Trim()
                   where !String.IsNullOrEmpty(trimmed)
                   select trimmed;
        }

        private void ValidateChildActionConfiguration()
        {

            if (!String.IsNullOrWhiteSpace(CacheProfile))
            {
                var cacheSettings =
                    (OutputCacheSettingsSection)
                    ConfigurationManager.GetSection("system.web/caching/outputCacheSettings");
                if ((cacheSettings != null) && (cacheSettings.OutputCacheProfiles.Count > 0))
                {
                    var profile = cacheSettings.OutputCacheProfiles[CacheProfile];
                    if (profile == null)
                    {
                        throw new HttpException("Cache Profile Not found");
                    }
                    if (!string.IsNullOrWhiteSpace(profile.SqlDependency) ||
                        !String.IsNullOrWhiteSpace(profile.VaryByContentEncoding) ||
                        !string.IsNullOrWhiteSpace(profile.VaryByControl) ||
                        !String.IsNullOrWhiteSpace(profile.VaryByCustom) || profile.NoStore)
                    {
                        throw new InvalidOperationException("OutputCacheAttribute ChildAction UnsupportedSetting");
                    }
                    //overwrite the parameters
                    VaryByParam = profile.VaryByParam;
                    Duration = profile.Duration;
                }
                else
                {
                    throw new HttpException("Cache settings and profile not found");
                }
            }

            if (!String.IsNullOrWhiteSpace(SqlDependency) ||
                !String.IsNullOrWhiteSpace(VaryByContentEncoding) ||
                !String.IsNullOrWhiteSpace(VaryByHeader) ||
                _locationWasSet || _noStoreWasSet)
            {
                throw new InvalidOperationException("OutputCacheAttribute ChildAction UnsupportedSetting");
            }

            if (Duration <= 0)
            {
                throw new InvalidOperationException("Invalid Duration");
            }

            if (String.IsNullOrWhiteSpace(VaryByParam))
            {
                throw new InvalidOperationException("Invalid vary by param");
            }


        }

        private sealed class OutputCachedPage : Page
        {
            private OutputCacheParameters _cacheSettings;

            public OutputCachedPage(OutputCacheParameters cacheSettings)
            {
                // Tracing requires Page IDs to be unique.
                ID = Guid.NewGuid().ToString();
                _cacheSettings = cacheSettings;
            }

            protected override void FrameworkInitialize()
            {
                // when you put the <%@ OutputCache %> directive on a page, the generated code calls InitOutputCache() from here
                base.FrameworkInitialize();
                InitOutputCache(_cacheSettings);
            }
        }
    }

    internal static class MyDescriptorUtil
    {

        private static void AppendPartToUniqueIdBuilder(StringBuilder builder, object part)
        {
            if (part == null)
            {
                builder.Append("[-1]");
            }
            else
            {
                string partString = Convert.ToString(part, CultureInfo.InvariantCulture);
                builder.AppendFormat("[{0}]{1}", partString.Length, partString);
            }
        }

        public static string CreateUniqueId(params object[] parts)
        {
            return CreateUniqueId((IEnumerable<object>)parts);
        }

        public static string CreateUniqueId(IEnumerable<object> parts)
        {
            // returns a unique string made up of the pieces passed in
            StringBuilder builder = new StringBuilder();
            foreach (object part in parts)
            {
                // We can special-case certain part types

                MemberInfo memberInfo = part as MemberInfo;
                if (memberInfo != null)
                {
                    AppendPartToUniqueIdBuilder(builder, memberInfo.Module.ModuleVersionId);
                    AppendPartToUniqueIdBuilder(builder, memberInfo.MetadataToken);
                    continue;
                }

                ICustomUniquelyIdentifiable uniquelyIdentifiable = part as ICustomUniquelyIdentifiable;
                if (uniquelyIdentifiable != null)
                {
                    AppendPartToUniqueIdBuilder(builder, uniquelyIdentifiable.UniqueId);
                    continue;
                }

                AppendPartToUniqueIdBuilder(builder, part);
            }

            return builder.ToString();
        }

        public static TDescriptor[] LazilyFetchOrCreateDescriptors<TReflection, TDescriptor>(ref TDescriptor[] cacheLocation, Func<TReflection[]> initializer, Func<TReflection, TDescriptor> converter)
        {
            // did we already calculate this once?
            TDescriptor[] existingCache = Interlocked.CompareExchange(ref cacheLocation, null, null);
            if (existingCache != null)
            {
                return existingCache;
            }

            TReflection[] memberInfos = initializer();
            TDescriptor[] descriptors = memberInfos.Select(converter).Where(descriptor => descriptor != null).ToArray();
            TDescriptor[] updatedCache = Interlocked.CompareExchange(ref cacheLocation, descriptors, null);
            return updatedCache ?? descriptors;
        }

    }

    internal interface ICustomUniquelyIdentifiable
    {
        string UniqueId { get; }
    }

Posted by Greg Roberts on Tuesday, January 25 2011 No Commentskick it on DotNetKicks.com Bookmark and Share

Thursday, January 20 2011
WPF ItemsControl and Operation is not valid while ItemsSource is in use…

See anything wrong with the following XAML:

<ItemsControl ItemsSource="{Binding GridColumns}" Grid.Row="1" Grid.Column="0">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Button Margin="0,14" Height="22" >
                                <TextBlock TextAlignment="Center" Text="{Binding Name}"></TextBlock>
                                <i:Interaction.Triggers>
                                    <i:EventTrigger EventName="Clicked">
                                        <n:ExecuteCommandAction Command="{Binding HighlightColumn}" Parameter="{Binding Index}" />
                                    </i:EventTrigger>
                                </i:Interaction.Triggers>
                            </Button>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal"  >
                        </StackPanel>
                    </ItemsPanelTemplate>
  </ItemsControl
>

Yeah I didn’t see it initially either, but if you run this you will get an error indicating that you are trying to modify the source collection.  Look closely at the ItemsPanelTemplate, while the syntax is correct it needs to be wrapped in ItemsControl.ItemsPanel.  Since it isn’t it treats that statement as an item and tries to add it to the collection.  The corrected Xaml is as follows:


                <ItemsControl ItemsSource="{Binding GridColumns}" Grid.Row="1" Grid.Column="0">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Button Margin="0,14" Height="22" >
                                <TextBlock TextAlignment="Center" Text="{Binding Name}"></TextBlock>
                                <i:Interaction.Triggers>
                                    <i:EventTrigger EventName="Clicked">
                                        <n:ExecuteCommandAction Command="{Binding HighlightColumn}" Parameter="{Binding Index}" />
                                    </i:EventTrigger>
                                </i:Interaction.Triggers>
                            </Button>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Horizontal"  />
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl
>

Posted by Greg Roberts on Thursday, January 20 2011 No Commentskick it on DotNetKicks.com Bookmark and Share

Wednesday, January 12 2011
Diagnosing Asp.Net Forms Authentication ticket failure on IIS 7 web farm

Have you gotten this error on a web farm sharing forms authentication recently?

Forms authentication failed for the request. Reason: The ticket supplied was invalid

Normally this is a no-brainer, just make sure you have the same machine key settings across servers, but recently I ran into this while setting up a new server and was honestly befuddled for an hour trying to figure out what I had missed.  After scouring the back alley’s of google-bing, I finally hit on the right keyword mojo and found this nugget on stackoverflow.com.  You remember that security vulnerability found last fall, yeah forgot about that one too, well I guess one of the side effects of the patch was that un-patched  servers don’t play nice with each other.   Here is a quote from the Gu himself that explains it clearly:

Because the patch modifies the encryption/signing behavior of certain features in ASP.NET, it is important that you apply it to all machines in a web-farm.  If you have a mix-match of patched/un-patched systems you’ll have forms-authentication, webresource.axd, and scriptresource.axd requests succeed/fail depending on which server they hit in the farm (since the encryption used would be different across them).

So what are you waiting for, go patch that server!

Posted by Greg Roberts on Wednesday, January 12 2011 No Commentskick it on DotNetKicks.com Bookmark and Share

Friday, November 05 2010
My Initial Thoughts on Xbox 360’s Kinect

I got my Kinect today and thought I would share my initial thoughts.  First off the packaging was actually really nice.  It’s funny on how much thought and design goes into something that you really only use for a minute and then throw away.  I think a lot of this comes from how Apple packages its products and has become somewhat of an industry benchmark.  It definitely sets the stage and makes you feel good about your $150 purchase.

photo

Setup:

The instructions were clear enough, the biggest things were to keep it centered under your TV, don’t put in front of a speaker and don’t put it too high (over 6 feet).  The device connects via USB, and if you have an original Xbox then you’ll need to also use an attached power supply.  If you have the newer Xbox S then this is not needed.

Upon first startup you are first asked to download an update, then you are walked through some initial setup.  The process is pretty simple and all seems to work rather magically.  One of the things that you are shown is how to interact with the Dashboard and other menus.  You are now allowed to go into a “Kinect” mode and browse some Kinect specific menus and applications.  I’m assuming this will grow, but the new ESPN experience is here as well as last.fm and some other goodies like Kinect video.

One of the first things I noticed when using Kinect is that it doesn’t require a whole lot of distance between you and the device, which I was worried about since I live in a condo and space is rather limited.  The other thing was just how smooth the transitions are between it recognizing you and you walking away.  It mostly feels natural and doesn’t get in your way or annoy you at all.  It’s not like you need to hold down a button and say “I’m here”, you basically just walk in the view and wave and you’re up and running.

I will say at the point that I was moving through the dashboard I felt a bit like Tom Cruise in Minority Report.image As a developer my mind was already off dreaming of how a nice .NET SDK around this thing would change a lot in application interfaces.  I now feel a bit disappointed by everything on my TV that I can’t control with simple gestures.  Microsoft needs to keep pushing this and compete with Apple and Google in the TV software interface battle.  If they allowed this as a way to change the channel and volume, I’m sold…

 

Games:

image Kinect Adventures is the “Wii Sports” of the Kinect, but I will say Wii Sports looks like child's play compared to this.  First off the game play is fast and fun and it gets you started with no real up front coaching.  Before you know it you’ll be sweating and giggling like a little girl.  It actually took me a while to realize that I could actually use my feet and not just my hands to do a lot of the maneuvers.  This game is definitely worth your investment and a great intro to the franchise.

 

image Dance Central was the other game that I purchased, on my wife’s request.  This was good but definitely a couple of notches down from Adventures.  First off, it’s really a 1 player game because the 2 player modes force you to take turns.  This is almost enough reason for me to give this a no vote, but once you get into it its still pretty fun.  You aren’t going to become Usher any time soon, but you may pick up some moves worth busting out at a friend’s wedding.  Overall the experience isn’t as good, but I got to think any game with Kinect is still so novel and fun right now that it won’t really matter.

 

Conclusion:

I was initially worried that there was going to be a gotcha with the system and what it could detect or that the games would be lame, but I will say right now that it is pretty magical.  Take what you felt the first time you played Wii and then multiply that times 5.  It just feels natural and the interface is very graceful and just detects when you come and go and doesn’ make a stink or hiccup during the transitions.
The only negative complaint I have was that through my entire experience I think I had to download 8 different updates. One for each game, one for the Kinect, and one for each application you wanted to interact with like the ESPN experience. I just wish this would just happen and not ask me each time, I mean what am I gonna do, not update?

Posted by Greg Roberts on Friday, November 05 2010 No Commentskick it on DotNetKicks.com Bookmark and Share

Sunday, October 17 2010
The Secrets of Creating a Animated Splash Screen In WPF

I come to this post a little relieved, but still frustrated enough that I felt like I needed to share my problem and solution.  In short, frustration + google/bing fail + eventual win = blog post.

Setup: I’ve been working on a WPF app, which just so happens to be my first “real” WPF app (I usually do web development), and I wanted to simply embed the version number on our splash image.  For those of you not familiar, in WPF having a splash image appear while your app is being loaded is as simple as right clicking on an image and setting it’s build action to “SplashScreen”.  At least I believe it’s been that easy since WPF 3.5 SP1 release. 

Now you might say, “Greg, this is awesome why would you ever be frustrated with such a simple solution?”.  Alas in life, as with programming, nothing is ever simple.  Yes this solution works, but most of the time a static image probably won’t fulfill all your requirements, and telling your boss “well that’s not possible” won’t earn you any points.  Frankly, it’s also plain lazy too.

  I call these types of features from Microsoft, the MRE’s of development.  MREFor those of you not familiar, MRE stands for “Meal Ready-to-Eat” and is used to feed soldiers in the US military in the field.  The reason I make the comparison is that any normal person would probably only use the MRE when there was no other suitable food to be had, or when time was a substantial factor. 

The same is true with a lot of  development features as well.  If you just need a quick fix and don’t need a lot of extra fluff then the splash screen feature is great, but now if you want some animations and some dynamic text then the pre-fab solution no longer works.  Here is a list of things that you cannot do with the built-in solution:

  • It does not actually improve application cold startup time.
  • Cannot display sequence of splash images or animation.
  • Does not support for animated GIFs
  • Does not have XAML support for setting splash screen image
  • Expression Blend does not provide UI to set the SplashScreen build action

Now my solution isn’t going to improve startup time either, it might actually slow it down a bit, but I’m not interested in shaving milliseconds on this, I’m interested in improving the app experience.

Enough talk, here is what you need to do to enable full XAML support in a startup screen without changing too much of your app:

  1. You may have noticed that in .NET 4, there is actually no apparent “Main” method in your code.  This is because it is now designer generated for you.  So Step 1 is to remove some of this auto-generation by editing the build action of your App.xaml file from “Application Definition” to “Page”.
  2. You need to create a new App entry point, either by creating a separate class or by adding it to your App.xaml.cs file. Add a Main method like the following:
          [System.STAThreadAttribute()]
          public static void Main()
           {
  3. Now you are back in control of your application and you can create your WPF Window that you want to use as your Splash page and make sure the following properties are set in your XAML:
           ShowInTaskbar="False"         ResizeMode="NoResize"         WindowStartupLocation="CenterScreen"         WindowState="Normal"         WindowStyle="None"         Background="Transparent"         AllowsTransparency="True" 

    These aren't really all necessary, but this will give you behavior similar to what you got for free.

  4. We need to show this window during startup, and the most important part is to give this window a separate UI thread from your main App. Otherwise, things will get nasty.

     

         private static void Main()
         {
             ResetSplashCreated = new ManualResetEvent(false);
             SplashThread = new Thread(ShowSplash);
             SplashThread.SetApartmentState(ApartmentState.STA);
             SplashThread.IsBackground = true;
             SplashThread.Name = "Splash Screen";
             SplashThread.Start();
    
             ResetSplashCreated.WaitOne();
    
             var app = new App(SplashWindow);
             app.InitializeComponent();
             app.Run();
         }
    
          private static void ShowSplash()
          {
             SplashWindow = new SplashWindow();
             SplashWindow.Show();
             ResetSplashCreated.Set();
             System.Windows.Threading.Dispatcher.Run();
          }
    This might be a lot to take in, but essentially what I’m doing is creating a new thread and making it’s ApartmentState to be STA (single threaded) and telling the Dispatcher to Run.  This threading technique is nothing new, but for more info see here.  Essentially you need a separate dispatcher for this window compared to your actual app’s window.  Now you have two windows running on separate threads.
  5. The last part to the puzzle  is communicating to the splash screen and also properly closing it when you are ready. You may have noticed I passed in a reference of the SplashWindow to the App.  My app was actually just looking for an interface, but it turns out that my splash window implements that interface.  Here is what it looks like:

     

    public interface IApplicationLoading {
        void AddMessage(string message);
        void PercentComplete(int current);
        void LoadComplete();

    Now there is nothing special here and this is really up to you how complicated you want to get with communicating, essentially I'm just saying somehow you need to update status on the splash window and essentially tell it to close. This could be done tons of ways. On the window side you will want to make sure all calls are done on the dispatcher and that you shut yourself down when told.

    public void LoadComplete()
    {
                Dispatcher.InvokeShutdown();
     }
  6. Finally make sure that you clean up references and be sure to test and see if the thread actually gets dropped after startup.

For extra credit you can combine this with Danial Vaughan's Single Instance App Enforcer if you need to guarantee 1 instance on a machine running at a time.

Hopefully this helps anyone that needs to easily add this functionality, and as always this is just one of many solutions that are out there, but it’s the one that I ended up using.

Posted by Greg Roberts on Sunday, October 17 2010 No Commentskick it on DotNetKicks.com Bookmark and Share

Tuesday, May 25 2010
Asp.net MVC 2 with JSONP and jQuery

I’m willing to bet as a web developer there will be some project that you are working on that requires you to expose your data and or services across domain boundaries through an REST API and want them to be called via javascript.  Maybe you wrote a jQuery plugin that retrieves data from your site, or maybe you have several domains that share the same services.  Whatever the reason is, you will quickly discover the browser same-origin policy, which states “a web page served from domain1.com cannot normally connect to or communicate with a server other than domain1.com”.

Fortunately there is a way around this.  It’s called JSONP or “JSON with padding”.  To summarize,  JSONP works around the cross-domain browser restriction by making a GET request using a script tag, which isn’t limited by the same-origin policy.  It traditionally will also provide a callback method in the url so the response from the server will look something like this:

callback({"title": "hello world!", "rank": "number 1"})

This call is then executed, and voila you have your data.  Now the complexity of how to do this in JavaScript is masked by most JavaScript libraries, like jQuery.  I’m going to focus on how you enable this in Asp.net MVC 2.

  • The first thing you need is the ability for your controller to return JSON or JSONP base on the request. As far as I know, there is not an out of the box JSONP Action Result in MVC, so we will create one.
       public class JsonpResult<T> : ActionResult where T : class, new()
       {
         
           public const string DefaultJqueryCallbackParameter = "callback";
           private string callbackParameter;
           private bool useDataContract = false;
           private bool useDefaultCallback = true;
           
           #region Constructors
    
           public JsonpResult(T data, bool useDefaultCallbacks, bool useDataContract)
           {
               this.Data = data;
               this.useDefaultCallback = useDefaultCallbacks;
               this.useDataContract = useDataContract;
           }
    
           public JsonpResult(T data, string callbackParamter) : this(data, callbackParamter, false)
           {           
           }
    
           public JsonpResult(T data, string callbackParamter, bool useDataContract)
           {
               this.Data = data;
               this.callbackParameter = callbackParamter;
               this.useDefaultCallback = false;
           }
    
           public JsonpResult(T data) : this(data, true, false)
           {
           }
    
          
    
           #endregion Constructors
    
           #region Properties
    
           public Encoding ContentEncoding { get; set; }
    
           public string ContentType { get; set; }
    
           public T Data { get; set; }
    
           public JsonRequestBehavior JsonRequestBehavior { get; set; }
    
           public bool UseDataContractSerialization
           {
               get { return useDataContract; }
               set { useDataContract = value; }
           }
    
           #endregion Properties
    
           #region Methods
    
           public override void ExecuteResult(ControllerContext context)
           {
               if (context == null)
               {
                   throw new ArgumentNullException("context");
               }
    
               HttpResponseBase response = context.HttpContext.Response;
    
               if (!String.IsNullOrEmpty(ContentType))
               {
                   response.ContentType = ContentType;
               }
               else
               {
                   response.ContentType = "application/json";
               }
    
               if (ContentEncoding != null)
               {
                   response.ContentEncoding = ContentEncoding;
               }
    
               if (Data != null)
               {
    
                   HttpRequestBase request = context.HttpContext.Request;
                   var jsonp =  IsJsonp(request.Params);
                   if(jsonp.Item1)
                   {
                       this.JsonRequestBehavior = JsonRequestBehavior.AllowGet; //this is new in MVC 2 otherwise an error will be thrown                    
                       response.Write(jsonp.Item2 + "(" + Data.ToJSON(useDataContract) + ")");                    
                   }                
                   else
                   {
                       //normal json here
                       response.Write(Data.ToJSON(useDataContract));
                   }
    
               }
           }
    
           private Tuple<bool, string> IsJsonp(NameValueCollection parameters)
           {                     
               if (useDefaultCallback && parameters[DefaultJqueryCallbackParameter] != null)
               {
                   return new Tuple<bool, string>(true, parameters[DefaultJqueryCallbackParameter]);
               }
               else if(!string.IsNullOrEmpty(callbackParameter) && null !=  parameters[callbackParameter] ){
                   return new Tuple<bool,string>(true, parameters[callbackParameter]);
               }
               return new Tuple<bool,string>(false, string.Empty);            
                   
           }
    
           #endregion Methods
       }
  • The real meat of the class is where we write out the JSON result to the response object with it wrapped in the callback function:
    response.Write(jsonp.Item2 + "(" + Data.ToJSON(useDataContract) + ")");    
  • Notice there is also a line there that changes the JSonRequestBehavior settings to AllowGet.  If we don’t do this then MVC 2 will barf on the response because of a known security vulnerability with GET requests and JavaScript arrays (more info here).  
  • I’m also using some JSON serialization extension methods that make serializing a bit simpler.    Here is the source for ToJSON, it takes a boolean which indicates whether you want the DataContractJsonSerializer or JavaScriptSerializer.  Each has it’s own benefits.
public static string ToJSON<T>(this T o, bool useDataContract) where T : class, new()
{
    string json = "";
    if (useDataContract)
    {
        var serializer = new DataContractJsonSerializer(typeof(T));

        using (var ms = new MemoryStream())
        {
            serializer.WriteObject(ms, o);
            json = Encoding.Default.GetString(ms.ToArray());
            ms.Close();
        }
    }
    else
    {
        var serializer = new JavaScriptSerializer();
        json = serializer.Serialize(o);

    }

    return json;
}

Finally all you need to do to use this new action result is pass it your data and other options you care about.  By default, it will use JavaScriptSerializer with the jQuery default callback name.

return new JsonpResult<SampleSiteInfoModel>(model);

Test:  To test that JSONP does in fact work across domains, use jsfiddle.net , my new favorite JavaScript test site, and point it at your local services.  In the sample app on codeplex there is a link to the fiddle that I created at the bottom of the master page.  Or you can look at it here, http://jsfiddle.net/FSnpp/1/.  To do the request  in jQuery, just change the Ajax options parameter dataType to ‘jsonp’ or use getJSON and add the callback parameter manually.

Important: The implementation of JSONP in jQuery is not without some flaws, one being it doesn’t raise errors when timeouts or error responses are given.  Fortunately there is a plugin that handles that for you.  I recommend looking at it if you get serious in consuming JSONP.  http://code.google.com/p/jquery-jsonp/

Note:  It the action result will default to just returning regular JSON if a callback parameter can’t be found in the request.  This means you can use this instead of the JsonResult for even normal requests and they will automatically handle JSONP.

Source: Full Source and Demo is available on Codeplex

Posted by Greg Roberts on Tuesday, May 25 2010 No Commentskick it on DotNetKicks.com Bookmark and Share

Tuesday, February 16 2010
Ramblings on Windows Mobile 7 Development

<Rambling>

Unless you live under a rock, you’ve probably heard of the announcement from Microsoft about Windows Mobile Series 7.  It’s already getting rave reviews from the tech-journalists and I think the warm reception that both the Zune interface and Xbox UI have gotten have more or less proven that this is going to be successful.  It’s not like this is really new, but more of a maturation of seeds that were planted a while ago. 

As a follower of most things tech and as a .NET developer, I can’t say that I’m really surprised.  For all the haters out there and all the people that love their iPods, iPads, and iLife, and to the open source town criers the negative nancies and googlebators out there, you’ve missed something.  While you were all mouthing away at forums and making your sarcastic comments, slobbering over the latest google lab and overwhelmed with the delicious android pastry excitement, all the while announcing the death of the old blue machine.  Something happened. 

Yes while you were away, sometime between when you left Win XP and laughed at Vista.  Microsoft actually turned itself around one step at a time. You could see it in Xbox live, you could develop it with WPF and Linq, you touched it with Surface. There was Zune and Windows 7, Silverlight, Bing and Azure, there was also unprecedented openness in blogs and actual open source hosting on codeplex, which hosts Microsoft and community source. Slowly release after release, like a mature fighter delivering body blows, they had turned around and were on the right path and things were snowballing in their favor. 

Now don’t get me wrong, unlike a lot of people, I like apple, google, microsoft, and linux all at the same time.  It’s simple,  I just like technology.  To me, each has it’s strengths, apple has revolutionized simple UI, google redefined the web, linux is the backbone of science and so many other industries, and microsoft well they walk the road between them all.  It’s the competition and the ideologies of them all the make up a really healthy competitive environment.  Unlike our government, most issues are more than 2 sided and these entities each bring to the table their own ideas and feed off each other to continually evolve the ecosystem.

So, no I’m not surprised about them not giving up on mobile and actually showing up to the party with their own twist on things.  What I think people will underestimate, and what is Microsoft’s greatest strength, is it’s access to developers and its ability to make first class developer tools and environments.  Trust me, if Apple cared as much about developers as Microsoft did then it would be different.  You can’t honestly tell me that objective-c is a modern language compared to C# or Java.  I know it’s lower level, but it’s an absolute pain, and their tools don’t make it any better.  I think if you really sat down a obj C developer in front of Visual Studio or Eclipse they might crap their pants at how much more advanced these tools and languages are.

All this being said, when there’s a will there’s a way, and when a platform is popular like the iPhone is.  Developers will make it happen.  Tools and languages aside, it doesn’t really matter, but when you take a first class development experience along with a revolutionary platform than I say watch out.  Yes there will be fart apps a plenty, but businesses will show up en mass.  That is the difference.  iPhone and to a lesser extent android is missing the ease of creating biz apps and that is where Microsoft will shine.

If you follow .NET development at you can see the perfect storm brewing.  Look at what is coming out, .NET 4.0, Azure, Silverlight 4.0, and XNA.  I think these will all play a roll in Windows Mobile 7 development.  I’m not sure whether or not Silverlight or WPF will be the main delivery mechanism or not for app development, but it’s possible.   I do know that there are a lot of existing Zune and other Xbox Live XNA games that will probably be easily ported.  We’ll see how it all is fleshed out at mix in a couple of weeks.  My prediction is that developers will finally get a first class mobile development experience and that is what will tip the scale if the platform and hardware meet expectations.

</Rambling>

Posted by Greg Roberts on Tuesday, February 16 2010 No Commentskick it on DotNetKicks.com Bookmark and Share

Saturday, February 13 2010
Salesforce.com bails on Internet Explorer

There is a growing trend among popular websites to end support for Internet Explorer 6 once and for all.  It’s actually something that’s been going on for awhile now and any web developer will tell you its about time.  The difference is now the big boys are doing it.  Some big companies that have started are:

  • Youtube: which now informs you that your browser sucks and recommends one of the latest ones and is predicted to drop support all together.

image

There are even sites out there with a single purpose of spreading the word to kill IE 6 usage:

Up until recently I thought this was just a bunch of tech sites complaining and that the mainstream B2B sites would still have to labor on supporting the bastard child of browsers.  That is until I got the following email….


 

Dear Customer,

At salesforce.com, seamless upgrades are a top priority, and we strive to provide open communication whenever we make changes that may impact our customers. You are receiving this email because we have identified you as system administrator for a Salesforce.com organization that will be impacted by an upcoming change to our support policy for Microsoft Internet Explorer 6.0 (IE6).  We have identified that one or more users in your organization logged into salesforce.com using IE6 between September 2009 and December 2009.

What is the change?

With the Spring '10 release, salesforce.com will begin delivering features that will not be supported for use with IE6, including our new user interface theme.  In subsequent releases throughout 2010, we may release additional features and UI enhancements that will also not be supported on IE6.  This is all in preparation for a full de-support of IE6, which is tentatively planned for end of calendar year 2010.

Why is salesforce.com doing this?

There are several reasons we are ending support for IE6:

  • IE6 is less secure.  Multiple security vulnerabilities in IE6 have been exploited over the years.  The most recent attacks against Google, Yahoo, and other companies specifically targeted vulnerabilities easily accessible in IE6 but much more difficult to exploit in IE7 and IE8—leading the Microsoft Security Response Center to recommend that users of IE6 upgrade to a newer version of Internet Explorer.
  • IE6 is slow.  Of all of our supported browsers, IE6 provides the slowest and least rewarding user experience for our customers.
  • IE6 is a “last generation” browser.  IE6 was first released in August 2001.  As an obsolete, non-standard platform, IE6 is a difficult browser on which to develop and support the rich internet applications our customers have come to expect.

What action do I need to take?

You and your company's IT administrators should plan and/or upgrade your users to IE7, IE8, or another supported browser by the end of calendar year 2010

What will happen if I take no action?

Your organization can continue to use IE6 in the Spring '10 release. However, beginning with the Spring '10 release, salesforce.com will make available several new opt-in features that are not supported on IE6.  Your organization has the option of leaving these features inactive until you have upgraded to a supported browser.

How can I get more information?

Please contact salesforce.com Customer Support with any questions you may have.

Best regards,
Salesforce Customer Support
support@salesforce.com


Salesforce.com, which is probably one of the biggest websites for businesses, is dropping support for IE6 and they actually took a couple cheap shots as they kicked IE out the door.  Some highlights:

  • Slow
  • last generation
  • obsolete
  • non-standard
  • difficult
  • Slowest and least rewarding user experience

As I don’t really disagree with any of these statements, I do think it’s sort of a kick in the pants for a browser that is almost 9 years old and one that was never built to handle modern websites. 

The blame can probably fall on the shoulders of Microsoft for not being more aggressive about encouraging users to upgrade, but also on the web community for not urging it’s uninformed users about what they are missing out on.  Imagine someone like my mother who has a hand-me-down laptop with Windows XP on it that seems to work fine for her needs.  How is she supposed to know that her browser sucks?  Luckily she has me, so when I come home for Xmas I set the situation straight, but not everyone has me for a son.  We need to do better about understanding our audience and informing them without insulting their lack of tech prowess. 

Posted by Greg Roberts on Saturday, February 13 2010 No Commentskick it on DotNetKicks.com Bookmark and Share

Friday, December 11 2009
Graffiti CMS finally gets some love

After over a year of complaints and failed promises by Telligent, the once loved and recently hated, Graffiti CMS, has finally gone open source (Official Press Release).  Believe me there was a huge amount of frustration gaining over this product, mostly for its owners utter lack of communication and upkeep (telligent).  And I should know, you are reading this from an officially licensed site…

I think a lot of my frustration is that this was a great example of a simple Asp.Net app that just worked and was well designed.  It was theme ready and plug-in ready from the start and even has a simple scripting interface, oh my.    To this day, even with the advent of Asp.net MVC and several open source projects (1, 2 ) on codeplex, I haven’t seen a comparable free or pay .Net blog engine that offers the same features and ease of use.

Here are some screen grabs of the admin interface:

image

 

image

Overall it is just a solid UI with a lot of good concepts going for.  Now I do cringe a bit since this was written before Asp.net MVC and I believe that could ultimately lead to its death in my mind, but I do think that with some effort it could be raised from the ashes and resurrect itself as “the” Asp.Net blogging engine of choice.  If anything it’s a great opportunity to look at some nice coding ideas and design.

Posted by Greg Roberts on Friday, December 11 2009 No Commentskick it on DotNetKicks.com Bookmark and Share

  • Menu

  • Tags