Friday, September 10, 2010

A few links pertaining to my code contracts talk

I am giving an intro talk on Code Contracts tomorrow for the Central PA .NET Code Camp 2010.
Here a few links from that talk.

  • Code Contracts web site

  • Sample chapter on Code Contracts from Jon Skeet's book C# in Depth (second edition)

  • Pex for Fun web site that I took examples from.

  • Excellent series of blog posts from Kevin Hazzard on code contracts

Souce Code and other materials from Grokking ORMs talk

Here are the slides and source code from my talk at Central PA.NET Code Camp 2010 called Grokking Object-Relational Mappers. The zip file is at https://public.me.com/jwigger and is called Grokking_ORMs_9_10_2010.zip
Here is a few links covered in the talk.
  • Julie Lerman's book, THE book on EF - Programming Entity Framework

  • Frans Bouma, developer of LLBLGen has a lot of interesting, highly opinionated posts on his blog. This post explains his position on why LLBLGen works well with Entity Framework. I will post more on this topic but I do really like the LLBLGen designer and code generator used in combination with EF. Caveat Lector: I received a free developer license of LLBLGen to work on this presentation.

  • NHibernate's Home is here at nhforge.org

  • Upcoming NHibernate 3 Cookbook by Jason Dentler and his Hanselminutes podcast episode

  • Jeremy Miller's MSDN article on persistence ignorance and the unit of work pattern.


  • An explanation of the Select N+1 problem that relates to lazy loading objects.

Code Contracts Support within .NET Framework BCL

Code Contracts were one of the Holy Grails in Computer Science when I received my bachelor’s degree in 1997. Yes, there was research aplenty including my professor Dr. Tim Wahls’ work with the Larch and later Java Modeling Language (JML) approaches to Design By Contracts. However, it was far removed from mainstream programming. Microsoft is poised to change that with Code Contracts.


Code Contracts allow formal specifications to be applied to code. These consist of preconditions, post-conditions, and object invariants. The idea is that code can have its intent made clearer for callers by specifying characteristics of valid use and code that calls code with contracts available can be more reliable by guaranteeing that the contracts aren’t broken. Compile-time checking allows abuse of contracts to be caught very early in the development cycle. An excellent chapter by Jon Skeet from C# in Depth (second edition) covering contracts is available here.


Code Contracts are still a development labs product but Microsoft has already modified some BCL code to support contracts. An earlier draft of Skeet’s chapter illustrates the progress is making. An example showing a case beyond what Code Contracts were NOT aware of is now caught by .NET 4 and the static contract checker! The system random number generator Next function takes two arguments , a lower bound and upper bound, and produces a pseudorandom number >= lower bound and < upper bound. Looking at the BCL source available through Microsoft’s symbol server shows a contract that stipulates that the lower bound can’t be larger than the upper bound.


 int randomNum;  
Random randomGenerator = new Random();
randomNum = randomGenerator.Next(7, 1);
//caught as an exception violation

If we have a function with a precondition that an input number is a valid output of a six-sided die, then the static contract checker uses the contracts built-in to the BCL to support its inference. The static check has found that the output of the Next function will always produce legal input.


 Random randomGenerator = new Random();  
randomNum = randomGenerator.Next(1, 7);

Sunday, August 15, 2010

Cardinal Rule of OO design: Internal Immutability

One of my bedrock OO programming practices is a use of internal immutability. I don’t know if there is an expression that describes this but that is what I call it. By this I mean calls to a procedure or function of a class from within another procedure or function of the same object shouldn’t change the state of any data members of a class. This is often referred to as avoiding side effects. Isn’t it fundamentally essentially that an object consists of both state and behavior? (As an aside, I am omitting the third characteristic of an object, identity.) State that is exposed to another object is allowable, and indeed essential for OO programming.


This practice is etched in mind through prolonged exposure to pain. I began my programming career by supporting the implementation of a subsystem developed by an experienced Fortran developer required to write his first C++ program. The essential flaw to this design was that each column of each database table used represented a data member in a SINGLETON class. What happened was that the state would get overwritten and lost in processing events. Development had started out very promisingly but slowed down by the time I joined the team. I assisted by testing the development code baseline. As I identified test case failures, the developer, who had both a phenomenal work ethic (12 hours a day, 7 days a week) and a keen ability in logic, would painstakingly correct the code. Once corrected, test cases would frequently fail again over time. Once implementation was undertaken, despite the fact that the system had no error-handling logic, it needed babysitting round the clock. I spent my evening onsite for this application querying and updating Oracle records to provide that fault handling. This is an extreme case but was helpful to develop OO religion.


This is a long-time practice of mine but not one that I could formally articulate until I recently read Growing Object-Oriented Software Guided By Tests, written by Steve Freeman and Nat Pryce. This book has a lot of insights into OO design that stand apart from its focus on TDD. Let me quote their wonderful explanation.



As well as distinguishing between value and object types (page 13), we
find that we tend towards different programming styles at different
levels in the code. Loosely speaking, we use the message-passing style
we’ve just described between objects, but we tend to use a more
functional style within an object, building up behavior from methods and
values that have no side effects. Features without side effects mean
that we can assemble our code from smaller components, minimizing the
amount of risky shared state. Writing large-scale functional programs is
a topic for a different book, but we find that a little immutability
within the implementation of a class leads to much safer code and that,
if we do a good job, the code reads well too.”

Friday, June 25, 2010

Pradeep's Presentation on Web Client Software Factory

Lately, all of the buzz within ASP.NET has been for ASP.NET MVC. Microsoft’s Patterns and Practice group’s Web Client Software Factory has been around a couple of years. It allows the Model View Presenter (with Passive View) pattern to be applied while still taking advantage of WebForms. I think that the WCSF fits a niche for developments shops with an investment in WebForms can utilize while still offering some benefits of a much more testable and clean development structure. Its recipe-based structure allows for guidance to encourage a consistent approach across the application. Fritz Onion has a nice article providing an overview of the product. WCSF continues to be supported for VS 2010.


In May, I saw an excellent presentation by Pradeep Panthulu on WCSF at a Central PA.NET users group meeting. He has been an architect on a large project that uses WCSF. If I recall correctly, there were at least 40 people on the project. For such a large project, Pradeep found the guidance-based approach of WCSF vital to keep development consistent across the application. Pradeep also showed his architectural expertise by demonstrating the ability to answer questions not directly related to his presentation.


