The .NET Buffet

.Net, .Net CF, Architecture, and more (would you like Fries with that?)

  • Resharper 4.5 OutOfMemoryException (and a fix!)

    So I'm working in a solution Visual Studio 2008 with Resharper 4.5.2 and, when including some large XML files (60M, don't ask, they have to be there) in the solution and restarting Visual Studio, Resharper started throwing an OutOfMemoryException when first loading, and then showing all kinds of errors in my solution which I know are not real errors. It ends up that there's an issue with heap fragmentation and memory allocation with Visual Studio and Jetbrains released a small "wrapper" application which appears, at least in my case and several others, to resolve the OutOfMemoryException. I found this nugget of information at CodeClimber's Blog, and the link to the actual wrappers is at: http://confluence.jetbrains.net/display/ReSharper/OutOfMemoryException+Fix Happy Coding!

    Read more...

  • Silverlight ChartHelper revisited...

     

    (Cross-posed from my old, personal blog – Originally published 6/10/2009)

    For my current project, I'm integrating the Silverlight Toolkit's charting functionality with our application.  As part of that effort, I came across this excellent post by Jeremiah Morrill on binding multiple chart series, where he provided the code to an attached behavior that supports this scenario.  However, I had a few additional requirements that his original didn't handle.  Most notably, we needed the ability to set the X and Y axis titles and to set the minimum and maximum values on each axis.  Although I'm not going to copy all of the code here, there were a few interesting challenges in implementing these changes that I'd like to discuss.  The complete source code for my updated example is available for download. (Updated to rename the tile .txt so it is downloadable)

    The Silverlight toolkit's charting module is incredibly modularized, being broken up into axes, series, etc. object hierarchies which together display the chart data. This allows for a great deal of flexibility, but also makes for some "hoop-jumping" to figure out when in the lifecycle of the chart/series/axes you need to set certain items.

    When you are creating your series manually via XAML, it is obvious that these options are easily available.  However, when utilizing the ChartHelper, there was no obvious way to get access to the axes when adding the series, as the chart selects the axes based on the series type you add.

     
    // NOTE: In order to change the Title, Maximum, and Minimum properties of the axes, you must handle the Axes_CollectionChanged event.
                // However, you only want this event to fire once, so we always remove our handler here, and then re-add it to make sure we don't have
                // an ever-increasing number of calls to Axes_CollectionChanged
                ((ISeriesHost)chart).Axes.CollectionChanged -= new NotifyCollectionChangedEventHandler(Axes_CollectionChanged);
                ((ISeriesHost)chart).Axes.CollectionChanged +=new NotifyCollectionChangedEventHandler(Axes_CollectionChanged);
            }
     
            /// <summary>
            /// Handles the CollectionChanged event of the Axes control.  Here, X and Y axis titles and min/max properties are set once the graph creates or assigns the axes we need.
            /// </summary>
            /// <param name="sender">The source of the event.</param>
            /// <param name="ccEventArgs">The <see cref="System.Collections.Specialized.NotifyCollectionChangedEventArgs"/> instance containing the event data.</param>
            static void Axes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs ccEventArgs)
            {
                if (ccEventArgs.Action != NotifyCollectionChangedAction.Remove)
                {
                    Chart chart = null;
                    foreach (DisplayAxis axis in ccEventArgs.NewItems)
                    {
                        chart = (Chart)axis.SeriesHost;
                        if ((axis.Orientation == AxisOrientation.X && GetSeriesType(chart)!=SeriesType.Bar) || (axis.Orientation == AxisOrientation.Y && GetSeriesType(chart)==SeriesType.Bar))
                        {
                            axis.SetBinding(DisplayAxis.TitleProperty, new Binding(GetXAxisTitle(chart)));
                            if (axis is LinearAxis)
                            {
                                axis.SetBinding(LinearAxis.MinimumProperty, new Binding(GetXAxisMinimum(chart)));
                                axis.SetBinding(LinearAxis.MaximumProperty, new Binding(GetXAxisMaximum(chart)));
                            }
                            else if (axis is DateTimeAxis)
                            {
                                axis.SetBinding(DateTimeAxis.MinimumProperty, new Binding(GetXAxisMinimum(chart)));
                                axis.SetBinding(DateTimeAxis.MaximumProperty, new Binding(GetXAxisMaximum(chart)));
                            }
                        }
                        else
                        {
                            axis.SetBinding(DisplayAxis.TitleProperty, new Binding(GetYAxisTitle(chart)));
                            if (axis is LinearAxis)
                            {
                                axis.SetBinding(LinearAxis.MinimumProperty, new Binding(GetYAxisMinimum(chart)));
                                axis.SetBinding(LinearAxis.MaximumProperty, new Binding(GetYAxisMaximum(chart)));
                            }
                            else if (axis is DateTimeAxis)
                            {
                                axis.SetBinding(DateTimeAxis.MinimumProperty, new Binding(GetYAxisMinimum(chart)));
                                axis.SetBinding(DateTimeAxis.MaximumProperty, new Binding(GetYAxisMaximum(chart)));
                            }
                        }
                    }
                }    
            }
     

    The trick (at least as far as I understand so far) is to attach a handler to the chart's Axes collection's CollectionChanged event and, in that event, apply the appropriate bindings to the axes.  So, at the end of Jeremiah's SeriesSourceChanged event, I get a reference to the chart's axes collection and add the event handler.  Note that I first remove, and then re-add the event handler.  The reason for this is that there's no other way I could find to remove the previous delegate before adding the new one when the series source had multiple changes (which it often does in my case).  The relevant code is below:

    Note that I've handled Linear and DateTime axes so far - this handles the situations I've run into at this point, but it may need to be extended.  Also note that the only reason I've got these if statements is because the minimum and maximum dependency properties are defined separately on each axis type, which is something of a pain.  perhaps DateTime and Linear axes could at some point derive from a common base where the Min and Max properties are defined, so this kind of code would be unnecessary.

    The other trick is that, for Bar-type charts, you really need to treat X and Y axes opposite of every other chart type, as the bar type switches the dependent and independent axes.

    I hope this is helpful to someone out there, and thanks again to Jeremiah (Jer?) for the initial implementation.

    P.S. - I apologize for the long line lengths - I have 1920x1200 monitors everywhere and have a tendency to let my code get wider than it should be, which I've now seen quite dramatically in this post.

    Doug 

    Read more...

  • The Dangers of Hammers (or, Why SRP Isn’t Dangerous)

    If you haven’t noticed, David Cooksey and I are having a bit of a back-and-forth about the Single Responsibility Principle and its use (or misuse) in software development. And I’m obviously not here to talk about the dangers of hammers.   But as David Cooksey has come up with another example of how SRP (the Single Responsibility Principle) is dangerous when completely misunderstood, I figured I had to reply with something.

    I’m not going to spend any time discussing the code in his latest example, as I don’t think there’s anything new to discuss.  It’s just another “wrong-headed-application-of-SRP-causes-bad-code” post.

    I guess we both agree that many people don’t necessarily understand SRP correctly (and, honestly, I’m sure I don’t always apply it perfectly every time I try either).  However,  it feels to me that David wants us to fear using SRP, and I want to try to help people understand how to apply it properly.

    Rather than continue to rehash what SRP means to me, I’d like to defer to those from whom I’ve learned and point you at some good articles on SRP, The Open/Closed principle, and other SOLID topics in the hopes that you can see past the fear and start applying these powerful tools properly and without fear.

    Jeremy Miller (of StructureMap fame, if you don’t already know) wrote a nice article in the June 2008 MSDN Magazine entitled The Open Closed Principle, in which he also talks about SRP.  In his words:

    The point of the Single Responsibility Principle isn't just to write smaller classes and methods. The point is that each class should implement a cohesive set of related functions. An easy way to follow the Single Responsibility Principle is to constantly ask yourself whether every method and operation of a class is directly related to the name of that class. If you find some methods that do not fit with the name of the class, you should consider moving those methods to another class.

    I highly recommend reading his article in its entirety (as well as about anything else I’ve ever read that he has written), as I’m pretty sure that article is the subconscious inspiration for my refactoring of David’s original post.

    Another good reference is the originator of the grouping of principles we know as the SOLID principles, Robert Martin.  In his post “Getting a Solid Start” “Uncle Bob” says:

    Following the rules on the paint can won’t teach you how to paint

    This is an important point. Principles will not turn a bad programmer into a good programmer. Principles have to be applied with judgement. If they are applied by rote it is just as bad as if they are not applied at all.

    Having said that, if you want to paint well, I suggest you learn the rules on the paint can. You may not agree with them all. You may not always apply the ones you do agree with. But you’d better know them. Knowledge of the principles and patterns gives you the justification to decide when and where to apply them. If you don’t know them, your decisions are much more arbitrary.

    I could make the same arguments David makes about SRP for just about any software development technique.  Have you ever seen a 12-level-deep inheritance structure used to avoid a bunch of nested if statements (or, god-forbid, the 1200-line method filled with those nested if statements) when applying The Chain of Responsibility Pattern or some other form of composition would have been a much better, and more maintainable, solution.  So, is inheritance dangerous?  Yes, if used incorrectly.

    In conclusion, hammers are not dangerous when used correctly.  However, most tools are dangerous when they are misused, and thousands of people hit themselves in the thumb with a hammer every year.  Hammers are dangerous - handle with care!

    Read more...

  • In response to "The Dangers of Single Responsibility in Programming"

    David Cooksey writes an interesting article titled "The Dangers of Single Responsibility in Programming" in which he proposes that there is a certain level of granularity below which SRP is not appropriate.  Although I understand where he's coming from, I tend to disagree with his conclusion, and I think it's because his hypothetical programmer didn't actually find the right responsibilities, not because the method was already granular enough.  I'd propose a slightly different breakdown of the responsibilities, leveraging Inversion of Control and creating several Pricing Calculators that each handle a different kind of discount (In his scenario, there are Sales prices and Gold Level Discounts).  I would see each of these items as their own calculator, and a separate "Pricer" class that would use each of these.  Note that in a real application I would probably leverage something like StructureMap to find all classes that implement IPriceCalculator and have some way to control the orderring of these (probably a Priority field on the IPriceCalculator interface to sort by) but to keep things simple I'm hard-coding the calculators list in this example.  So, something like this:

       public interface IProduct

        {

            decimal BasePrice { get; }

            decimal SalesPrice { get; }

            decimal GoldLevelDiscount { get; }

            bool IsOnSale { get; }

        }

     

        public interface ICustomer

        {

            bool HasFixedDiscountAgreement { get; }

            decimal FixedDiscount { get; }

            bool IsGoldLevelCustomer { get; }

        }

     

        public class Pricer

        {

            private List<IPriceCalculator> _calculators = new List<IPriceCalculator>

              {

                  new GoldLevelPriceCalculator(),

                  new SalePriceCalculator()

              };

            public decimal GetPrice(IProduct product, ICustomer customer)

            {

                decimal price = product.BasePrice;

                foreach (IPriceCalculator calculator in _calculators)

                {

                    price = calculator.CalculatePrice(price, customer, product);

                }

                return price;

            }

        }

     

        public interface IPriceCalculator

        {

            decimal CalculatePrice(decimal price, ICustomer customer, IProduct product);

        }

     

        public class GoldLevelPriceCalculator: IPriceCalculator

        {

            public decimal CalculatePrice(decimal price, ICustomer customer, IProduct product)

            {

                if (customer.IsGoldLevelCustomer)

                {

                    price = price*(1 - product.GoldLevelDiscount);

                }

                return price;

            }

        }

     

        public class SalePriceCalculator: IPriceCalculator

        {

            public decimal CalculatePrice(decimal price, ICustomer customer, IProduct product)

            {

                if (product.IsOnSale && !customer.HasFixedDiscountAgreement)

                {

                    price = product.SalesPrice < price ? product.SalesPrice : price;

                }

                return price;

            }

        }

    Notice that now, each type of discount is contained in its own class which takes the customer, product, and current price and applies its business rules to the price.  In this way, the GetPrice method isn't going to turn into a Monster Method as new business rules are added. Also notice that it's easy to add a new pricing calculator.   So, for grins, let's add the "FixedDiscount" version alluded to in David's example.  First, create a new price calculator:

    public class FixedDiscountCalculator: IPriceCalculator

        {

            public decimal CalculatePrice(decimal price, ICustomer customer, IProduct product)

            {

                if (customer.HasFixedDiscountAgreement)

                {

                    price = price*(1 - customer.FixedDiscount);

                }

                return price;

            }

        }

    Now, we simply add this to the collection of price calculator used by our pricer (again, this would be handled by our DI container of choice in the real world):

    private List<IPriceCalculator> _calculators = new List<IPriceCalculator>

                                                              {

                                                                  new GoldLevelPriceCalculator(),

                                                                  new SalePriceCalculator(),

                                                                  new FixedDiscountCalculator()

                                                              };

    And we're done.  Now, we've got a well-factored system which follows SRP and is easily extendable with new pricing rules (which, I would assume, could become significantly more complex than the examples given).

    Well, we're not really done - if the theoretical developer had actually modified this original functionality in a Test-driven manner, you'd have a large number of unit tests to prove that you didn't break anything when you added the new FixedDiscountCalculator.  Note that I'm a fan of RhinoMocks, and leveraged it so I don't actually care about where my customer or product information comes from (there's actually no implementation of these interfaces at all - they should be loaded using your favorite repository-pattern-ORM-leveraging-code).  For the sake of keeping this post short, I've uploaded the complete source with unit tests as PricingCalculator.txt - rename to .cs, add NUnit and RhinoMocks references, and you're good to go.

    In conclusion, Is SRP dangerous?  IMHO, not when properly applied.  But that's true for most SOLID principles - you need to know how to apply them appropriately.

     

    Read more...

  • VBCommenter Source

    OK, so it's been a really long time since I've posted here.  In any case, I noticed that in the very recent past several people were looking for the source to VBCommenter.  As it stands, the GotDotNet site is toast, but if you look hard enough, you can still find downloads on their site for VBCommenter.

    I've downloaded the 1.2.6 source code and posted it here so others can continue working on it.  I'd recommend posting the code to CodePlex if there's really still a strong need for this.  Given VS.NET 2005 and 2008 both support XML comments in VB.NET code, I had long ago dropped this project.  I'm hopefully that posting the code will help out those who are still maintaining .Net Framework 1.0/1.1 applications in VB.NET.  Go forth and code!

    Doug

    Read more...

  • VBCommenter 1.2.5 FINAL released

    Anyone who is using VB.NET and wished for support for XML comment generation (NDoc, anyone?) should be using VBCommenter.  As I found myself in that very situation over the last few months, I've made some fairly major improvements to the VBCommenter add-in, and have wrapped up a new release.

    Read more...

  • End to End EntLib Demonstration (Source and Powerpoint presentation)

    Ok, so between naps (of my 21-month-old son) and some late nights, I've managed to get the source code from my presentation last Tuesday put together.  You can downoad the source and my presentation and follow the readme.txt to get set up.  The source has examples of consuming all of the application blocks.  It also includes an example of how to integrate ASP.NET's Forms Authentication and EntLib's Authentication/Authorization block.

    Read more...

  • Another VB.NET note (The BuildRules add-in)

    On another VB.NET note, for anyone using the BuildRules tool included in the Microsoft Visual Studio .Net 2003 Automation Samples and have noticed that when you have a reporting project in your solution the BuildRules tree doesn't populate itself, the bug is essentially the same bug as the one I fixed in VBCommenter.  There's a "foreach (project in solution.projects)" or some such loop in the BuildRules code, which fails somewhat silently when a reporting services project is in the solution.  If you change it to an indexed loop going from 1 to the count of the Solution.Projects.Count property (yes, it really is a one-based array) and get the project using the Projects.Item(index) property, it will work again.  This appears to have something to do with the COM interface to VS.NET and its implementation of the COM equivalent of IEnumerable.GetEnumerator (NewEnum? Sorry, I wasn't a COM guy before .NET) method, which fails in this case.

    Read more...

  • A new VBCommenter release for those of you using VB.NET...

    I've just posted a new release of VBCommenter on the GotDotNet workspaces.  This tool has been invaluable to us on my current project, where VB.NET has been mandated but where we wanted to create our API documentation just like a C# project.  However, there were several issues with the 1.2 release that caused us issues, and over the last few months I've been slowly working on cleaning them up.  Major improvements over the 1.2 version include:

    Read more...