Monday, July 5, 2010

Gradients, CSS and Overflow

Last year, I built a website (http://www.joebeernink.com) to handle aspect of my burgeoning writing career.  I also used it to learn ASP.NET MVC.

I had a designer do the styles and the graphics, but I did all the HTML work.  When I originally laid everything out, the content all fit nicely on a single 800px long div which exactly matched the length of the repeating vertical gradient the designer put together for me for the outer background. 

Once the content got too long, the repeating style left a lot to be desired.  It not only repeated across the X axis, but the Y axis as well, which meant starting at pixel 801, I had this nasty black line across the bottom of the screen, and then the gradient began again.  Yuck.

So instead of that, I set overflow = auto on all my inner divs, which for a while meant that the one page that had too much content had an inner scroll bar.  I was kind of okay with that (I shouldn’t have been), but CSS has never been something I’ve worked with a lot, so I ignored it.

Lately, as I’ve been upgrading my site for an upcoming conference, every page began to have the scroll bar, and it was killing me.  I talked to my designer at work and they shook their heads and said, “Dude, that’s like one line of CSS to fix.  Don’t be such a loser.”  Okay they didn’t say that, but they should have.  They said it was pretty easy, and could be done in a single line of CSS.  They were going to send me that line of CSS, but must have forgot.  So yesterday, knowing that a single line solution existed, I got ready to do some CSS spelunking, and eventually came up with the solution.

Out with the old CSS Classes

.page
{
    background-image: url("../../Content/beernink_pagebkgd.jpg");
    margin-left: auto;
    margin-right: auto;
    background-repeat: repeat;
}

#main
{
    margin-left: auto;
    margin-right: auto;
    padding: 20px 30px 20px 30px;
    background-image: url("../../Content/beernink_insideBkgd.jpg");
    background-repeat: repeat;
    margin-bottom: 5px;
    width: 740px;
    _height: 1px; /* only IE6 applies CSS properties starting with an underscrore */
    overflow: auto;
    height: 500px;
}

And in with the new

.page
{
    background: #252E33 url("../../Content/beernink_pagebkgd.jpg");
    margin-left: auto;
    margin-right: auto;
    background-repeat: repeat-x;
}

#main
{
    margin-left: auto;
    margin-right: auto;
    padding: 20px 30px 20px 30px;
    background-image: url("../../Content/beernink_insideBkgd.jpg");
    background-repeat: repeat;
    margin-bottom: 5px;
    width: 740px;
    _height: 1px; /* only IE6 applies CSS properties starting with an underscrore */
    /* overflow: auto;
    height: 500px; */
}

The #252E33 is the color at the bottom of the gradient. The color nicely fills the page beyond the 800px line, and looks great. 

There are probably better ways to do this, but this was simple and allowed me to say the site was ‘done-done’ for the conference later this month.

Of course, now I want to find a real blogging engine in ASP.NET MVC that I can deploy with my site.  Any recommendations?

Friday, May 7, 2010

Silverlight + Azure Shared Access Policy Issue

We’ve been working with Shared Access Policies in Azure for the last week or so, and for the most part it was working.  But it would only work for a while, then it would stop.  Then it would start working again.   It took some help from Steve Marx and Jai Haridas on the Azure Team to figure out what was going on.

This first piece of code is part of our storage manager that retrieves the Uri for the blob from Azure Blob Storage, and creates a Shared Access Policy for that blob so that our Silverlight Video Player can directly access the blob without going through a very slow web service call.

   1: /// <summary>



   2:         /// Get the Uri for a specified video blob



   3:         /// </summary>



   4:         /// <param name="videoId">The unique identifier of the video</param>



   5:         /// <returns>A Uri ponting to the Video</returns>



   6:         public Uri GetVideoBlobUri(Guid videoId)



   7:         {



   8:             var log = Log4NetHelper.GetLogger();



   9:             log.DebugFormat("Getting Video for video id {0}", videoId);



  10:  



  11:             try



  12:             {



  13:                 CloudBlobContainer container = GetContainer("VideoContainerName");



  14:  



  15:                 CloudBlockBlob cloudBlockBlob = container.GetBlockBlobReference(string.Format(CultureInfo.InvariantCulture, "{0}", videoId));



  16:                 



  17:                 var readPolicy = new SharedAccessPolicy



  18:                 {



  19:                     Permissions = SharedAccessPermissions.Read,



  20:                     SharedAccessExpiryTime = DateTime.UtcNow + TimeSpan.FromMinutes(10)



  21:                 };



  22:  



  23:                 var blobUri = new Uri(cloudBlockBlob.Uri.AbsoluteUri + cloudBlockBlob.GetSharedAccessSignature(readPolicy));



  24:  



  25:                 log.DebugFormat("GetVideoBlobUri successfully retrieved for video id {0}", videoId);



  26:  



  27:                 return blobUri;



  28:             }



  29:             catch (StorageClientException ex)



  30:             {



  31:                 // If the blob was not found, return null



  32:                 if (ex.ErrorCode == StorageErrorCode.BlobNotFound)



  33:                     return null;



  34:                 // Rethrow the exception in all other cases



  35:                 throw;



  36:             }



  37:             catch (Exception ex)



  38:             {



  39:                 log.ErrorFormat("Error while retrieving video blob {0}", ex.Message);



  40:                 throw;



  41:             }            



  42:         }




In our Silverlight Web Service, we call this manager class and return the Uri embedded in an XElement.  Originally we did this to allow us to return other information with the Uri, but at this point, the Uri is all we are passing through.





   1: /// <summary>



   2: /// Get video URI.



   3: /// </summary>



   4: /// <param name="videoId">ID of the given video.</param>



   5: /// <returns>Status</returns>



   6: public XElement DemoVideoUri(string videoId)



   7: {



   8:     var blobManager = UnityFactory.Current.Resolve<IBlobManager>();



   9:     var blobUri = blobManager.GetVideoBlobUri(new Guid(videoId));



  10:  



  11:     string xml = string.Format("<VideoUri>{0}</VideoUri>", HttpUtility.HtmlEncode(blobUri.AbsoluteUri));



  12:     var sr = new StringReader(xml);



  13:     return XElement.Load(sr);



  14: }




On the Silverlight side, we take make a call to this web service, extract the Url from the XElement, and pass the Url into the MediaPlayer like so





   1: var client = new WebClient();



   2:  



   3: var videoUri = GetVideoUri();



   4:  



   5: client.DownloadStringCompleted += (x, y) =>



   6:                                Dispatcher.BeginInvoke(



   7:                                    () =>



   8:                                    {



   9:                                        var xdoc = XDocument.Parse(y.Result);



  10:                                        var query = from b in xdoc.Descendants()



  11:                                                    select b.Value;



  12:                                        HostedVideoUri = new Uri(HttpUtility.HtmlDecode(query.First()), UriKind.Absolute);



  13:                                        mediaPlayer.Source = HostedVideoUri;



  14:                                        Log(string.Format("HostedVideoUrl = {0}", HostedVideoUri.AbsoluteUri));



  15:                                    }



  16:                                    );



  17:  



  18: client.DownloadStringAsync(new Uri(videoUri, UriKind.Absolute));



  19:  



  20:  



  21: private static string GetDemoVideoUri()



  22: {



  23:     var host = HtmlPage.Window.Eval("window.location.hostname;") as string;



  24:     var path = HtmlPage.Window.Eval("window.location.pathname;") as string;



  25:     var refererUri = host + path;



  26:     var url = string.Format("http://{0}/xxxx.Svc/DemoVideoUri/{1}", GetHost(), VideoId);



  27:     return url;



  28: }






This is all pretty simple code (and the above code works, by the way).



Where we ran into problems was in the Web Service, when populating the xml string.  Originally, we used blobUri.ToString() instead of blobUri.AbsoluteUri.   This caused big issues (403 errors returned from the Azure Storage Service), when the Video Player tried to retrieve the blob because the Url returned from the Shared Access Policy generator can have spaces in it.  And Uri.ToString and Uri.AbsoluteUri work very differently when handling spaces.  I did not know this until last night.  Uri.ToString unescapes the Uri before returning it.







So why did it work sometimes, and not all the time?  Simple.  Sometimes the Uri from the Shared Access Policy Generator has spaces, and sometimes it does not.  The former did not work, while the latter did.  We were looking for a pattern in the number of times we called the web service, or the interval between calls, and the size of the video blob.  But it was as simple as a single space.



I think we spent at least 8 hours over the last two days trying to track down this bug.  Hopefully this saves someone else some grief.



This post is cross posted on http://www.palador.com/blog/Blog/Silverlight--Azure-Shared-Access-Policy-Issue intentionally.

Monday, April 26, 2010

Book Review: Professional Application Life Cycle Management with Visual Studio 2010

We’re jumping into Visual Studio 2010 this week, and beginning the migration to TFS 2010 as well.  I wanted to get familiar with TFS 2010 and try to standardize our practices a little more before we mis-configured everything, so I bought the first book I saw that seemed to cover TFS 2010.  Professional Application Lifecycle Management with Visual Studio 2010 by Mickey Gousset, Brian Keller, Ajoy Krishnomoorthy and MArtin Woodward fit the bill for what I was looking for and more.

The book is broken into 5 Parts:

  • Architect
    • This was a little basic, and highlighted a few new features in VS 2010 that I once used Visio to accomplish.  But it also clarified for me a few basic UML constructs that I rarely used or may have been using incorrectly.  I’m not sure I’ll use all of the available UML diagrams very frequently, mainly because not everyone on the team will be able to use them or understand them, but I’ll see how it goes.  Ironically, this may be the last section that is truly useful for me.
  • Developer
    • I’m going to make sure all my developers are familiar with the new capabilities of VS2010, and this is a fantastic guide to what is possible.  It make take a little effort to get to add these tools to the dev tool belt, but I think these time savers make the difference between a professional development shop, and a place that is just throwing code over the fence.
  • Tester
    • A great section about brand new functionality in 2010, and an area both testers and devs should be reading.  I’m hoping that I can really alter our expectations of the relationship between dev and QA through the use of these tools, and that by the end of the year, our QA process can be much more thorough than it is now, and not cost any more time than it already does.  It’s definitely been the neglected child of the development process, and my goal for the rest of 2010 is to bring it up to speed.
  • Team Foundation Server
    • A solid primer on TFS and some good guidance on branching and merging.  A must read for dev leads, architects and build engineers
  • Project / Process Management
    • This is the section that really got my attention at first, and the one I would like everyone here to read, even the execs, and especially the solution managers.  Half the battle of good project execution is getting everyone on the same page of terminology and process.  This is definitely worth a read for a shop that is will to make changes, not for the sake of making changes, but to fix issues and bring themselves into compliance with the rest of the development world to eliminate the vocabulary barrier.

I found all the sections useful as a starting point to either make slight improvements to the processes we use, or as a guideline to make wholesale changes to how we are working to improve our output. 

What I really liked about this book was that while I could have figured this stuff out on my own over the next year or so, it gave me a good primer to get started, so hopefully that will result in fewer wrong steps, and let me know about hidden features that I may have never discovered. 

I powered through this book in about a week, and I’m sure I remember less than 50% of it.  But at least I know where to go to look things up, and can begin to plot out direct for the configuration of our TFS servers and our processes.

Tuesday, March 2, 2010

Book Review: Introducing .NET 4.0

I recently finished reading Alex Mackey’s book, “Introducing .NET 4.0 With Visual Studio 2010”.  VS2010 won’t be launched until April 12, 2010, which is still just over a month away, but I’ve been champing at the bit, ready to dive into .NET 4.0 for months now.  Mackey does a great job of whetting my appetite without drowning me in the minutiae of each new or improved feature. 

.NET 4.0 is all about improvements to pieces that have been slowly coming together over the past few years.  There have been a number of out of band releases to the .NET Framework since .NET 3.5 launched.  .NET 4.0 enhances a lot of those releases, and, in some cases, completely goes back to the drawing board.  There are a few new features that will make developers happy, but for me, the money is in the things Microsoft made better. 

Mackey assumes you have a good knowledge of .NET, as this book targets what is new since 3.5.  He includes things which were included in .NET 3.5. SP1, since not everyone may have gotten into that yet.  I was pleasantly surprised at how much of the SP1 functionality we have actually put to use here, and was able to skim those chapters.

There are parts of the book that were finished before the actual functionality of VS2010 or .NET 4 were finalized, but that’s what you’ll get when you buy a book on a product before the product is released. Caveat Emptor.

By the end of the book, I was able to make some decisions on what functionality to target for further research.  My bets are on three areas that will have the biggest payoffs for my team and my customers:

  • MEF (Managed Extensibility Framework)
  • Entity Framework 4.0
  • Windows Workflow 4

With MEF being such an integral part of Office 2010, a good working knowledge of it is essential to provide process enhancements for our customers.

We use Entity Framework 1.0 in just about every project we work on, and the leap to 4.0 should resolve a number of significant issues and code costs that we have encountered in the past year.  I expect to see a large effort reduction in application development costs due to this upgrade.

If the improvements to Windows Workflow are as good as advertised, then I believe WF will go from shunned cousin to an accepted member of the development family.  There’s a lot of power in WF, but the previous implementation was lacking.  I stopped considering the previous releases as viable last year after a few false starts, but I have much higher hopes for it going forward with V4.

I recommended Introducing .NET 4 to my colleagues as a good getting started guide, and directed some to target certain chapters to match up with the type of work they typically do, or areas where they have yet to become involved in to give them a 40,000 foot view. 

I will probably go out and buy other .NET 4 books as they become available, but will focus on the three areas above as they will have the biggest impact to my architecture choices in the coming months. 

Mackey helps to give that guidance, and gets me excited for the new features.  That’s what I want in an introductory level book.

Cross Site Blogging

Today, I’m proud to announce the launch of a revamped Palador.com web site.  Palador is the consulting company that I work for, and as the Senior Application Architect there, I will be doing my part to blog there, as well as here, and my personal blog as well.  That’s a whole lot of blogging, but I actually get paid to blog there, so hey, I’m okay with taking that on.

Occasionally, I will cross post blogs here and there.  Sometimes things will be posted there and not here, depending on the topic. We’ll see how it goes.

We’ll have five or six of us posting entries on a variety of topics, which is cool as it just goes to show how diverse our skill set is here. 

Anyway, take a spin over to the new site and let us know what you think.  I wrote or edited a lot of the copy there, so if you find issues, let me know.