Pradeep found two way data binding to be difficult to accomplish with WCSF. He has ultimately had some success in this area and his blog is a must read for dealing with this scenario. You can read about his modifications to the Object Container Data Source here.


Pradeep also took the time to replace the dependency injection technique supplied by WCSF. Out of the box, WCSF for VS 2008 utilized ObjectBuilder. He replaced it with the newer P&P solution. He found using Unity for DI to not be a performance bottleneck, but application startup was slow. Another problem he encountered was that the team's project would often crash within the visual studio editor when under design view.

Wednesday, June 23, 2010

dealing with EF error

I have been spending a lot of time lately comparing NHibernate with Entity Framework using POCOs. I have been hesitant to blog about potential flaws in the EF because there hasn’t been a lot of writing out there on the subject. One experience I have had shows the holes in what is essentially a 1.0 for POCO support. The mapping error handling in EF must be improved.
If you make a mistake in EF where your class doesn’t map correctly to the model, you are likely to see this error “Mapping and metadata information could not be found for EntityType 'YourNamespace.YourClass'. When not using POCOs with EF, the properties in the class that map to the model are automatically generated. However, with POCOs you are on your own. For troubleshooting I did find it helpful to temporarily turn code generation of classes on and then compare my properties with those generated by the EF templates. It still is error handling that sucks, and it should be improved by Microsoft’s EF team. Ideally, the missing or mistyped property should be spelled out. In fact, when using EF with EntityClasses I received at one point (after mucking around in the model .edmx xml file) this error “The type 'Employee'('EntityType') of the member 'manager' in the conceptual type 'HelloEfModel.Employee' doesn't match with the type 'collection[HelloNHibernate.Employee(Nullable=True,DefaultValue=)]'('CollectionType') of the member 'manager' on the object side type 'HelloNHibernate.Employee'.” That is exactly the kind of error I want to see!

Saturday, May 15, 2010

Introducing SpecFlow

Philly .NET Code Camp 2010 was particularly timely, being in conjunction with the Visual Studio 2010 launch. There were 10 different tracks, with numerous well-known speakers and many exciting new .NET features. Despite all of that, one of the more low-profile talks, by Tony Nguyen, on Behavior Driven Development, proved to be the most exciting to me. This talk on BDD and the relatively new product SpecFlow draws heavily on concepts pioneered in the Ruby world through the Cucumber BDD framework.


I had been unconvinced about the full value of BDD prior to this. I could see potential benefits as part of the development process. However, I was skeptical that users, even highly motivated users that are part of an agile process, would be interest in seeing test results. With SpecFlow, instead of just seeing test results as output, quality assurance or end users can write out requirements.


The approach SpecFlow takes is requirements first. The requirements are written in the natural language Gherkin. Conventions are then use to determine the names of tests that should be written. Instead of being test-first, it is requirement first. Running the test suite will confirm or deny the existence of individual test cases and whether they return the proper result. Requirements writers can write cases in notepad and developers can run test suites integrated into Visual Studio. I haven’t provided any details of the Gherkin language but Tony’s presentation, available here, is one good place to start.


There are some immediate questions that are still worth considering before jumping in using SpecFlow. One important question to consider is that given SpecFlow is a fairly new open source project, will it continue to be actively maintained? Another big question is, will there be end-user buy-in into writing requirements in this fashion? Tony has had some success with end users but reports, after less than a year of development with BDD on his most recent project, less than 100% adoption. Organizational culture and management support will affect adoption greatly. Finally, BDD emphasizes integration style tests. How should unit testing be combined, if at all, with BDD tests? In Tony’s case, there test cases are most done in SpecFlow but unit test cases have been written too by some team members.

Monday, May 3, 2010

Turbo-charge your .NET application – upgrade to .NET 4.0

Even if you aren’t planning to take advantage of any of the new features in the .NET 4.0 Framework, performance alone can justify the upgrade. I recently spent a “Day of Performance” with John Robbins at the April 2010, Wintellect Devscovery conference. He estimates that applications should see a 5-10% increase in performance. This is due to improvements in garbage collection and within the Common Language Runtime (CLR).


Prior to .NET 4.0, garbage collection took over execution within your application. This meant that while garbage collection was running, your code wouldn’t be. In .NET 4.0, garbage collection can now occur in a background thread. Of course, it is always wise to address performance by cutting down on the number of garbage collections that are necessary.


Two performance boosts stand out in the .Net CLR: reflection and StringBuilder appending. Although already fast, Robbins’ performance metrics show that StringBuilder appending is three times as fast. Reflection binding and invoking are also three times as fast. Considering how slow reflection is compared to normal method invocation, this increase is huge. Even if you aren’t directly performing reflection or using a StringBuilder, the NET FCL code uses these classes as building blocks. I have run Robbins’ test suite and encountered the same results on my own PC. I have not directly included the test suite results or test code due to intellectual property concerns.

Wednesday, April 21, 2010

VS 2010 Links from Central PA .NET presentation

Visual Studio 2010 Intros



  • Link to code(CPADemo.zip) from Entity Framework Demo with POCOs (Plain Old CLR Objects)
  • CodeCamp Philly 2010 with webcast downloads to Judy's presentation and EF presentation

  • Scott Wiltamuth Apr 26 at 5:30 Microsoft Malvern

  • Public Sector Road Show in Harrisburg May 5 Overall look at VS 2010 + focus on team system

  • Visual Studio Editing features
    MSDN article

    Note: Control-Alt-Spacebar to switch between completion and suggestion mode

  • Free e-book on moving to Visual Studio 2010


More detailed links



Entity Framework 4.0 New Feature Summary


    EF 4 new features
  • POCO support and Proxies

  • Lazy/Deferred Loading

  • Foreign Keys

  • ObjectSet and Testability

  • Model First/Database Generation

  • LINQ to Entities Improvements

  • Pluralization

  • Stored procedures that return complex types

  • Provider changes, including support for Date/Time, Math, and Provider Supplied Functions

  • ExecuteStoreQuery, Translate



Entity Framework Resources



EF and POCO



  • Microsoft-created templates are downloadable through gallery OR here

  • POCO template walkthrough

  • 4 part POCO walkthrough: 1 2 3 4


Tuesday, April 20, 2010

Farewell code access security policy (and others things deprecated in .NET 4.0)

