Thursday, September 28, 2006
.NET Serialization: Custom Formatter, IFormatter
Of course, this "absolute requirement" has now changed and using the BinaryFormatter and the NonSerialized attribute is no longer an option as all properties/fields must now be available through remoting. It was time for a custom formatter as the BinaryFormatter class is sealed/NotInheritable.
As the help topics on IFormatter contains only API level details, I though I should share this excellent documentation and working code with you: Serialization Formatters (published by Universität Karlsruhe).
The article also explains the little known ISerializationSurrogate mechanism; this allows you to provide your own serialization mechanism for specific classes/object types/value types, even when using one of the standard formatters. This is typically used to serialize classes that are not marked as [Serializable]. It can also be used to provide specific handling of null/nothing strings and for normalizing the serialization of decimal values. The former is a problem for the .IsDirty mechanism because a null/nothing string is different from a ""/String.Empty string, while the latter is a problem because the decimal value 1 might be different from the value 1.0 as the binary representation might change.
You might also find this Advanced Serialization MSDN article useful.
[UPDATE] Serializing object graphs that comprises inheritance requires some extra work. If you need to serialize inherited composite objects, the XmlInlcude(typeof(DerivedClass)) class attribute is the best solution when derived classes are know at compile-time. If you need to serialize "unkown" derived objects, the CodeProject XmlSerializer and 'not expected' Inherited Types article provides a really simple solution (the comments section includes a Generics NodeSerializer<T>).
Some of the MSDN help topics lacks working, real-life examples of how to implement an interface or abstract class; which is too bad and makes developers waste a lot of time in "the desert of desperation". I had the same problem last year looking for a working example of how to implement a SoapExtension. I wish Microsoft could do a litte more to help developers fall into "the pit of success".
Monday, September 25, 2006
MSCRM 3: Move contact, retain history
Read the article over at Barney's blog.
Monday, September 11, 2006
Intention Revealing Interfaces, Bad Naming and Maintenance
The naming focus is on intention revealing interfaces, but still new methods/properties/class members with creative misspelling, abstract names such as PerformDataFunction, abbreviations such as IntAccount (integer, internal, international ?) , pops up in the design now and then.
What triggered me to write this post is misleading name reuse. One of the domain objects is the AccountNumber and the account number does either belong to the bank or it does not. In addition, an account belong to the bank can be an internal account for e.g. book-keeping, currency exchange, etc. Looking through the .IsXxx properties of the object I found .IsInternal, but no property to tell me if the account belongs to the bank or not. As the object did not reveal its intention to me, I had to find and ask the developer. And surprise, surprise; the domain term 'is internal' had been used as the 'own bank' indicator as it "seemed natural at the time".
"So why did you not change it when you discovered the misleading term?" I asked, knowing the answer: "I am afraid that it will break the other project. Also, it might be a lot of work to make it build after the refactoring". I know that the "other project" has low unit tests coverage and a complicated build configuration, but none of the solutions using the common component is in production yet.
This leads me to the difference between public and published, i.e. it is the published parts of your object model/API you cannot change (it is the contract of your service). The public parts is subject to change without notice. As none of the components are published yet, we decided to refactor the design of the object model to comply with best practices, now rather than later.
The main goal of the refactoring of our components is to comply with some of the central design goals of our components: "power of sameness" and "tools for communication (revealing intention)". As it is now, coding against the common core components is like being an archeologist; piecing together fragments left behind by long gone developers.
Being complex is easy, being simple is hard - Brad Abrams
Monday, August 28, 2006
Using Excel to generate picklist XML for MSCRM
The range name is entered into A2 ("CountryList" in the example) and this defines the set of picklist item values. The option offset number to start with is entered into B2 ("10" in the example), it becomes the value of the first generated option. Use one as the 'Start option number' when adding items to an empty picklist.
I have added a button control to run the GenerateCustomizationXml method that generates the customization XML:
Sub GenerateCustomizationXml()
Dim namedRange As range
Dim outputCell As range
Dim listName As String
Dim xml As String
Dim ctr As Integer
listName = range("A2").Text
ctr = range("B2").Text
Set namedRange = range(listName)
xml = "<options nextvalue=""" & ctr + namedRange.Cells.count & """>"
For Each listItem In namedRange.Cells
xml = xml & "<option value=""" & ctr & """><labels><label description=""" & listItem.Text & """ languagecode=""1033"" /></labels></option>"
ctr = ctr + 1
Next
xml = xml & "</options>"
Set outputCell = range("B4")
outputCell.Value = xml
End Sub
The macro generates the XML with the correct option value numbers, calculates the nextvalue number, and puts the result into B4. Mark the B4 cell and click CTRL-C to copy it to the clipboard. Follow the steps outlined in Mitch's blog to import the new picklist values into MSCRM. Refer to the SDK for more details.
The macro is generic and can be used for any named range of cells in the worksheet. Just enter the range name in A2 and run the macro. Naming a range of cells is as easy as selecting the range of cells and typing in the name in the 'name box' in the upper left corner of the worksheet.