I'm fairly new with APIs and versioning but from what I understand, the developer (which is me) should retain the code if there will be a contract breaking change for the API. Correct me if I'm wrong but I consider Model changes as contract breaking change.
So my question is - Do you make a new model (ex. ModelName.V2) just for the sake of versioning? Is there a better way to do this? This would mean even a slight change in property in my model would mean I would iterate it to another version.
p.s. let me know if I need to edit my question as I'm also fairly new in StackOverflow.
Sample
public class Product
{
public int ID {get;set;}
public string Name {get;set;}
}
and accompanying Controller
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]/[action]")]
public class Products : Controller
{
Product[] prod = new Product[]{
new Product(){ID = 1, Name = "T-Shirt"},
new Product(){ID = 2, Name = "Jeans"}
};
[HttpGet]
[ActionName("gotcha")]
public IActionResult GetProduct()
{
return Ok(prod);
}
}
and for V2 Controller
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]/[action]")]
public class V2.Products : Controller
{
[HttpGet]
[ActionName("gotcha")]
public IActionResult GetProduct()
{
var trash = "Hello World!";
return OK(trash);
}
}
The above codes are what I understand as contract breaking and needed versioning and below is my problem with Model contract breakage:
public class Product
{
public int ID {get;set;}
public string Name {get;set;}
public decimal Price {get;set;}
}
So the sample above shows I added a new property. This I consider as contract breakage and do I iterate a new controller version and then retain the old Model as well? In the future this will be messy if I keep legacy versions.
First, you only need to reversion if there's a breaking change. Not everything is necessarily a breaking change, and typically adding a new property is not in fact a breaking change. Outdated clients should simply ignore it, and if not, that's more on the client than you, as they'd be doing something weird/wrong to cause anything to break that way. You need to be more concerned about changes or deletions, which from a client perspective are kind of the same thing; with a change, it's as if the old property was removed and new one was added. Even then, though, it only matters if the name or the type changes. Any under the hood processing doesn't matter, and technically, even if you change the property name, you can utilize something like the JsonProperty attribute to make the serialization return the old name, if you want.
Assuming you do have a breaking change, then yes, you should create a new version of your model class, and probably a new action/controller to go with it, both named with the new version number, i.e. Product2 and GetProduct2 and/or Product2Controller, etc. Yes, this can lead to code duplication, but there's two things you can do to minimize that:
Use inheritance if possible. For example, Product2 can inherit from Product and simply override whatever property needs to change. If you just add a new GetProduct2 action, you can factor out the original code for GetProduct into a private generic method GetProduct2<TProduct>, and then reimplement the original (and new) method to simply return that, i.e. return GetProduct<Product>(); and returnGetProduct();`. These are just examples. There's many different ways to handle this, but the point is that it doesn't necessarily require major code duplication to do versioning.
If you notice your codebase is starting to feel cluttered, you can begin deprecating API versions. Issue a notice to your clients that one or more of your oldest versions are now deprecated. Then, after a reasonable amount of time (depending on the complexity of the changes required to get up to date), remove that old code in a new release. This will of course break any outdated clients, but they were forewarned and given time to change, so if they don't that's on them. You'll notice all the big boys do this from time to time. I know I've been receiving a ton of emails from Facebook warning of pending API version removals. That's essentially what they're doing behind the scenes: cleaning their codebase.
When I do a API versioning. I add a new model with the Version number just to be able to track down the changes in data data structure, example:
public class ProductV2
{
//New attributes
}
I would just inherit attributes from the previous version, if the new model is similar to the old one plus new attributes:
public class ProductV2 : Product
{
//New attributes
}
Hopefully I understood your question this time.
Related
I'm in the middle of refactoring an analytics api which needs to allow clients to send events as HTTP GET requests, with their "Hit" data encoded in the URL's QueryString Parameters.
My API's job is to recieve these events, and then place the "valid" events onto a queue in another part of the system for processing.
Some Hits have the same shape. The only thing that makes them different is the value of the type parameter, which all events must have at a minimum.
The problem I've encountered is that based on the Hit type, I'd like to be able to assume the type of each field given to me, which requires model binding. Of course. Currently, I can only find out what model to validate against after checking the value of type - which risks making the API excessively "stringly typed"
An example route would be:
GET https://my.anonymousanalytics.net/capture?type=startAction&amount=300&so_rep=true
Therefore, my Hit would be:
{
type: "startAction",
amount: 300,
so_rep: true
}
Which, hypothetically, could be bound to the Model StackOverflowStartHitModel
class StackOverflowStartHitModel {
public string type { get; } // Q: Could I force the value of this to be "startAction"?
? public int amount { get; }
public boolean so_rep { get; }
}
Why am I asking this here? Well I'm normally a JavaScript developer, but everyone who I'd normally turn to for C# wisdom is off work with the flu.
I have experimented with the [FromQuery] attribute decorator, but my concern is that for Hits that are the exact same shape, I might not be able to tell the difference between whether it is a startAction or an endAction, for example.
you're going to need to have a validation engine of some sort, but do not confuse this with your UI model validation. It sounds like you really have one model with a number of valid states which really is business logic.
Your model looks like this:
public class StackOverflowModel
{
public string type { get; set;}
public int amount { get; set; }
public bool so_rep { get; set;}
}
it doesn't matter what value your type field has and you don't need to hard-code it either, it will be captured as is and then it can be checked against valid states.
There are a number of ways to do this, that I can think of.
One option would be to create a list of valid rules ( states ) and then simply check if your input model matches any of them. One way to implement something like this could be with a library like FluentValidation. You can see an example here: Validation Rules and Business Rules in MVC
Another option would be to use some sort of Pattern Matching techniques like described here: https://learn.microsoft.com/en-us/dotnet/csharp/pattern-matching
Whichever option you go with, make sure you put this validation stuff in a separate class, maybe even a separate project. You can then add tests for each rule that you have to make sure everything works. This will also keep your controller light.
You haven't given examples of valid and invalid states, but I am guessing you're really talking about variations of those 3 parameters such as, when type is "something" then amount can only be < 200 and so_rep can only be "whatever". This can be done quite nicely with the FluentValidation library.
My Home Model/View/Controller (which configures the initial state of the page) is working fine.
I also, though, need to respond to changes the user makes on the page (selecting an option from a select, checking a checkbox, etc.), and have not got that to work yet.
Maybe the reason I'm having problems is that I'm trying to reuse my "Home" model, which contains not only what I need for page initialization, but some other things as well. For example, my model:
public class HomeModel
{
public DataTable Units { get; set; }
public DataTable Reports { get; set; }
public DataTable UnitReportPairEmailVals { get; set; }
public DataTable UnitReportPairGenerateVals { get; set; }
. . .
}
...contains things the page needs at first ("Units"and "Reports" and the things represented by the ellipsis dots), but also things only needed later (the other two shown).
I'm wondering if at least part of my problem with getting this data back (via an Ajax call to another method in HomeController) is because I should be using a separate Model and Controller for the Ajax call.
So I'm wondering: is Model/Controller proliferation a code smell/anti-pattern, or necessary? Should I create another Model like:
public class AJAXModel
{
public DataTable UnitReportPairEmailVals { get; set; }
}
...and a corresponding separate Controller for it?
If I have a complex Model, which is used in various scenarios, it seems that every time I pass a model back as the return value (result) of an Action, a lot of superfluous/unpopulated things will also be passed back (only the members that I'm interested in at the time being populated in the Controller, thus passing back a lot of empty/null members).
So my question is, should I create spearate Models/Controllers for each "use case", or is it okay - or even better - to combine a bunch of things into one Model/Controller pair?
There's no compelling reason to limit a Model to a single Controller or to expect that a Controller has only one Model. You could write your entire app in a single Controller (really bad idea, by the way).
Generally, the division is a logical one...a bunch of actions that talk to the same set of Models in one controller. It's more to keep your brain from melting when you open the source file as anything else.
You often have multiple Views and they tend to mach name-for-name with the Actions in your controller...but this isn't strictly enforced.
When you feel like you're getting more data in the View than necessary, this can be simplified by mapping the Model to a ViewModel to simplify the code in the View. Yes, this is MVVM...and again...the brain hurts less dealing with the simpler object in the View.
You can manually map the object in your Controller, or you can use an auto-mapper to do it. There are a number to choose from...and they make the MVVM a simpler thing to do. You don't necessarily need one. They're just helpful.
Consider below class being updated in database
public class ProductionLineItem
{
public int Id { get; set; }
public DateTime ProductionDate { get; set; }
public string HandledBy { get; set; }
public DateTime DateToMarket { get; set; }
}
void UpdateProductionRecord(ProductionLineItem existingRecord, ProductionLineItem modifiedRecord)
{
existingRecord.Id = modifiedRecord.Id;
existingRecord.ProductionDate = modifiedRecord.ProductionDate;
existingRecord.HandledBy = modifiedRecord.HandledBy;
existingRecord.DateToMarket = modifiedRecord.DateToMarket;
}
Customer wants to keep a log of all changed properties in dedicated table.
I should be doing something like this:
void UpdateProductionRecordWithLog(ProductionLineItem existingRecord, ProductionLineItem modifiedRecord)
{
existingRecord.Id = modifiedRecord.Id;
if (existingRecord.ProductionDate != modifiedRecord.ProductionDate)
{
existingRecord.ProductionDate = modifiedRecord.ProductionDate;
//Log: productionDate update form xyz to abc
}
if (existingRecord.HandledBy != modifiedRecord.HandledBy)
{
existingRecord.HandledBy = modifiedRecord.HandledBy;
//Log: HandledBy updated from Mr. John to Mr. Smith
}
if (existingRecord.DateToMarket != modifiedRecord.DateToMarket)
{
existingRecord.DateToMarket = modifiedRecord.DateToMarket;
//Log: DateToMarket updated form 2013 to 2014
}
}
For small number of properties it should be fine, but if properties goes beyond 15-20. I believe this would not be best way to do it.
Can I make my code more clean? I am open to use any framework like AutoMapper or so, If needed.
There are multiple elegant solutions to your problem, some of those include:
You could use Aspect Oriented Programming (AOP, for frameworks see this answer) to capture every modification to a property. You could save those changes for later retrival or invoke events which are then logged.
You could put Reflection (e.g. PropertyInfo) to good use here and iterate over all properties and compare the current value. This will spare you from writing all properties by hand.
Reflection and Attributes in conjunction with the Properties which are needed to be logged will work too. Using Attributes as a kind of post-it note on those properties which are important to be logged.
Be aware that Reflection might impose some performance penalities.
Do you use Entity Framework? It supports INotifypropertychanged, which could be used:
How to raise an event on Property Change?
If not, your classes could implement INotifyPropertyChanged() themselves - while not great (you have to write geteers / setters explicitly), it provides a better decoupling than invoking a loggin facility in the Properties directly (what if, if your logging is not available).
I would be worried about performance issues, so I might store logs and only write once in a while...
Well first you've done more than the requirement, in that you are only changing Existing item's properties if they are different.
Adding some new method to your class e.g. LogDifferences(ProductLineItem old, ProductLineItem new) and calling it from UpdateProductionItem would be good.
Personally I'd being going back to the Customer and saying what are you really trying to do and why, what they asked for smacks more of solution than requirement.
E.g. just log old record new record, like a DB transaction log. Do the an analysis of what changed when it's required.
One last possiblilty, that admittedly might cause more problems than it solves, is storing the values of the properties in say a Dictionary<String,dynamic> instead of discrete members.
Then logging changes based on Existing["ChangedToMarket"] = Modified["ChangedToMarket"] is fairly trival.
I've built an open source application, and I'd be curious to know how others are handling customer-specific requests. It's important to me to keep the app simple; I'm not trying to make it all things for all people. Apps can get bloated, complex, and just about unusable that way. However, there are some customer-specific options that would be nice (it just wouldn't apply to all customers). For example...
Say we have a domain entity called Server. In the UI, we let a customer pick from a list of servers. For one company, it's helpful to filter the servers by location (US, Germany, France, etc...). It would be easy enough to add a server property like this:
public class Server
{
public Location Location { get; set; }
// other properties here
}
My concern is that Server could become bloated with properties over time. And even if I only add location, not all customers would care about that property.
One option is to allow for user-defined fields:
public class Server
{
public string UserField1 { get; set; }
public string UserField2 { get; set; }
public string UserField3 { get; set; }
// etc...
// other properties here
}
Is that the best way to handle this? I don't like the fact that type safety is gone by making everything a string. Are there other/better ways that people are handling issues like this? Is there even a design pattern for something like this?
In my opinion, a good design pattern for something like this is to use schemas at the database level and then basic inheritance at the class level.
CREATE TABLE dbo.A (
ColumnA INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
ColumnB VARCHAR(50),
ColumnC INT,
etc.
)
And now we have a client who needs some specific functionality, so let's create an extension to this table in a different schema:
CREATE TABLE CustomerA.A (
ColumnA INT NOT NULL PRIMARY KEY,
Location VARCHAR(50)
)
But now we have another client who needs to extend it differently:
CREATE TABLE CustomerB.B (
ColumnA INT NOT NULL PRIMARY KEY,
DataCenterID INT
)
Though the fields may not be relevant, you get the idea, and so now we need to build the customer specific domain models here:
public abstract class A
{
public int ColumnA { get; set; }
public string ColumnB { get; set; }
public int ColumnC { get; set; }
}
public class CustomerA_A : A
{
public string Location { get; set; }
}
public class CustomerB_A : A
{
public int DataCenterID { get; set; }
}
And so now when we need to build something for Customer A, we'll build their subclass, and for Customer B theirs, and so on.
Now, FYI, this is the beginnings of a very dynamic system. I say that because the piece that's missing, that's not yet dynamic, is the user-interface. There is a significant number of ways that can be accomplished, but way outside the scope of this question. That is something you'll have to consider. I say that because the way you manage the interface will determine how you even know to build which subclass.
I hope this has helped.
The usual approach early on is to use the config XML files for this sort of thing. But programming for client-specific needs requires a whole mindset around how you program. Refer to this answer to a similar question.
Of course it always depends on how much customization you want to allow. In our product we went as far as enabling users to completely defined their own entities with properties and relations among them. Basically, every EntityObject, as we call our entities, in the end consists of a value collection and a reference to a meta-model describing the values within them. We designed our own query language that allows us to query the database and use expressions that are translate-able to any target language (although we currently only do SQL and .net).
The game does not end there and you quickly find that things like validation rules, permissions, default values and so on become a must have. Of course all of this then requires UI support, at least for the execution of the meta-model.
So it really depends on the amount of adjustment a end-user should be able to perform. I'd guess that in most cases simple user fields, as you described, will be sufficient. In that case I would provide a single field and store JSON text within that. In the UI you can then provide at least a semi-decent UI allowing structure and extensibility.
Option 1: Say "no". :-)
And while I say that (half) jokingly, there is some truth to it. Too often, developers open themselves up to endless customization by allowing one or two custom features, setting the snowball in motion.
Of course, this has to be balanced, and it sounds like you may be doing this to an extent. But if you truly want to keep your app simple, then keep it simple and avoid adding customizations like this.
Option 2: Inheritance.
If you really need to add the customization, I would lean the way of building a base class with all "standard" options, and then building customer-specific classes containing customer-specific optimizations.
For example:
public class Server
{
// all standard properties here
}
Then for Joe's Pizza, you can have:
public class JoesPizzaServer : Server
{
public Location Location { get; set; }
}
The side-benefit to this is that it will allow you to base your presentation views off of the client-specific (or base) models.
For example, in MVC you could set up your view models like this, and then you could have specific views for each customer.
For example, Bob's Burgers would have its own view on the base model:
#model MyApp.Server
#* implement the base form *#
And Joe's Pizza's view would use the custom model:
#model MyApp.JoesPizza
#* implement the base form -- a partial view -- with addtional custom fields
MVC does a really good job of supporting this type of pattern. If you're not using MVC (maybe WPF or Web Forms), there are still ways to leverage partial "view" files for accomplishing something similar.
Of course, your database can (and probably should) support a similar inheritance model. Entity Framework even supports various inheritance models like this.
I may be wrong here, but it looks like you want to handle different versions of your software with the same code base. I can think of two approaches for this:
Actually define different versions for it and handle changes for each client. This won't give you problems from the domain-modeling point of view, but will require a supporting infrastructure, which will have to scale according to your client requirements. There are some related questions out there (e.g. this, this and this).
Handle this at the domain-model level, as a user-defined configuration. The advantage of this approach is that you don't have to incorporate multiple versions of your software, but this comes at the expense of making your model more generic and potentially more complex. Also your tests will surely have to be adapted to handle different scenarios. If you are going in that direction I would model an object representing the attribute (with a name and a value) and consider the Server class as having a collection of attributes. In that way your model still captures your requirements in an OO style.
HTH
I approach from Python that I think would work rather well hear is a dictionary. The key is your field name, the value is the, errrrr... value ;)
It'd be simple enough to represent in a database too.
From my experience many validation frameworks in .NET allow you to validate a single field at a time for doing things like ensuring a field is a postal code or email address for instance. I usually call these within-field edits.
In my project we often have to do between-field-edits though. For instance, if you have a class like this:
public class Range
{
public int Min { get; set; }
public int Max { get; set; }
}
you might want to ensure that Max is greater than Min. You might also want to do some validation against an external object. For instance given you have a class like this:
public class Person
{
public string PostalCode { get; set; }
}
and for whatever reason you want to ensure that Postal Code exists in a database or a file provided to you. I have more complex examples like where a user provides a data dictionary and you want to validate your object against that data dictionary.
My question is: can we use any of the existing validation frameworks (TNValidate, NHibernate Validator) for .NET or do we need to use a rules engine or what?? How do you people in the real world deal with this situation? :-)
There's only one validation framework that I know well and that is Enterprise Library Validation Application Block, or VAB for short. I will answer your questions from the context of the VAB.
First question: Can you do state (between-field) validation in VAB?
Yes you can. There are multiple ways to do this. You can choose for the self validation mechanism, as follows:
[HasSelfValidation]
public class Range
{
public int Min { get; set; }
public int Max { get; set; }
[SelfValidation]
public void ValidateRange(ValidationResults results)
{
if (this.Max < this.Min)
{
results.AddResult(
new ValidationResult("Max less than min", this, "", "", null));
}
}
}
I must say I personally don't like this type of validations, especially when validating my domain entities, because I like to keep my validations separate from the validation logic (and keep my domain logic free from references to any validation framework). However, they need considerably less code than the alternative, which is writing a custom validator class. Here's an example:
[ConfigurationElementType(typeof(CustomValidatorData))]
public sealed class RangeValidator : Validator
{
public RangeValidator(NameValueCollection attributes)
: base(string.Empty, string.Empty) { }
protected override string DefaultMessageTemplate
{
get { throw new NotImplementedException(); }
}
protected override void DoValidate(object objectToValidate,
object currentTarget, string key, ValidationResults results)
{
Range range = (Range)currentTarget;
if (range.Max < range.Min)
{
this.LogValidationResult(results,
"Max less than min", currentTarget, key);
}
}
}
After writing this class you can hook this class up in your validation configuration file like this:
<validation>
<type name="Range" defaultRuleset="Default" assemblyName="[Range Assembly]">
<ruleset name="Default">
<validator type="[Namespace].RangeValidator, [Validator Assembly]"
name="Range Validator" />
</ruleset>
</type>
</validation>
Second question: How to do complex validations with possible interaction a database (with VAB).
The examples I give for the first question are also usable for this. You can use the same techniques: self validation and custom validator. Your scenario where you want to check a value in a database is actually a simple one, because the validity of your object is not based on its context. You can simply check the state of the object against the database. It gets more complicated when the context in which an object lives gets important (but it is possible with VAB). Imagine for instance that you want to write a validation that ensures that every customer, at a given moment in time, has no more than two unshipped orders. This not only means that you have to check the database, but perhaps new orders that are added or orders are deleted within that same context. This problem is not VAB specific, you will have the same problems with every framework you choose. I've written an article that describes the complexities we're facing with in these situations (read and shiver).
Third question: How do you people in the real world deal with this situation?
I do these types of validation with the VAB in production code. It works great, but VAB is not very easy to learn. Still, I love what we can do with VAB, and it will only get better when v5.0 comes out. When you want to learn it, start with reading the ValidationHOL.pdf document that you can found in the Hands-On Labs download.
I hope this helps.
I build custom validation controls when I need anything that's not included out of the box. The nice thing here is that these custom validators are re-usable and they can act on multiple fields. Here's an example I posted to CodeProject of an AtLeastOneOf validator that lets you require that at least one field in a group has a value:
http://www.codeproject.com/KB/validation/AtLeastOneOfValidator.aspx
The code included in the download should work as an easy to follow sample of how you could go about it. The downside here is that Validation controls included with ASP.Net don't often work well with asp.net-ajax.