At this writing, Microsoft is still has a lot of work to do in articulating their revamped security model. Here is what I gather from what 2 Microsoft employees involved in CLR security: Andrew Dai and Shawn Farkas. CAS policy is being deprecated in favor of Level 2 Security Transparency. Non-hosted applications, e.g. a WinForms app, will be fully trusted when run locally or over the local network. Microsoft is recommending use of policy be implemented and managed outside of the CLR itself. Hosted applications such as in ASP.NET will still have the ability to run as a partially trusted application. In essence Microsoft is trying to simplify the security model. In the end, I think a more understandable model will be utilized more. As an ASP.NET developer I hope to see more ASP.NET applications running as partially trusted in the future.


Surprisingly, ASP.NET Ajax client side libraries are deprecated. Microsoft is open sourcing its Ajax client library and making JQuery the “the primary way to develop client-side Ajax applications using Microsoft technologies.” This come from a post on Stephen Walther’s blog. I think this is a great decision, having long favored JQuery myself. Given all of Microsoft’s efforts in creating its Ajax library , switching to JQuery is also a ballsy decision.


Microsoft continues to publicly support WebForms and MVC but a closer look at the new features in each suggests otherwise. MVC has new features like Areas, data annotations, and asynchronous controllers. In web forms, allowing developers control over the ID of form fields when using server controls is a huge deal. It was a frustrating experience to deal with the ID mangling done previously. Greater control over viewstate is another very useful change. Having server controls emit clean css-based markup is also important. I see these as bugfixes, not the introduction of new features. True new features are basically absent within WebForms.
There is a lot of exciting stuff in .NET 4.0 but it is always interesting to see what the casualties are.

Major Themes emerging from the VS 2010 Launch

Amidst the bevy of new features, a few major themes emerge in the release. C# and VB.NET changes are primarily designed to add features that already existed in its sibling language. Dynamic support has been added to C# and VB.NET and a production release of the DLR with IronPython and IronRuby has come as well. VS 2010’s much talked about conversion to being a WPF application shows that Microsoft is preparing WPF to be the primary desktop software. Finally, software parallelism is featured in numerous areas, notably the available of F# as a fully supported functional programming language.



Microsoft has had numerous teams and research projects focus on parallelism related technologies. Including F# “in the box” with VS 2010 provides a functional language within the family of .NET framework languages. Functional languages are considered well suited for splitting logic across multiple CPUs. Having fewer or no side effects, as functional languages are oriented around, allows program instructions to be more easily scheduled across CPUs. For multi-threaded processing, Microsoft has provided a new library called tasks. Tasks offer a simplified approach to using thread pools that also allowing greater control over such things as aborting a task.
WPF and its sibling Silverlight appear to be the focus in rich UI technologies, finally pushing WinForms aside. There is little new on the WinForms front. WPF is plugging availability holes (relative to WinForms) in its array of controls. WPF offers a databound grid for the first time. WPF and Silverlight both benefit from a new, shared XAML designer. Since VS 2010 is built using WPF and the VS and WPF teams collaborated closely, his has meant many WPF performance improvements. I think that this will give Microsoft the courage to finally officially deprecate WinForms with the next major VS release.


Microsoft’s linguistic emphasis in VS 2010 for VB.NET and C# is to make the two languages comparable in features. For C#, this means features that are important in COM interop scenarios and Office-related programming in particular. These features include named parameters, optional parameters, and late binding. For VB.Net, this includes full support for lambdas. This includes multiline lambdas and lambdas that don’t return a value.


Dynamic language features have finally made it as a fully supported part of .NET. The Dynamic Language Runtime (DLR) is a layer that exists on top of the CLR. Both VB.NET and C# allow ways to specify the use of dynamic typing. The .NET based dynamic languages IronRuby and IronPython are now available, although not directly provided by Visual Studio (separate downloads are available). Interop between Ruby or Python and VB.NET or C# is available plus VB.NET and C# can host a Python or Ruby scripting engine.

Wednesday, April 7, 2010

Reflections on J.P.’s Nothing But Net Course

I took JP’s course in 2008 in Philadelphia and found it to be the most valuable but most draining course I have ever taken. By my nature, I am not somebody who will survive a boot camp of ANYTHING well. It also takes me a long time for me to absorb things. It is important to note that J.P. has announced plans to cut back from days that run until 2 or 3 in the morning to ending by 10 pm. I think it has taken me about 18 months but, I have finally absorbed most of the course. I still have some work to do in grokking Behavior Driven Design. During the class I made reference to the students as “Boodhoosattvas”. A bodhisattava is an enlightened learner on the way to Buddhahood. J.P. is an inspiring teacher encouraged his students to become a continuously evolving (and continuously integrated :) )passionate developer.


One key takeaway from the course was the concept of developing a solid core of knowledge. For me, focusing on Domain Driven Design through the work of Eric Evans (one of JPs recommendations) has been an area of focus for me. The idea of an ubiquitous shared language between users and developers has been a key tenet in my efforts to do stealth agile development. Evans focus on container shipping as a system example worked great for me, since I worked on a system that involves booking container shipments. I probably have taken even more, though, from some of Evans’ post-book webcasts that cover strategic design. Often forgotten amidst the tactical design DDD topics of value objects, repositories, and aggregate roots are some real wisdom in Evans’ approach to strategic design. Another pair of books that I have focused on are Jon Skeet’s C# in Depth and Jeffrey Richter’s CLR via C#.


Another thing J.P covered is how to develop a reputation as a developer. He encouraged the class to blog and work on presenting at user groups. I have started blogging this year and have my first user group presentation in a couple of weeks.


A third important takeaway was to take a broader view of a developer community. A great deal of the course is spent working with different groupings of fellow students. Prior to the course, I had been somewhat isolated from a sense of a developer community apart from the 7 or so people directly on my development team. In my own little community, I was content to dominate the discussion without any real technical debate or challengers. This week broadened my developer world view tremendously.


A fourth, very specific, takeaway was to embolden my renounciation of WebForm development. JP criticized WebForms development in favor of pattern-based approaches in the ballpark of the Model View Controller pattern. This has given me the kind of expert opinion and intellectual support for me to pursue the goal of eliminating WebForm server control based pages from the applications I work on.


This reflection really doesn’t relate to specific coverage of topics, although I can assure you that JP did cover the very ambitious syllabus in the course. I also blog about one approach he utilized to represent type-safe enums here.

Article Posted on Handling Http Form Data in ASP.NET

