jvance.com

.net, c#, asp.net, linq, htpc, woodworking

Jarrett's Tech Blog - Browsing ASP.NET

  1. Simple Fix for ASP.NET FormsAuthentication Redirect when using AJAX

    There is one paticular annoying "feature" of ASP.NET forms authentication module that has kicked my butt many times. When a user loads a page but their session has expired, the module will take over the request and return a 302 redirect to the login page rather than the appropriate 401 unauthorized.

    Specification of the correct behaviour has been part of the HTTP standard for more than 15 years now. HTTP 1.1, RFC 2616 (and before that, HTTP 1.0, RFC 1945) specify the correct behavior in sections 10.4.2 and 9.4 respectively (the verbiage hasn't changed significantly):

    This "feature" has always been broken in ASP.NET and it has caused me countless hours of research and workarounds. Others have also dealt with the problem:

    Back in 2008, I used the  HttpModule workaround as decribed in many of the above posts. I've also utilized an Application_OnError workaround. Unfortunately, many of these solutions require too much code, additional config, and/or tradeoffs.

    I would prefer a fix directly to forms authentication, but Microsoft still hasn't addressed the problem. We could replace forms authentication with something like AppHarbor.Web.Security or MADAM. However, this can be scary to those who are unfamiliar with exercising options outside of those provided by Microsoft.

    So that brings me to point of this post. How can we KISS and still fix the damn problem?

    Add this to Global.asax.cs to fix the broken FromsAuthentication redirect behavior. This code will reset the 302 back to 401 for AJAX requests.

    protected void Application_EndRequest()
    {
        var context = new HttpContextWrapper(this.Context);
    
        // If we're an ajax request and forms authentication caused a 302, 
        // then we actually need to do a 401
        if (FormsAuthentication.IsEnabled && context.Response.StatusCode == 302 
            && context.Request.IsAjaxRequest())
        {
            context.Response.Clear();
            context.Response.StatusCode = 401;
        }
    }
    

    Add this javascript to your layout so that anytime you use jQuery ajax, get, or post, the client will detect the 401 and reload the page. This will cause the browser to redirect to login page.

    $(document).ajaxError(function (xhr, props) {
      if (props.status === 401) {
        location.reload();
      }
    });
    

    That's all. Problem fixed with very few lines of code.

    Posted by JarrettV on September 21 at 5:39 AM

  2. ASP.NET MVC Bundling of Bootstrap Less Source

    Our team is utilizing bootstrap for our MVC application. We would like to be able to update the variables.less file and have the entire "theme" of the website updated.

    The typical methods are:

    • Utilize a tool (Chirpy in Visual Studio) to automatically output css anytime the less file is updated
    • Transform the less on the server side

    I prefer the second approach since:

    • It doesn't depend on everyone having the same tool setup
    • You don't have worry about versioning of the code generated files

    The most popular library dotless utilizes HttpHandlers to translate the less to css on the server side. This requires extra configuration in the web.config.

    However, the latest version of ASP.NET MVC, version 4, has support for bundling and minification. It also supports transforms.

    The asp.net article shows a few simple lines of code to add a transform for less files.

    using System.Web.Optimization;
    
    public class LessTransform : IBundleTransform
    {
        public void Process(BundleContext context, BundleResponse response)
        {
            response.Content = dotless.Core.Less.Parse(response.Content);
            response.ContentType = "text/css";
        }
    }
    

    Unfortunately, this method only supports simple less files. If there are any imports, like in bootstrap, the application will throw a FileNotFoundException.

    {"You are importing a file ending in .less that cannot be found.":"reset.less"}

    We need to be able to tell the parse method where to find the imported files. You can do that by providing a VirtualFileReader that looks in your less folder.

    internal sealed class VirtualFileReader : IFileReader
    {
        public byte[] GetBinaryFileContents(string fileName)
        {
            fileName = GetFullPath(fileName);
            return File.ReadAllBytes(fileName);
        }
    
        public string GetFileContents(string fileName)
        {
            fileName = GetFullPath(fileName);
            return File.ReadAllText(fileName);
        }
    
        public bool DoesFileExist(string fileName)
        {
            fileName = GetFullPath(fileName);
            return File.Exists(fileName);
        }
    
        private static string GetFullPath(string path)
        {
            return HostingEnvironment.MapPath("~/less/" + path);
        }
    }
    

    Now all you need to do is provide the config with the VirtualFileReader to the parse method like so:

    public class LessTransform : IBundleTransform
    {
        public void Process(BundleContext context, BundleResponse response)
        {
            DotlessConfiguration config = new DotlessConfiguration();
            config.MinifyOutput = false;
            config.ImportAllFilesAsLess = true;
            config.CacheEnabled = false;
            config.LessSource = typeof(VirtualFileReader);
    #if DEBUG
            config.Logger = typeof(DiagnosticsLogger);
    #endif
            response.Content = Less.Parse(response.Content, config);         
            response.ContentType = "text/css";
        }
    }
    

    Perfect! With just a single reference to bootstrap.less you can have your less files utilize the existing bundling and minification strategy.

    public class BundleConfig
    {
        public static void RegisterBundles(BundleCollection bundles)
        {
            var less = new Bundle("~/bundles/less")
                .Include("~/less/bootstrap.less")
                .Include("~/less/datepicker.less")
            less.Transforms.Add(new LessTransform());
            less.Transforms.Add(new CssMinify());
            bundles.Add(less);
    ...
    
    Posted by JarrettV on August 31 at 8:09 PM

  3. MVC3 Talk

    Image7.media Tonight, I will be talking about MVC3 to bugdotnet which is Birmingham's .NET User Group.

    Topic: ASP.NET MVC 3

    ASP.NET MVC 3 is a framework for building scalable, standards-based web applications using well-established design patterns and the power of ASP.NET and the .NET Framework. The latest version includes great new features: razor view engine, expanded validation, and built in support for dependency injection.

    As part of my preparation for the talk, I built a feedback site using many of the new features in MVC3.  The feedback site is live and is is currently hosted on my backup server at discountasp.  I've posted the source code on github.

    The reason for this feedback site was two-fold.  I not only wanted to use newer MVC3 features, but I wanted to solicit feedback for my talk.  You see, I have already given the MVC3 talk to GGMUG, which is the Gwinnett, Georgia, Microsoft User Group.  The presentation was great.  The audience was great. The feedback was great.

    From this feedback, tonight I will approach the audience with a choice.

    • Learn about what is new in MVC3 or
    • Learn about MVC in general

    Please attend if you'd like to have a say. The meeting is tonight at 6:30 pm at New Horizons located at:

    601 Beacon Pkwy W
    Birmingham, AL 35209-3121
    Posted by JarrettV on March 08 at 2:56 PM

  4. Comparison of YUI Compressor for .Net to Microsoft Ajax Minifier

    Minify

    Microsoft just released the Microsoft Ajax Minifier for minifying javascript files.  Since I've been using the Yahoo! UI Library: YUI Compressor for .Net to do this in AtomSite, I thought it would be great to compare the two to see which is best.  I'm mainly interested in the file size reduction but it would be nice to know any speed differences as well.

    The Test

    image

    This method allows me to test compress some javascript using any method I pass into the Func delegate and capture the results.

    To get a reasonable sample of the performance I minified 3 different files with each method 1000 times.  I attempted to configure both algorithms to produce the smallest output possible.

     image

    The Results

    image

    From these results you can see that Microsoft AJAX Minifier creates smaller files in about the same amount of time.  Note, both algorithms have been set in aggressive, or hypercrush, mode to rename variables and perform other tweaks for reducing file size. The Microsoft AJAX Minifier seemed to have more granular options for tweaking output. However, the YUI Compressor is open source so you could add additional options if you need them.

    The Comparison

    Scorecard Speed Size Reduction Options CSS & JS Support Build Task Open Source
    YUI Compressor lose lose lose win win win
    Microsoft AJAX Minifier win win win lose win lose

    And the Winner is..

    It depends.  I suggest using the Microsoft AJAX Minifier as it produces smaller files.  However, the YUI Compressor.Net better satisfies my needs as it can minify both JS and CSS files.  So, when I need to minify dynamic combinations of both types of files, I'll use Yahoo! UI Library: Compressor for .Net.  When I need to do one-time minification during a build or prior to deployment, I'll use the Microsoft AJAX Minifier.

    Download

    I've uploaded the test solution and console app so you can run the tests yourself.

    JsMinTest.zip (291KB) fixed

    More Reads

    Check out how I am using minification and combination in AtomSite to speed up page load time.

    Posted by JarrettV on October 19 at 11:57 PM

  5. AtomSite 0.9 Released, Mix09, MVC Final

    Today is a great day for me.  ASP.NET MVC 1.0 Final was released today at Mix09. I finally released AtomSite 0.9 on CodePlex to coincide with the new framework.  I can finally get some sleep.  However, there is still tons of documentation that needs to be created/updated for this release.

    I can't do this project alone.  If you'd like to help create plug-ins, documentation, or themes, let me know so I can add you to the development team.

    Also, AtomSite has a new website to go along with it's .

    Finally, the keynote for Mix09 was streamed live today and there are some great things coming out of Microsoft.  Silverlight 3.0 looks very promising.  I encourage you to watch the video.

    Posted by Jarrett on March 19 at 12:23 AM

  6. AtomSite 0.9 Nearly Ready

    BlogSvcToAtomSite  I'm excited about the next release of BlogSvc, which going forward will have the of AtomSite.  I have put my architect hat on to design and build a plugin/widget system.  Along the way I've learned how to build an extremely modular web application based on the ideas pioneered by Louis DeJardin of the Spark engine.  We do not (yet) use the Spark view engine.  However, it does support it.

    The plug-in model supports:

    • Installation
      • Drop in bin folder
      • Supports extracting embedded theme/script files to correct folders
    • Register Additional View Engines
    • Registering Routes
      • Supports collection constraints
      • Support for multiple workspaces (areas)
      • Support for secure routes (https)
    • Dynamic Controllers
    • Services
      • Supports cross-service events via singletons
    • Widgets
      • Supports both composite and simple view type widgets
      • Supports three different scopes, Service, Workspace, Collection
      • Widget can register stylesheet dependency link
      • Widget can register javascript dependency link
      • Widget can include in-line script at bottom of page
      • Widget can have nested widgets
      • Widgets can be cached (with proper authorization support)
      • Planned support for script/style compression and consolidation planned
      • Planned support for drag drop widget management planned
    • Themes
      • Revised to use YUI layout grids to support dynamic templates
      • Side bar can be moved to either side
      • Supports multiple fixed-widths and fluid layout
    • Metadata
      • Data could be used to install, register, uninstall
      • Planned support for plug-in admin pages
      • Planned support to submit to a global plug-in registry
    • Merits
      • Supports order in which plug-in is activated
      • Supports overwriting previous plug-in routes

     

    All of this is nearly ready for the next release.  If testing goes well, you can expect a release this weekend.

    Posted by Jarrett on March 09 at 4:05 PM

  7. Update to ASP.NET MVC RC1

    I've checked in the code to update BlogSvc to ASP.NET MVC RC1 Refresh.  There were only minor updates to get things workings and the overall process only took around 10 minutes.  However, the readme notes on the configuration are misleading.  The release notes tell you to update the pages section to look like:

    <pages

    validateRequest="false"

    pageParserFilterType = " System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35 "

    pageBaseType = " System.Web.Mvc.ViewPage, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35 "

    userControlBaseType = " System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35 " >

    This is not necessary as you'll notice when creating a new MVC project that three bolded lines are not included.  When I added the lines to my config it caused errors on my hosting provider.

    Posted by Jarrett, Jarrett on January 31 at 12:05 AM

  8. New BlogSvc Release and Oxite

    oxciteblogsvc

    Wow, I believe I'm all caught upontherecent hypearoundOxite. Although I can't help but feel a bit left out in the cold.  I mean BlogSvc has been on codeplex much longer than oxite and it never received this much attention.  It is a shame because I believe the newest release, BlogSvc 0.8 Wizard Release is solid example of how to build a content management solution using MVC.

    I know BlogSvc doesn't yet have all the fancy administration pages or widgets/plugins yet, but we have a solid foundation to get there.  I wish we could bring all the developers together on one solution so we build the next WordPress on ASP.NET MVC. Perhaps combine the best of BlogSvc, BlogEngine.net, dasBlog, SubText all into one super solution and call it SuperPressTM.

    </rant>

    Posted by Jarrett on December 24 at 10:20 AM

  9. ASP.Net MVC Beta Crashing IIS7

    With the new beta release of the MVC framework, I updated BlogSvc to compile and run with the new dlls that are now in the GAC.  After deleting from the gac and finally copying the dlls to my bin folder I things running smoothly from within Visual Studio.  However, when I deploy to IIS7, I am getting a crash.

    AspNetMvcBetaIis7Crash

    I’ve tried cleaning out all the applications in my IIS and also restarted the AppDomains, sites, servers.  I’ve also tried rebooting.  Anyone have any idea’s?  Does the beta run on your IIS7 in Vista?

    I’ve asked this question on StackOverflow: Why is Asp.net MVC Beta crashing my IIS7?

    Update: I toggled data execution preventions (DEP) and a couple a reboots later and the issue cleared up.

    Posted by Jarrett on October 16 at 5:33 PM

  10. Deploy MVC Application

    I previously thought Visual Studio.NET only supported automatically deploying “Web Site” projects but it also works with “Web Application” and “MVC” projects. Right-click on your project and choose publish.

     PublishWeb

    After choosing publish it will upload all the files based on your “Copy” choice.  You can watch the output window to track the progress:

    ------ Publish started: Project: WebMvc, Configuration: Debug Any CPU ------
    Connecting to ftp://ftp.atomserver.net/wwwroot/...
    Deleting existing files...
    Publishing folder /...
    Publishing folder App_Data...
    Publishing folder App_Data/www...
    Publishing folder App_Data/www/blog...
    Publishing folder App_Data/www/blog/WelcomeToBlogService06...
    Publishing folder App_Data/www/media...
    Publishing folder App_Data/www/pages...
    Publishing folder js...
    Publishing folder themes...
    Publishing folder themes/default...
    Publishing folder themes/default/images...
    Publishing folder bin...
    ========== Build: 5 succeeded or up-to-date, 0 failed, 0 skipped ==========
    ========== Publish: 1 succeeded, 0 failed, 0 skipped ==========
    Posted by Jarrett on October 15 at 7:17 PM

© Copyright 2024