Archive for the ‘Microsoft .NET’ Category

Problems and Solutions with Model-View-ViewModel

My MSDN article on the MVVM design pattern is finally available!
http://msdn.microsoft.com/en-us/magazine/ff798279.aspx

Unfortunately, Figure 1 is not correct;  we’re working on getting that fixed in the article. In the meantime here’s a corrected version:

  • The WPF Utilities component should not depend on any unit tests
  • The unit test components should not depend on any other unit testing component
  • The domain model should NOT depend on the data access layer.  Instead, the data access layer should depend on the domain model.  The domain model is the core of everything.  Acthieving this is not easy, and I’ll post about how to achieve it.

Let me know what you think of the article!

Robert

Advertisements

Switching to NLog

My application has about 165,000 lines of code, and I have been using log4net for all my logging needs.  However, for a client application that I’m working on I wondered if Log4Net was the best choice.  After doing some research and experimentation I decided it wasn’t.  Instead, NLog wins the new title, and it only took 1 hour to switch my entire 165,000 lines of code over to NLog.

Benefits of NLog over Log4Net:

  • Signs of life!  Log4Net doesn’t seem to be active any more – certainly there hasn’t been a release in ages.
  • Logging methods that accept format strings and parameters.
    This later is why switching to NLog took so long: I was able to go through my code (using VS2008 & searching across the entire solution) and remove all the irritating string concatenation, replacing them with format strings and parameters.  This means that if a logging level is turned off, the string concatenation will never occur!

So instead of:

log.Debug(“Some message ” + pieceOfData + ” and ” + someOtherData );

which ALWAYS results in 3 string concatenations even if debug logging is disabled, I can now do:

log.Debug(“Some message {0} and {1}”,pieceOfData,someOtherData );

which ONLY does a string concatenation if the debugging is enabled.

  • Automatic configuration – just start-up your application and go
  • More powerful configuration!
    Their configuration has LOTS of very cool marcos (which they call Layout Renderers).  This allowed me to eliminate a huge pile of messy C# log4net configuration code (complete with nasty casting to internal classes – which apparently is the “documented” approach) just to configure the output file to go into the user’s AppData local folder.Eliminiating C# code for a single easy-to-understand line of configuration is good!

So instead of all of this:

/// <summary>
/// Setup Log4Net and create a file appender so that it logs to a writable location!
/// (even in Vista where the "Program files" folder is read-only.
/// </summary>
private static void SetupLog4Net( string dataPath ) {
	// Configure Log4Net with the properties from the app.config file
	log4net.Config.XmlConfigurator.Configure();

	// Create the file appender and setup basic options
	var fileAppender = new log4net.Appender.RollingFileAppender();
	fileAppender.AppendToFile = false;
	fileAppender.RollingStyle = log4net.Appender.RollingFileAppender.RollingMode.Once;
	fileAppender.MaxSizeRollBackups = 4;	// The number of log files to keep around
	fileAppender.MaximumFileSize = "10MB";

	// Use an almost standard layout pattern
	const string layout = "%date  %-5level  Thread:[%-23thread]  %logger - %message%newline";
	fileAppender.Layout = new log4net.Layout.PatternLayout(layout);

	// Log data to the location application data directory because it's pretty
        // much guaranteed we can write there.
	string logFilePath = CurrentLogFilePath(dataPath);
	fileAppender.File = logFilePath;

	//Notify the appender on the configuration changes
	fileAppender.ActivateOptions();

	// Get the root logger (bit of a hack, but seems "standard") and add the file appender
	var repository =  LogManager.GetRepository() as log4net.Repository.Hierarchy.Hierarchy;
	if( repository==null ) throw new Exception("Failed to get the log4net hierarchy repository.");
	log4net.Repository.Hierarchy.Logger root = repository.Root;
	root.AddAppender(fileAppender);

	// Very important: Mark the repository as configured and notify it that is has changed
	repository.Configured = true;
	repository.RaiseConfigurationChanged(EventArgs.Empty);
}

I now have this one line of configuration code in the XML configuration file:

fileName=”${specialfolder:folder=LocalApplicationData}\MyApp\MyApp.${shortdate}.log”

That is FANTASTIC!

  • NLog is also supported by Gibraltar!  (Which I WISH I owned…)