Just a quick note that I have placed an article here on a utility class for handling http form data. The idea is to allow you to treat post or get data in a consistent manner for both retrieval and generation of data. It incorporates UrlEncoding and HtmlEncoding as appropriate to allow you to output sanitized code without dwelling on the details. The class allows you to treat as a writeable dictionary so that entries can be added or deleted as needed. You could probably write most of the code from this description, it is that simple. However, I do illustrate a solution to pass data of one's choice when making a Server.Transfer call.


In ASP.NET, Server.Transfer will either pass exactly the same data that the initial page received or no data at all. I use Thread Local Storage (TLS) to store a representation of form data. If you aren't familiar with it, TLS is an extremely useful feature within Windows that allow data storage on a per-thread basis. It is used to provide under the hood support for many cool features within and beyond .NET. An example feature is the idea of an ExecutionContext, which is actually patented by Microsoft.

Wednesday, March 24, 2010

Too-Busy Constructors

In dealing with a more complicated OO design, it can be a mistake to put too much initialization logic into constructors. This is especially important for an OO design that uses inheritance significantly. In this post I offer three reasons against doing too much in a constructor. lazy loading, exception handling, and control over execution order.


First, lets look at control over execution order. It can become complex to reason about the order in which code gets executed. It is necessary to distinguish between the execution of data field initializers and the code in the constructor. I blog here about the exact sequences that occur in VB.NET and C#. The languages have a significantly different ordering! Moving initialization logic into a separate initialization routine can allow you to control this order more precisely, without having to fit logic into object initialization as implemented by your .NET language.


Second, the lazy loading pattern is an extremely useful technique to be aware of. Martin Fowler articulates the lazy load pattern well within his Patterns of Enterprise Application architecture. The basic idea behind lazy loading is that it can be significantly more efficient to delay gathering data until it is actually needed. It is possible that the data may never actually be needed. At the same time, a calling class need never know about the lazy implementation. It can call the object that employs lazy loading and simply assume that the data will be available when it is needed. For some things that are naively done in the constructor, using the lazy load technique is the best way to go.


Third, handling exceptions generated from within a constructor can prove difficult. If the exception should prove critical and can’t be easily handled then the code execution flow can be messy. You have to allow for disposal of all relevant objects and resources obtained so far. You also need to consider what the results of the exception unwinding the call stack will be.


In my own experiences with profiling .NET applications, object creational concerns have proven to a significant cause of inefficiency. In one case, I found that there were an excessive number of Oracle connection objects being created. These connections weren’t actually being opened (thankfully!) but they were instantiated nonetheless. Having constructors do less and instantiating fewer aggregated objects can result in code that is more manageable and more efficient.

Field initializer differences between C# and VB.NET

There are many subtle problems which exist when porting code between C# and VB.NET. One involves inheritance and the order of initialization for fields in a class. I learned about this from reading .NET Gotcha’s by Venkat Subramaniam (Gotcha #27). In C#, fields initializers are executed in order from child to parent and then constructors are called from parent to child. In VB.NET, field initializers are executed immediately before the constructor of the relevant. As with C#, constructors are called from parent to child. Here is a simple example that illustrates how different behavior can result.


The VB.NET code looks like this:
 Public Class Sample1  
Public Sub New()
Debug.WriteLine("Sample1 constructor")
End Sub
End Class
Public Class Sample2
Public Sub New()
Debug.WriteLine("Sample2 constructor")
End Sub
End Class
Public Class Parent
Public oSam1 As New Sample1
Public Sub New()
Debug.WriteLine("Parent constructor")
End Sub
End Class
Public Class Child
Inherits Parent
Public oSam2 As New Sample2
Public Sub New()
Debug.WriteLine("Child constructor")
End Sub
End Class

The C# code looks like this:
   class Sample1  
{
public Sample1()
{
Debug.WriteLine("Sample 1 constructor");
}
}
class Sample2
{
public Sample2()
{
Debug.WriteLine("Sample 2 constructor");
}
}
class Parent
{
public Sample1 Sam1 = new Sample1();
public Parent()
{
Debug.WriteLine("Parent constructor");
}
}
class Child:Parent
{
public Sample2 sam2 = new Sample2();
public Child()
{
Debug.WriteLine("Child constructor");
}
}

Despite the seemingly identical code, the order of execution varies significantly.
In VB.Net the output is:

  1. Sample1 constructor

  2. Parent constructor

  3. Sample2 constructor

  4. Child constructor


But in C# the output is:

  1. Sample 2 constructor

  2. Sample 1 constructor

  3. Parent constructor

  4. Child constructor


There are a couple of approaches that allow this concern to be resolved easily. One simple solution to this problem is to separate construction of objects from effectively initializing their state. For example, having the classes Sample1 and Sample2 put their logic in an Init method would allow a more consistent and predictable behavior. Another approach is to assign the reference (i.e. “new up”) to data fields within the constructor. I expound on the more general flaw of doing too much in constructors here.

Monday, March 22, 2010

Typesafe enumerations in .NET

One of the weaker aspects of C# and VB.NET is the lack of support for strongly-typed enumerations. The enum type in VB.NET uses whole numbers as a backing store with Integer being the default backing store type. Since enums are a value type based on whole numbers, they can have mathematical operations applied to them. You can, for example, add or subtract to their value. More importantly, you can assign a value to an enum that is not actually part of the enum. As programmers we make an association between the enum and backing store and face the temptation of dealing with the underlying store and explicitly assigning a value. This applies even to code that could be identified as buggy at compile-time. It is possible to identify whether an enum has a valid value by using the System.Enum.IsDefined function.


Here is an example of a convention enum that illustrates the weaknesses of the Enum type.


 Enum ConnectionStatus  
Closed
Open
Retrying
End Enum
Sub BuiltInEnumTest()
Dim connectionType = ConnectionStatus.Open
Console.WriteLine()
connectionType += 5
If [Enum].IsDefined(GetType(ConnectionStatus), connectionType) = False Then
Console.WriteLine("Out of bounds value")
End If
End Sub



One of the many takeaways I gained from a course with JP Boodhoo (his famous Nothing But Net Course) was how to create what can be treated like a typesafe enum. The idea is to have a class that equates to the enum type with static variables representing instances of objects that are the value of the enum. In my version, I add a private constructor so that an instance of the enum type can’t be created outside of the class. By removing the integer-based backing store, programmers are forced to treat the enum type as a black box. This ensures type-safety. Here is how this looks converted to a type-safe enum.


 Enum ConnectionStatus  
