Click here to Skip to main content
15,881,938 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hi,

I’m using EF-Code first / MVC4 / C# for a number of projects now. Overall I’m really happy with the robustness and testability of the code, one kind of error however keeps popping up that I would like to obliterate once and for all.

Between different layers of the solution I’m passing (DB) identifiers, from controller to repository, from DB to viewmodel, from view back to controller and such. I found it quite easy to pass the wrong identifier to any such layer. Say a repository expects an Order-Id and receives an OrderStatus-Id. (They’re both basically int32) It seems to happen most of the time when someone refactors or rewrites a part of the code and inadvertently returns the wrong Id. Sometimes this is caught by unit/functional testing, but sometimes it only surfaces in production. This could be solved by simply passing an entire order-class and letting the receiver pick the ID from that, but I feel they’re a bit too heavy to be passing around all the time when all I need is the ID.

My solution so far:
Since I’m using poco classes I added a type Identifier class to each poco class with a sealed constructor and a function on the class to instantiate the new Identifier class. (See below) So an instance of the order-class can only create an orderIdentifier-class. In repositories and such I can now simply replace the Int with a type-safe identifier; for example OrderIdentifier.

POCO:
SQL
namespace x.Models
{
    public class Customer
    {
        public int Id { get; set; }
// Lots of fields
        public CustomerId Identifier()
        {
            return new CustomerId(this);
        }
    }

    public sealed class CustomerId
    {
        // The identifier for read-only access
        public int Value { get; private set; }
        public CustomerId(Customer data)
        {
            Value = data.Id;
        }
    }
}



Repository:
public static string Config(CustomerId customerId)


This seems to work great except when I need to pass data from the view back to the controller. Ideally I’d write something like this:

Razor: (* using T4MVC)
@Html.ActionLinkButton("Edit",MVC.Customer.Config(CustomerItem.Identifier())) 


Controller:
C#
public virtual ActionResult Config(CustomerId CustomerId)
{
// Do stuff with CustomerId
}



This works great with a primitive types like INT32, but not so with a complex object like CustomerId. (Since obviously MVC simply iterates all the properties), the resulting CustomerId remaines null.

Questions:
1) Is this a solid solution for attaining type safety for identifiers or are there other (better) solutions?
2) Is there a fix for this solution so it becomes usable from view>controller without relying on tempdata and the likes?
Posted
Comments
Dave Kreskowiak 28-Jul-13 10:23am    
What's going to stop you from putting the wrong value in CustomerId?
Martijn Hoedeman 28-Jul-13 13:31pm    
You can't directly put a value into CustomerId, it's got a private set so the property can only be set by the constructor. This way I can guarantee that the CustomerId is always created from an exiting Customer record, since that is the only argument that the constructor allows.
Martijn Hoedeman 29-Jul-13 1:06am    
For now I've added a serializer and deserializer so the class can be stored in a string and passed back to the controller that way. I've included the type of the object so when running the deserializer I compare and throw if its a wrong type. In effect this moves the validation from compile time to run time, not ideal but at least unit-test will always catch the error.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900