The only down side is that padding doesn’t always work, so laying out the log file for easier reading is not there yet (from the NLog blog):

…the use of “padding” attribute on layout renderers. If you used it in v1 you may have found
that it did not work for all renderers (depending on their implementation)

Apparently this is fixed in version 2, but I don’t know when that will be available.

Somebody has also already written an article about NLog and PostSharp which is cool because it means “free” logging.

I also can’t get it to do rolling log files every time the application starts up.  I’ve posted a question on the NLog forum here.

Robert

Failed to deserialize change-set. Operation is not valid due to the current state of the object.

I’ve had a long disucssion with myself over on the MSDN forums here:
http://forums.silverlight.net/forums/p/140254/313870.aspx#313870

I’ve reproduced it here:

I’ve written a domain service that allows basic CRUD operations for a person’s “Contacts”.  Lots and lots of unit tests run just fine against the server side code, and the Silverlight client can download all the contacts I put into the database using a SQL script and display them very nicely.

Unfortunately, I can’t create a new contact from the Silverlight side.  In the submit operation’s completed event handler I get the error message:

{System.Windows.Ria.Data.EntityOperationException:
Failed to deserialize change-set. Operation is not valid due to the current state of the object.
at System.Windows.Ria.Data.HttpDomainClient.GetRequestResult(HttpDomainClientAsyncResult httpAsyncResult)
at System.Windows.Ria.Data.HttpDomainClient.EndSubmitCore(IAsyncResult asyncResult)
at System.Windows.Ria.Data.DomainClient.EndSubmit(IAsyncResult asyncResult)
at System.Windows.Ria.Data.DomainContext.CompleteSubmitChanges(IAsyncResult asyncResult)}

However,  in the submit operation completed event handler submitOp.EntitiesInError.Count()=0.  Thus, it doesn’t seem to be my new contact instance object that’s the problem.

I’ve overriden all the methods in the domain service adding try/catch blocks (or at least a breakpoint) and just calling base.whatever()  the only method that seems to be called is the Initialize(DomainServiceContext context) method, which completes normally.  The insert method of the domain service is definitely not called:

[Insert]
 public void AddContact( ContactDto newContact ) {
    Contract.Requires(GetCurrentUserId()!=null, "The request must be authenticated");
    Contract.Requires(newContact!=null, "The contact to add must not be null");
    Contract.Requires(newContact.Id==0, "All new contacts must have a zero ID");
    Contract.Ensures(newContact.Id!=0, "The contact's ID should not be zero after adding it to the database");
    System.Diagnostics.Trace.WriteLine("*** SERVER *** AddContact( "+ newContact + " )");
    var userID = GetCurrentUserId();
    this.UnitOfWork.SaveContact(userID, newContact);
 }

The JSON that is passed to the server is:

[{"Entity":{"__type":"Contact:#MyApplication.DataAccessLayer.Contracts.Data",
"Archived":null,
 "Category":null,
 "Company":"ABC inc",
 "DataVersion":null,
 "DateCreated":"\/Date(-621355788000000500)\/",
 "DateModified":null,
 "DateViewed":null,
 "FirstName":"Robert",
 "HomeAddressId":null,
 "Id":0,
 "LastName":"McCarter",
 "Notes":null,
 "NotificationFrequency":null,
 "OwnerId":0,
"SpouseFirstName":null,
 "SpouseLastName":null,
 "WorkAddressId":null},
"Id":0,
 "Operation":1,
 "OperationData":null,
 "OperationName":null}]

So, in a separate solution I started from scratch and created a new Silverlight  .NET RIA Services project. I copied the definition of the DTO contact class into this new project.  I can easily create new instances of the DTO contact class in the new project.   Then I copied my simplified GUI in to the original project and it doesn’t work, I get the same error as above.  Then I copied my simplified domain service to the original project and it STILL doesn’t work, I get the same error.

The contact DTO class was being automatically generated by my ORM tool, and was being annotated by that tool as follows:

[System.Runtime.Serialization.DataContract(Name="Contact")]
public partial class ContactDto : BaseEntityDto {
....
}