Closed
Open
Retrying
End Enum
Sub BuiltInEnumTest()
Dim connectionType = ConnectionStatus.Open
Console.WriteLine()
connectionType += 5
If [Enum].IsDefined(GetType(ConnectionStatus), connectionType) = False Then
Console.WriteLine("Out of bounds value")
End If
End Sub



There is one drawback worth mentioning. As a consequence of removing the integer-based backing store it is no longer possible to use the values in a Select statement in VB.NET 10. It is under consideration, however, for future versions of VB.NET to allow a select statement that allows type to be the selection criterion.

Thursday, March 18, 2010

Steve Bohlen on Practical DDD in .NET and Value Equality

I recently had the chance to see an excellent presentation by Steve Bohlen on Practical Domain Driven Design. It was given to the Philly ALT.NET user group. He has slides and example code available here. ). For numerous discussion points, he emphasized the range of options available. It was refreshing to hear this approach which wasn’t dogmatic in how to approach DDD.


He talked about his Proteus open source library which has some very useful code in it. I want to illustrate in this post one of the classes he uses for DDD category of classes know as value objects. Value objects don’t have a unique identifier for equality checks. Instead, value objects are equal when all fields match. Steve uses a ValueObject base class that allows any type to have its fields compared using reflection. This allows the creator of a value object to have the functionality of equality comparison without writing out all of the tedious plumbing code to compare two objects field by field and without the code clutter within the class. There is more to his class than this but this is a very significant method.


 public virtual bool Equals(TObject other)  
{
if (other == null)
{
return false;
}
FieldInfo[] fields = base.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
foreach (FieldInfo info in fields)
{
object obj2 = info.GetValue(other);
object obj3 = info.GetValue(this);
if (obj2 == null)
{
if (obj3 != null)
{
return false;
}
}
else if (typeof(DateTime).IsAssignableFrom(info.FieldType) || typeof(DateTime?).IsAssignableFrom(info.FieldType))
{
DateTime time = (DateTime) obj2;
string str = time.ToLongDateString();
string str2 = ((DateTime) obj3).ToLongDateString();
if (!str.Equals(str2))
{
return false;
}
}
else if (!obj2.Equals(obj3))
{
return false;
}
}
return true;
}

Tuesday, March 16, 2010

Want to become a better VB.NET programmer? Read C# In Depth!

I have been focusing lately on improving my VB.NET expertise. After reviewing the available books I decide to re-read C# in Depth by Jon Skeet (first edition) and really focus on how that translates to VB.NET. C# in Depth is definitely more theoretical than most other books. It is probably one of the few books that help to prepare for reading the actual C# language specification. I strongly recommend porting his example code to VB.NET and playing with these examples. Don’t just read the book.


I’d suggest start by working with a snippet editor. I spent a little time porting Jon’s snippet compiler/runner Snippy to be a VB.NET and will blog about that later in a bit. Alternatively, LinqPad is an excellent Snippet compiler and isn’t just for Linq.


Jon also spent a day presenting a deep dive into C# in Copenhagen and made the material available here. A good chunk of this actually goes deeper in depth than his book. It also just how well he did on focusing his book when you see how tangential he is in these talks. For the most part I would suggest, reading the book first. However, when you reach the promised land of Linq in the book, I suggest you view the first part of Session 6 which illustrates the characteristics of Linq using people as query operators. This beautifully illustrates important concepts like streaming vs buffering and deferred vs immediate execution.


