Is there a .Net attribute that will tell Breeze to completely ignore a property?
I know that making the property protected is one way to hide it from Breeze and prevent its serialization, but what if I would like it to remain public
?
Is there a .Net attribute that will tell Breeze to completely ignore a property?
I know that making the property protected is one way to hide it from Breeze and prevent its serialization, but what if I would like it to remain public
?
If you are using the Json.Net serializer ( the Breeze.WebApi default) you can use the JsonIgnoreAttribute, described here
It is tricky to devise an easy, maintainable way to have EF-generated metadata say one thing to the client and another to EF itself.
But you can do it if you're willing to have two DbContexts: the "real" DbContext for server-side model operations and another DbContext strictly for client metadata generation.
A DbContext for Metadata
It isn't as difficult as it sounds. I experimented with such a thing in DocCode. I created a
NorthwindMetadataContext
that inherits from theNorthwindContext
. It hides the disusedCustomerID_OLD
property.Here is that DbContext in its entirety:
You read that right! I simply add a single EF Fluent API instruction to hide the
CustomerID_OLD
property from theNorthwindMetadataContext
.It's still on the
Customer
type and it's still known to the baseNorthwindContext
. That means a query will return theCustomerID_OLD
property when you query with theNorthwindContext
but will not return the property when you query with theNorthwindMetadataContext
.Of course you only use the
NorthwindMetadataContext
to generate metadata for the Breeze client. All of your server logic continues to use the "real", baseNorthwindContext
I make sure that's what happens by changing the way the
NorthwindRepository
implements theMetadata
property:All other members of the
NorthwindRepository
use an EFContextProvider for the "real" DbContext:This works like a charm. As far as the client know, the
CustomerID_OLD
property doesn't exist.Try to keep the hidden data off the wire
Although you've hidden the property from Breeze clients, the property remains on the server-side entity type and, because we use the "real" DbContext for the query and save operations, you can see the
CustomerID_OLD
property going over the wire in the query results payload.To keep that from happening, you can add the JSON.NET serializer
[JsonIgnore]
attribute to theCustomer.CustomerID_OLD
property in the model (you use other JSON.NET configuration options if you don't want to pollute your model with JSON.NET serialization attributes).Run again and
CustomerID_OLD
is no longer serialized. TheCustomerID_OLD
property is now completely invisible to the client while still accessible in your model on the server.BEWARE
The property that is hidden in metadata is hidden from Breeze clients ... but not from the world. Because you want that property available on the SERVER-SIDE TYPE, an evil client (not a Breeze client) can still GET that data with a projection even though you have hidden it when serializing the complete type.
The following query URL returns projection data that include the
CustomerID_OLD
that would be invisible if you queried for entireCustomer
objects.Here is a bit of the result:
Perhaps more seriously, a POST can update to that hidden property in the payload of a "SaveChanges" request.
As always with sensitive data, you must inspect every save request to make sure that the user is permitted to save each and every changed property value identified in the
OriginalValues
collection.If you have security concerns, I feel it is much safer to use DTOs for types that carry data that must not be exposed to unauthorized clients. I don't like DTOs for every type; that's overkill that can ruin productivity. But I do like them for entity types with significant confidentiality requirements.
Example code
I have not yet decided if I will keep this example in the published DocCode or stash it in my private reserve. It is a cool trick.
My worry is that people will think this technique is a secure way to hide confidential data which it definitely is not. It's fine for hiding data that you'd rather keep hidden. But if it MUST be kept off the wire, you better use a DTO.
Let me know if what I've described is clear enough for you to proceed without a concrete example.