When I had previously copied the DTO code to my simplified experimentation project I had not copied the attributes.  The moment I copied the attributes it stopped working.  Changing the name of the data contract to match the name of the class fixes the problem.

Notice that this is actually visible in the original JSON:

    Contact:#MyApplication.DataAccessLayer.Contracts.Data

this should have been

    ContactDto:#MyApplication.DataAccessLayer.Contracts.Data

I don’t know WCF so I don’t fully understand what this name is actually doing, although according to the MSDN documentation (http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractattribute.aspx) the default value is the name of the class.

Is it possible that this is a bug in .NET RIA Services, where RIA Services is assuming the data contract name is the same as the class name even when it doesn’t have to be?

Update:

I’ve asked Mindscape if LightSpeed could be modified to make this work:
http://www.mindscape.co.nz/forums/Post.aspx?ThreadID=2507&PostID=7399

 

 

OnCreated not called when created

I’m using Microsoft .NET RIA Services to build a Silverlight application, and today I had a bug.  At first it looked like the DataGrid’s RowDetailsTemplate wasn’t working, but that wasn’t it.

After debugging it for a little while I realized that the property I had data bound to, “FullName” wasn’t being set by the OnCreated() method,  which is a partial method called by the class’s constructor.

Apparently .NET RIA Services is using reflection in  such a way that it doesn’t call the constructor when it is creating client side objects from a server response.  This is possible using the serialization method: FormatterServices.GetUninitializedObject().  So when .NET RIA Services is de-serializing objects from the server it doesn’t call the constructor and the objects are created without their OnCreated() method being called.

In my case, the solution was simply to move the initialization of the derived  FullName property into the property getter rather than in OnCreated() method.  Then I had to implement the appropriate partial methods for the “FirstName”, “LastName” “SpouseFirstName” and “SpouseLastName”properties so that they would raise the property changed event for the “FullName” property.

Nice and easy, however it’s still a shame there’s no way for an object to know when it has been newly retrieved from the server.

VS2010 MSDN Accouncement and pricing

Microsoft just had some major announcements about VS2010 MSDN subscriptions:

1. New SKUs:
http://arstechnica.com/microsoft/news/2009/10/visual-studio-2010-simplified-to-four-skus-beta-2-arrives.ars

2. “Free” upgrade
http://www.microsoft.com/visualstudio/en-us/products/msdn/default.mspx#roadmap

Here’s a quick price comparison matrix/chart that I put together that will probably mean I’ll ditch NCover and buy MSDN premium instead, picking up Expression Studio 3 and the full version of Office 2010 in the process.

Upgrading to Visual Studio 2010
MSDN Premium
(with Ultimate offer)
MSDN Professional
MSDN subscription cost: $2,499 $1,199
Code Coverage included $658 (NCover complete)
Test prioritization included n/a
Code analysis / optimization included n/a Microsoft code contracts (watch the video)
DB dev & testing tools included n/a
Expression Studio 3 included $600
Office included $540 (Ultimate upgrade price)
Windows OS included included (Windows 7 Ultimate upgrade price)
$2,499 $2,997
$498
Other links:
Current subscriptions http://msdn.microsoft.com/en-us/subscriptions/subscriptionschart.aspx
VS in only 4 SKUs http://arstechnica.com/microsoft/news/2009/10/visual-studio-2010-simplified-to-four-skus-beta-2-arrives.ars

2009-10-30: Update!

I just watched this amazing profiling video:  http://channel9.msdn.com/posts/DanielMoth/VS2010-Parallel-Computing-Features-Tour/

Recently I was talking with RedGate about their profilers:

  1. Performance profiler: http://www.red-gate.com/products/ants_performance_profiler/index.htm $500
  2. Memory profiler:  http://www.red-gate.com/products/ants_memory_profiler/index.htm ANOTHER $620

While Parallel Tasks and Parallel Stacks are available in Pro and above, it’s not immediately clear about the profiling, but I’d guess it’s only in Premium and above, which differentiates itself from the professional version by another $1120 for a total savings of about $1620 AND its all nicely integrated inside Visual Studio.

2010-02-04: Update

For Code Contracts: “The one that includes the static checker requires VS 2010 Premium or VS 2010 Ultimate.

Static code-contract checking is amazing – I think this could save a lot of debugging time.