For the most part, Skeet’s examples work well in VB.NET. One gotcha is that in VB.NET events must be associated with an instance of a class whereas Jon’s examples deal with a static (static in C# is synonymous with Shared in VB) class with static methods. Simply changing his examples to use an instance of a class allowed his examples of events to work properly. A more significant problem is the lack of support for iterator blocks with VB.NET 10 (i.e. VS 2010). This means most of chapter 6 is not directly applicable to VB. I also found the type inference in C# to be superior to VB.NET. A few of Skeet’s Linq examples had to be tweaked or explicit typing added to work properly. I found this problem mostly in determining the type of the loop variable in a For Each block. I worked through the examples using VB.NET 10 which rounds out VB.NET’s support of Lambdas. Using any earlier version of VB is likely to be frustrating. I have a nearly complete set of converted examples for those who are interested.


Now to a review of the book itself. Jon creates a narrative structure by showing the evolution of C# from the perspective of examining the language and compiler underpinnings. C# moved to language support for lambdas in two steps. First, it introduced anonymous methods in C# 2 (VS 2005) and subsequently added full lambda support in C# 3 (VS 2008). Covering both approaches is somewhat redundant for C# purposes, and even more so for VB which moved to lambda syntax without an intermediate step. Although the C# syntax is redundant, Jon’s coverage does minimize the redundancy. Don’t skip Chapter 5,which covers anonymous methods. His coverage of closure in the section on capturing variables is excellent and representative of his approach to the more challenging theoretical parts of .NET programming. Once you grasp his coverage of capturing variables, he has a nice followup article on the web here. He provides a gentle approach that warns of the complexity of the material and doesn’t get lost in academic jargon. Lambda calculus has been a favorite topic in computer science theory for many years. Jon doesn’t lose precision in his writing by trying to write in a style that is down to earth as possible. He is a stickler for consistent usage of terminology.


A key technique in the book is analyzing the code generated by the compiler. Although new language syntax has been created for C#, it is amazing just how much extra work is done by the compiler to make Linq and its underpinnings happen. Jon makes it clear what is part of the language, what are extension methods, and what is compiler magic. An important note for VB programmers is that VB does introduce more syntax directly into the language relative to C#. Jon happens to favor the C# approach which has a smaller set of syntax.


Although the focus of the book is on Linq and its underpinnings, you will learn a good deal about two crucial topics: deferred execution and functional programming. These topics will, in my opinion, reshape the future of .NET development. The increasing availability of multiple CPUs in Windows will demand that enterprise programmers take advantage of these features. Deferred execution via async enumerators has application to threading that Jeffrey Richter and the parallel processing folks within Microsoft have exploited recently, particularly in .NET 4.0. See Richter’s CLR via C# third edition for threading coverage that is all-new to readers of previous editions. Interest in functional programming has exploded in recent years and a lot of that is due to the expectation that functional programming will allow programs to be written in a way that increases parallelism. The introduction of PLinq is one way that using a functional approach to .NET can be accomplished while still using VB.NET. C# in depth will prepare you for a functional approach that, while still VB.NET is idiomatically and conceptually quite different.

Saturday, March 13, 2010

Finally, VB.NET supports Auto Properties!

One modest but greatly appreciated feature in VB 10 and Visual Studio 2010 is the inclusion of automatically implemented properties. This feature was first introduced in C# 3/Visual Studio 2008. The idea is that the typical boilerplate property declaration and creation of a field as a backing store can be created through a little extra work done by the compiler.


If you are familiar with the c# version, you will notice some differences in the VB.NET implementation. In the VB.NET version of auto properties, only properties with setters and getters having the same accessibility level. In C#, you can have an auto properties with a public getter and private setter. VB.NET does default to use Public accessibility (, although Private or Protected availability are available. A feature available only in VB.NET auto properties is the convenient ability to assign an initial default value to a property.


The full definition of a property plus its backing store looks like this.


 Private _manualProp As String = ""  
Property manualProp As String
Get
Return _manualProp
End Get
Set(ByVal value As String)
_manualProp = manualProp
End Set
End Property


The auto property definition looks like this but produces the identical code as with a manual property, if you check the results in reflector. The naming convention used is that the compiler will create a backing store field by prepending an underscore character to the name of the property.


 Property autoProp As String = “”  

For those folks committing to using a version of the .NET framework prior to 4 there is good news. Since this new feature is created through an enhancement to the compiler in Visual Studio 2010, you can still target .NET 2.0 through 3.5 and take advantage of this new feature.

Tuesday, March 2, 2010

Making a case for the NetDataContractSerializer

Despite Microsoft’s best effort to keep it a secret, the shared type contracts in the NetDataContractSerializer does have its uses, primarily internally to an application that needs to distribute itself to handle its load. WCF has distanced itself from the code-first (as opposed to schema-first) style used in ASMX web services and .NET remoting. In many cases, I concur with the arguments against the code-first approach. For dealing with other applications, even within an enterprise, it is a much cleaner design to expose an interface. The quality of the WSDL can be much better, allowing service consumers to have a quicker, less buggy development. An SOA approach to recognizing opportunities to allow asynchronous processing is definitely a better architecture to deal with load distribution, than a shared type, code first solution.


Here is a scenario that I have used to quickly make use of the NetDataContractSerializer. I have an application that exposes a web interface but is also heavily involved in EAI (enterprise application integration) scenarios. It was helpful to be able to process messages from a queue and have them processed in a scalable way using IIS and NLB (network load balancing). The open-source tool AutoMapper has opened my mind to using an interface with separate types on the client and server sides. AutoMapper takes away a lot of the grunt work in dealing with separate types that have many identically named and typed fields. Nevertheless, it is very convenient to use a common assembly and a shared type between the client and server.


To use the NetDataContractSerializer you must include in both client and server the source file for the NetDataContract attribute. Aaron Skonnard has a nice reference with the relevant source code. If you use his version just note that the name of the attribute is NetDataContractFormat whereas I chose use the name NetDataContract. Here is a VB.NET version of this:


Imports System.ServiceModel
Imports System.ServiceModel.Description
Imports System.ServiceModel.Dispatcher
Imports System.ServiceModel.Channels
Imports System.Runtime.Serialization
Imports System.Xml

Public Class NetDataContractAttribute
Public Class NetDataContract
Inherits Attribute
Implements IOperationBehavior

Public Sub AddBindingParameters(ByVal description As OperationDescription, ByVal parameters As BindingParameterCollection) Implements IOperationBehavior.AddBindingParameters

End Sub


Public Sub ApplyClientBehavior(ByVal description As OperationDescription, ByVal proxy As ClientOperation) Implements IOperationBehavior.ApplyClientBehavior
ReplaceDataContractSerializerOperationBehavior(description)
End Sub


Public Sub ApplyDispatchBehavior(ByVal description As OperationDescription, ByVal dispatch As DispatchOperation) Implements IOperationBehavior.ApplyDispatchBehavior
ReplaceDataContractSerializerOperationBehavior(description)
End Sub

Public Sub Validate(ByVal description As OperationDescription) Implements IOperationBehavior.Validate
End Sub


Private Shared Sub ReplaceDataContractSerializerOperationBehavior(ByVal description As OperationDescription)
Dim dcsOperationBehavior As DataContractSerializerOperationBehavior = description.Behaviors.Find(Of DataContractSerializerOperationBehavior)()

If dcsOperationBehavior IsNot Nothing Then
description.Behaviors.Remove(dcsOperationBehavior)
description.Behaviors.Add(New NetDataContractSerializerOperationBehavior(description))
End If
End Sub

Public Class NetDataContractSerializerOperationBehavior
Inherits DataContractSerializerOperationBehavior
Public Sub New(ByVal operationDescription As OperationDescription)
MyBase.New(operationDescription)
End Sub

Public Overrides Function CreateSerializer(ByVal type As Type, ByVal name As String, ByVal ns As String, ByVal knownTypes As IList(Of Type)) As XmlObjectSerializer
Return New NetDataContractSerializer()
End Function
Public Overrides Function CreateSerializer(ByVal type As Type, ByVal name As XmlDictionaryString, ByVal ns As XmlDictionaryString, ByVal knownTypes As IList(Of Type)) As XmlObjectSerializer
Return New NetDataContractSerializer()
End Function
End Class
End Class

End Class


The NetDataContractSerializer provides shared type information by including assembly information in the serialized message. I use this simple LocationInfo class in an assembly called SharedType.dll that isn’t strongly named to illustrate the differences in how the XML becomes serialized.

 Imports System.Runtime.Serialization  
<DataContract()> _
Public Class LocationInfo
<DataMember()> _
Public postalCode As String
<DataMember()> _
Public latitude As Double
<DataMember()> _
Public longitude As Double
End Class


My Service Contract was based on this interface.
 <ServiceContract()> _  
Public Interface INetDataContractSerializerSample
<NetDataContract()> _
<OperationContract()> _
Sub DetermineCoordinates(ByRef loc As LocationInfo)
End Interface


The default DataContractSerializer data looks like this:


 <s:Body>  
<DetermineCoordinates xmlns="http://tempuri.org/">
<loc xmlns:a="http://schemas.datacontract.org/2004/07/SharedTypes" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:latitude>0</a:latitude>
<a:longitude>0</a:longitude>
<a:postalCode>90125</a:postalCode>
</loc>
</DetermineCoordinates>
</s:Body>

The NetDataContractSerializer data adds type information based on the shared type in the assembly. The type data includes the assembly name, assembly version, culture, and public key token.


 <s:Body>  
<DetermineCoordinates xmlns="http://tempuri.org/">
<LocationInfo z:Id="1" z:Type="SharedTypes.LocationInfo" z:Assembly="SharedTypes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns="http://schemas.datacontract.org/2004/07/SharedTypes" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<latitude>0</latitude>
<longitude>0</longitude>
<postalCode z:Id="2">90125</postalCode>
</LocationInfo>
</DetermineCoordinates>
</s:Body>


One gotcha I ran into in using the NetDataContractSerializer is the client not supplying type information. This results in a Protocol exception indicating that the data “does not contain expected attribute 'http://schemas.microsoft.com/2003/10/Serialization/:Type'.”. If you encounter this error, double check the client proxy file (by default reference.vb or reference.cs) in the Service References for this directory. The desired Operation Contract should have the NetDataContract attribute applied.

Thursday, February 25, 2010

WCF Zero-Config in .NET 3.5! (Part II)

In this blog post I complete the process of creating a custom WCF service host to allow IIS service hosting without a config file. In my prior post, I create mex endpoints in IIS without adding information in the web.config. The custom host created earlier will be extended in this post to create an endpoint using a WsHttpBinding. This approach has been tested only on IIS7 and .NET framework 3.5 SP1. The technique applies regardless of whether the ServiceContract attribute has been applied to an interface or a class.


First, lets examine the easier case of a class with the ServiceContract attribute applied. We start with the ABCs: address, binding, and contract. IIS (and the Cassini debugging host) provide the address and the class that implements the service to the ServiceHost constructor. This class is directly used as the contract. As in the prior post, I have modified the service .svc file to use the custom ServiceHostFactory we have created. The Custom ServiceHostFactory calls our custom ServiceHost, ZeroConfigServiceHost.


That was easy enough, but dealing with interfaces that have the ServiceContract attribute applied is trickier. The class implementing a given service is known but in order to provide the contract we need to determine the correct interface implemented by this class. I use reflection to identify this information.


I begin this identification by enumerating all interfaces in the current assembly to see if they have the ServiceContract attribute applied. I build a list containing all of these interface types. I then take the type of the class and find which ServiceContract it implements. I use the IsAssignableFrom method available to a System.Type object to match the class to its interface. Once the contract interface is identified it can be used to provide the contract for the endpoint. Everything else is the same as if the ServiceContract was directly applied to a class.


Source File 1: Reflection class
 Imports System.Reflection  
Public Class ReflectionExperiment
Dim oServiceInterfaceTypes As New List(Of Type)
Public Sub New()
Dim oAssembly As Assembly
oAssembly = Assembly.GetExecutingAssembly()
oServiceInterfaceTypes = FindServiceInterfaces(oAssembly)
End Sub
Public Function FindServiceInterfaces(ByVal oAssembly As Assembly) As List(Of Type)
Dim ExportedTypes() As Type
Dim currType As Type
Dim olServiceInterfaceTypes As New List(Of Type)
ExportedTypes = oAssembly.GetExportedTypes()
For Each currType In ExportedTypes
If currType.IsInterface = True AndAlso IsTypeAServiceContract(currType) Then
olServiceInterfaceTypes.Add(currType)
End If
Next
Return olServiceInterfaceTypes
End Function
Public Function IsTypeAServiceContract(ByVal oType As Type) As Boolean
Dim oServiceContractAttribute As New System.ServiceModel.ServiceContractAttribute
Return Attribute.IsDefined(oType, oServiceContractAttribute.GetType())
End Function
Public Function FindServiceContractType(ByVal serviceType As Type, ByRef serviceContractType As Type) As Boolean
Dim bRetVal As Boolean = False
Dim currType As Type
If IsTypeAServiceContract(serviceType) Then
serviceContractType = serviceType
Return True
End If
For Each currType In oServiceInterfaceTypes
If currType.IsAssignableFrom(serviceType) Then
bRetVal = True
serviceContractType = currType
Exit For
End If
Next
Return bRetVal
End Function
End Class


File 2: ServiceHost-related Classes
 Imports System.ServiceModel.Description  
Imports System.ServiceModel.Activation
Public Class ZeroConfigServiceHost
Inherits ServiceHost
Private pReflectionExperiment As New ReflectionExperiment
Public Sub New()
MyBase.New()
AddMexEndpoint()
End Sub
Public Sub AddEndpoints (ByVal serviceType As Type, ByVal ParamArray baseAddresses As Uri())
Dim serviceContractType As Type
Dim oReflectionExperiment As New ReflectionExperiment
AddMexEndpoint()
If oReflectionExperiment.FindServiceContractType (serviceType, serviceContractType) Then
Me.AddServiceEndpoint (serviceContractType, New WSHttpBinding, baseAddresses (0).AbsoluteUri)
End If
End Sub
Public Sub AddMexEndpoint()
Dim mb As ServiceMetadataBehavior
mb = Me.Description.Behaviors.Find (Of ServiceMetadataBehavior)()
If (mb Is Nothing) Then
mb = New ServiceMetadataBehavior()
mb.HttpGetEnabled = True
Me.Description.Behaviors.Add (mb)
Me.AddServiceEndpoint (ServiceMetadataBehavior.MexContractName, _
MetadataExchangeBindings.CreateMexHttpBinding(), _
"mex")
End If
End Sub
Public Sub New (ByVal serviceType As Type, ByVal ParamArray baseAddresses As Uri())
MyBase.New (serviceType, baseAddresses)
AddEndpoints (serviceType, baseAddresses)
End Sub
Public Sub New (ByVal singletonInstance As Object, ByVal ParamArray baseAddresses As Uri())
MyBase.New (singletonInstance, baseAddresses)
AddMexEndpoint()
End Sub
End Class
Public NotInheritable Class ZeroConfigServiceHostFactory
Inherits ServiceHostFactory
Public Overrides Function CreateServiceHost (ByVal constructorString As String, ByVal baseAddresses As Uri()) _
As ServiceHostBase
Return MyBase.CreateServiceHost (constructorString, baseAddresses)
End Function
Protected Overrides Function CreateServiceHost (ByVal serviceType As Type, ByVal baseAddresses As Uri()) _
As ServiceHost
Return New ZeroConfigServiceHost (serviceType, baseAddresses)
End Function
End Class

Monday, February 22, 2010

WCF Zero-Config in .NET 3.5! (Part I)

WCF configuration is, in my mind, the biggest misstep made within WCF (prior to .NET 4.0), compared to ASMX web services. For someone getting starting with web services, their first steps should “just work”. My early successes with ASMX web services allowed me to build confidence. WCF, on the other hand, forces one to immediately deal with System.ServiceModel XML configuration hell. This can scare developers away, especially with the incredibly configurable and extensible WCF. Fortunately .NET 4.0 does allow zero-config WCF, but what about .NET 3.5? This post shows part of how to accomplish this within ASP.NET.



I don’t want to advocate config-less use of WCF in production, but it is sure convenient to have this available in testing. When I first worked with WCF, I was not aware of the WCF Service Configuration Tool (SvcConfigEditor.exe) which has a GUI to more safely edit the System.ServiceModel part of a config file. This caused a lot of teeth-gnashing indeed.


The first big step to making WCF just work was POCO (plain old CLR object) support added to .NET 3.5 SP1. This brings back the ASMX default serialization of including all public fields and properties in a class for serialization. In WCF before 3.5 SP1, a class would have the DataContract attribute applied to it.


In this post I explain how to use a custom ServiceHost and ServiceHostFactory to automatically add HTTP-based metadata exchange (MEX) support for any given service hosted within ASP.NET. This code is reuseable, requiring only the Factory attribute to be added to the service directive line in the .svc. The .svc Factory refers to a custom service host factory. The custom factory simply has code to reference the custom ServiceHost.


The ServiceHost class inherits from the default ServiceHost class. It calls the base class for all functionality and then adds the mex-specific logic. Identifying which extensibility hook is needed is the hard part. From there it simply a matter of mirroring the config file entries to enable mex with programmatic setup. As with the config file, a behavior must be added to set HttpGetEnabled = “true” and add a Mex Endpoint to the service. Note that this example covers HTTP based metadata exchange, not HTTPS, although the concepts are similar.



Step 1: Add the ServiceHost and ServiceHostFactory to a new file within your web site.
 Imports System.Collections  
Imports System.Collections.Generic
Imports System.ServiceModel.Channels
Imports System.ServiceModel.Description
Imports System.ServiceModel.Dispatcher
Imports System.Xml.Schema
Imports ServiceDescription = System.Web.Services.Description.ServiceDescription
Imports System.ServiceModel.Activation
Public Class AutoMexServiceHost
Inherits ServiceHost
Public Sub New()
ConditionallyAddMexEndpoint()
End Sub
Public Sub ConditionallyAddMexEndpoint()
Dim mb As ServiceMetadataBehavior
mb = Me.Description.Behaviors.Find(Of ServiceMetadataBehavior)()
If (mb Is Nothing) Then
mb = New ServiceMetadataBehavior()
mb.HttpGetEnabled = True
Me.Description.Behaviors.Add(mb)
Me.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, _
MetadataExchangeBindings.CreateMexHttpBinding(), _
"mex")
End If
End Sub
Public Sub New(ByVal serviceType As Type, ByVal ParamArray baseAddresses As Uri())
MyBase.New(serviceType, baseAddresses)
ConditionallyAddMexEndpoint()
End Sub
Public Sub New(ByVal singletonInstance As Object, ByVal ParamArray baseAddresses As Uri())
MyBase.New(singletonInstance, baseAddresses)
ConditionallyAddMexEndpoint()
End Sub
End Class
Public NotInheritable Class AutoMexServiceHostFactory
Inherits ServiceHostFactory
Public Overrides Function CreateServiceHost(ByVal constructorString As String, ByVal baseAddresses As Uri()) As ServiceHostBase
Return MyBase.CreateServiceHost(constructorString, baseAddresses)
End Function
Protected Overrides Function CreateServiceHost(ByVal serviceType As Type, ByVal baseAddresses As Uri()) As ServiceHost
Return New AutoMexServiceHost(serviceType, baseAddresses)
End Function
End Class


