I am using breeze with Web API. I don't have a good grasp on how to "Filter columns" or how to not expose and entire table to my Web API. I am using the Entity Framework as my source, and both of my questions are addressed by John Papa here: http://www.johnpapa.net/spajs04/#comment-113761 and confirmed to be a good solution by Ward Bell below. Can someone please show me how I to use the entity framework to create a partial or projection that is queryable in my webapi and will work with breeze?
Here is my current function in the webapi
[HttpGet]
public IQueryable<Contact> GetContacts()
{
return _contextProvider.Context.Contact;
}
Here is my current class:
public class Contact
{
[Key]
public Guid ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string NickName { get; set; }
public string JobTitle { get; set; }
public DateTime BirthDate { get; set; }
public bool Gender { get; set; }
public string SSN { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateUpdated { get; set; }
public virtual ICollection<Address> Address { get; set; }
}
I would like to have a queryable webapi function that is my current class WITHOUT the SSN field. A solution that works a "database first" entity and does not involve changing my database or adding "views" would be great.
Client-side projection is fine when you're trying to reduce the payload. You need something server-side when you must ensure that certain data (e.g., SSN) are truly and safely hidden from the client.
@james suggestion - to use the [NonSerialized]
(or JSON.NET's [JsonIgnore]
attribute) - is an easy and effective approach when the SSN should never go to the client.
It's too inflexible if the SSN should be visible on the client in authorized circumstances (e.g., a user reviewing her own SSN or an HR person with the right to see the SSN). The JSON.NET IContractResolver gives you tremendous flexibility in deciding dynamically, based on authorization rules, what properties may cross the service boundary.
Some might consider addressing this problem with the serializer as too much of a hack. They might be satisfied by the server-side projection that you showed, @chris_dotnet. Btw, it still makes sense to return an IQueryable
from the projection so that the client can reduce the network payload with a filtering query.
Others will prefer to define a DTO (ContactDTO
) and serialize that over the wire.
[HttpGet]
public IQueryable GetContacts()
{
return _contextProvider.Context.Contacts
.Select(p =>
new ContactDto
{
FirstName = p.FirstName,
ID = p.ID,
LastName = p.LastName
});
}
This IQueryable
is more robust than the projection version because the filtering can take place on the data tier rather than the server tier.
On the client-side you can either define metadata for the ContactDto
type or you can use a JsonResultsAdapter
to map the ContactDto
data into a Contact
Breeze entity.
Using the JsonResultsAdapter
presupposes that you actually want the Contact
type - the type as it is shaped in the business model on the server - to be known on the client.
You may not want the server-side Contact
shape to be exposed from your service. Many people feel really strongly about this. If you are one of those people, you're better off defining a "DTO Model" representing the entities as you want them to be seen on the client. That means learning to create metadata for your DTO model and writing mapping logic on the server to move between DTOs and your business model.
You can see how all of this can become a big topic. It's one that I'll be taking up soon in the Breeze documentation. Consider this answer a taste of things to come. The take-away is ... you have good choices for hiding data that users' shouldn't see.
Thanks John for this info, I took a look at that and it was helpful for client side filtering. I found that I could do it from client side and/or server side.
Client side with breeze:
var query = EntityQuery.from("Customers")
.select("ID, FirstName, LastName");
Server side:
[HttpGet]
public IQueryable<Contact> GetContacts()
{
var contactList = _contextProvider.Context.Contacts
.ToList()
.Select(p =>
new Contact
{
FirstName = p.FirstName,
ID = p.ID,
LastName = p.LastName
})
.AsQueryable(); // actually IQueryable is not useful after "ToList()"
return contactList ;
}
Chris - There is an example of this in the course with the speaker and session partials. I return projections from those where i do not return the description field (for sessions) nor the bio field (for speakers). Check that out and use the same style for not showing your SSN field for your Employee class
Can't you mark your attribute as [NonSerialized]
[NonSerialized]
public string SSN { get; set; }
I've just found another solution to ignore columns depending on criterias. Just add a partial class (my model gets generated) belonging to the model of interest and use the ShouldSerialize%PropertyName%
:
namespace ProvSys.Models
{
partial class tblEmployees
{
public static bool ShouldSerializeResetPassword()
{
// Only hand over ResetPassword Field for admin role
return (ProvSysRepository.IsAdmin);
}
}
}
In this sample the ResetPassword
property of the tblEmployees
table gets transmitted only if the user is in the admin role.