Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to version middle tier .NET application classes/methods

We have a typical N-Layer .NET application which sits in between our database and Web API service layer. This application consists of Business Layer, Data Repository/Access along with the related DTOs and Business Objects.

We have solutions in place to version our stored procedures and our Web API endpoints. The issue is the solution to version this middle layer, the actual class methods and schema objects. All Google searches come up with results for versioning source code in a source control solution or how to version using the Assembly info, neither of these are what we are referring to so results are limited.

So for example, we have two endpoints:

...api/v1/tax/charges

...api/v2/tax/charges

v1 must hit one version of the method CalculateTaxPctgs and v2 hits another version with updated business logic. Along with both needing to use different versions of the POCO Tax and TaxItems as we changed the name of one field in v2.

The easy to develop but hard to manage and very rigid/static solution would be to create two different methods, CalculateTaxPctgs_V1 and CalculateTaxPctgs_V2. This doesn't seem like a good idea.

Hard to find best practices or even alternative solutions for this dilemma. This is an enterprise application which takes millions of requests every day so performance is extremely important but so is code management and reliability.

like image 737
kruegerste Avatar asked Apr 22 '15 14:04

kruegerste


1 Answers

Instead of different methods I'd use object inheritance. This way if a method stays the same between different versions you don't need to change the implementation in any way. You could then use a factory of some sort to create the instance required. For example:

public virtual class TaxCalculatorBase {
    public virtual ICollection<TaxPercentage> CalculateTaxPercentages() {
        DefaultImplementation();
    }
}

public sealed class TaxCalculatorV1 : TaxCalculatorBase {
    //Same implementation so no need to override
}

public sealed class TaxCalculatorV2 : TaxCalculatorBase {
    //Same implementation but with a bit extra
    public override ICollection<TaxPercentage> CalculateTaxPercentages() {
        base.CalculateTaxPercentages();
        ExtraStuff();
    }
}

public sealed class TaxCalculatorV3 : TaxCalculatorBase {
    //Different implementation
    public override ICollection<TaxPercentage> CalculateTaxPercentages() {
        NewImplementation();
    }
}

public static class TaxCalculatorFactory {
    public static TaxCalculatorBase Create(int version) {
        switch (version) {
            case 1: return new TaxCalculatorV1;
            case 2: return new TaxCalculatorV2;
            case 3: return new TaxCalculatorV3;
            default: throw new InvalidOperationException();
        }
    }
}

public class CallingClass {
    public void CallingMethod(int versionFromURL) {
        var calculator = TaxCalculatorFactory.Create(versionFromURL);
        var percentages = calculator.CalculateTaxPercentages();
        percentages.DoStuffWithThem();
    }
}

If the api implements an entire new version each time the factory can be more generic and something like:

public static class MyFactory {
    public static TaxCalculatorBase CreateTaxCalculator(int version) {
            switch (version) {
                case 1: return new TaxCalculatorV1;
                case 2: return new TaxCalculatorV2;
                case 3: return new TaxCalculatorV3;
                default: throw new InvalidOperationException();
            }
        }
    }
    //various other methods to create classes which depend on version
}
like image 158
Andy Nichols Avatar answered Sep 20 '22 14:09

Andy Nichols