Step 2: Add Factory to your existing .svc file
For example,


<%@ ServiceHost Language="VB" Debug="true" Service="WcfNoodler.Service1" CodeBehind="Service1.svc.vb" Factory="WcfNoodler.AutoMexServiceHostFactory"%>

Thursday, February 18, 2010

Passing that Bear

I passed (barely) my first Microsoft Certification exam this week. Reading Derik Whittaker’s blog post on the course did offer a warning of the difficulty of what expect. He also talked about XML Serialization and presented a good DimeCast on the subject. As different as .NET was from the previous C++_ and COM technologies, it gradually proved to provide good backward compatibility. So I was kind of looking forward to having a “Core .NET”exam under my belt. When you look real close you see that having a single broad-based .NET exam is really unmanageable.There are simply too many areas to cover.The exam also becomes somewhat of an API bee that intellisense can easily answer once you are familiar with a particular area of the framework.

I know the exam has been around for a while but in 2010, with .NET 4.0 around the corner the exam seems pretty dated. The emphasis on Code Access Security is particularly hard to prepare for, in light of .NET 4.0s make CAS obsolete. Localization was a topic of no applicability for me, but I can accept its inclusion. Using COM libraries from .NET remains useful but bothering to master exposing .NET code for COM consumption doesn’t seem essential to me.

Another bone I had to pick with the exam was coverage of some of the more obscure extensibility points for .NET.Building a Custom CultureInfo class for localization is too esoteric. As valuable as the topic category of reflection is, I question the general need to create assemblies on the fly, such as using the AssemblyBuilder class. If one does need to create code or even assemblies on the fly, there are much better regarded APIs available outside the FCL, such as Cecil.

Another topic covered that I have to question was the introduction to GDI+.The coverage was just a drop in the bucket of possible coverage.I would suggest excluding this topic.This especially true since GDI+ is officially not supported with ASP.NET.I actually wish GDI+ were supported for ASP.NET, particularly for its very useful image conversion functionality. Scott Hanselman just posted on his successful usage of GDI+, even though it is unsupported for ASP.NET. Hopefully he can find out why it remains unsupported!

Thursday, January 28, 2010

Bejabbers begins

Bejabbers is my long-overdue blog on software development from an open-minded .NET developer. Bejabbers literally means "a mild oath expressing astonishment, dismay, disbelief, or the like". If I could only use that when I mumble under my breath at my frustration of the moment.