Alex B. Alex B. - 8 days ago 8
C# Question

C# - Prism for WPF - Common modules' libraries upgrading strategy

I'm designing a composite WPF/MVVM application using Prism patterns. I've read the Developer's Guide to Microsoft Prism Library 5.0 for WPF and I am familiar with most of the patterns described.

My application's modules will consist of a number of binaries (dll-s) and some of them will include a shared library, which will define public interfaces to MVVM models, event classes for event aggregator and services implemented by that module. Other modules would be able to reference such a library and work with its models, events and services through public interfaces and IoC.

Let's say ModuleA.Shared shared library includes a public interface for its SampleModel and SampleService, which performs work with SampleModel:

namespace ModuleA.Shared
{
interface ISampleModel
{
int SampleProp01 { get; set; }
int SampleProp02 { get; set; }
}

interface ISampleService
{
ISampleModel GetSampleModelInstance();
void SaveSampleModelInstance(ISampleModel obj);
}
}


Now say ModuleB (in a non-shared binary) uses ModuleA's public library:

namespace ModuleB.Engine
{
class SampleClass
{
void SampleMethod()
{
ModuleA.Shared.ISampleService srvc = SomeIoCContainer.Resolve<ModuleA.Shared.ISampleService>();
ModuleA.Shared.ISampleModel obj = srvc.GetSampleModelInstance();

// Do some work on obj...

srvc.SaveSampleModelInstance(obj);
}
}
}


Okay, now let's say ModuleB is developed and mantained by a third-party (like a third-party plugin). At some point in time I add a new property to ModuleA.Shared.ISampleModel:

namespace ModuleA.Shared
{
interface ISampleModel
{
int SampleProp01 { get; set; }
int SampleProp02 { get; set; }
int NewProp { get; set; } // <-- New property
}

/* ... */
}


The final user upgrades my application, so the old ModuleA's binaries get replaced with the new ones. ModuleB is distributed by a third-party and its binaries stay the same.

Since ModuleA and ModuleB are now compiled with different versions of ModuleA.Shared.ISampleModel, I assume IoC resolving will not succeed and the application will end in an exception.

What I am asking is what are the good practices / patterns for resolving this kind of issuses? How to make some modules upgradable without breaking the support for third-party modules which depend on them and were built with an older version of their shared libraries?

Answer

This is completely independent of whether you use prism or not. You're providing a plugin api (through the use of prism's module disconvery), and you have to plan for versioning your api.

First of all, once a version of the api is released, it's frozen. You cannot ever touch it (unless you want your third parties to recompile everything, making them and your customers unhappy, to say the least).

Instead of changing the api, release a new version of it:

interface ISampleModelV1
{
   int SampleProp01 { get; set; }
   int SampleProp02 { get; set; }
}

becomes

interface ISampleModelV2
{
   int SampleProp01 { get; set; }
   int SampleProp02 { get; set; }
   int NewProp { get; set; } // <-- New property
}

A third party can then decide to either continue to use ISampleModelV1 or switch to ISampleModelV2 if they need NewProp. Your app, of course, will have to support both of them.

As this gets ugly sooner or later as the amount of api versions increases, you might want to deprecate the old ones, e.g. if your app goes from 2.5 to 3.0, you could remove support for api 1.x... be sure to communicate these decisions to customers and third parties early enough, though.

BTW:

Challenges Not Addressed by Prism [...] Application versioning

Comments