How to prevent private properties in .NET entities from being exposed as public via services? - wcf

I'm creating a WCF service that transfers entity objects created via entity framework. I have a User entity that maps to a User db table. There are certain User fields (Password, DateCreated, etc) that I don't want to expose to the client but, because they are non-nullable in the db, Visual Studio requires mappings. Setting these properties as private seems like a good workaround but these properties are converted to public when consumed by a client.
Is there a way around this, or a better approach to take? I'd rather avoid changing these fields at the db level just to make EF happy.

This sounds like to perfect opportunity to segregate the layers of the application. What you should do is create objects that are specific to the WCF layer that act only as Data Transfer Objects (DTO) to the outside consumers.
So, in your WCF service layer you make will your calls to your data access layer (Entity Framework) which retrieves User objects and you should return to your consumer objects constructed with only what you want to expose.
If you do this, you can explicitly control what you make visible to the outside world and also hide any implementation details about what you are doing from a data storage perspective.
As an extremely crude example, in your Entity Framework layer you might have this object:
namespace ACME.DataAccessLayer.Entities
{
public class User
{
public int Id { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Hash { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
namespace ACME.DataAccessLayer.Services
{
using ACME.DataAccessLayer.Entities;
public class UserService
{
public User GetUser(int id)
{
using (ACMEDataContext dc = new ACMEDataContext())
{
// psuedo code to return your user with Entity Framework
return dc.Users.FirstOrDefault(user => user.Id == id);
}
}
}
}
Then in your WCF later you might have an entity like:
namespace ACME.Services.DataTransferObjects
{
[DataContract]
public class User
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
}
}
Then you would expose a service endpoint that would return back the DTO as such:
namespace ACME.Services
{
using ACME.DataAccessLayer.Services;
public class PublicWCFService : IUserService
{
public ACME.Services.DataTransferObjects.User GetUser(int userId)
{
ACME.DataAccessLayer.Entities.User entityFrameowrkUser = new UserService().GetUser(userId);
return new ACME.Services.DataTransferObjects.User
{
Id = entityFrameowrkUser.Id,
FirstName = entityFrameowrkUser.FirstName,
LastName = entityFrameowrkUser.LastName
};
}
}
}
Now what you would do is just return the DTO object which will not have any of the attributes, or methods that you may have in the real entities you use in your system.
With this approach, you can safely break the layers of the application into different layers (DLLs) that can easily be shared and extended.
This is a quick example, so let me know if there's anything further that would make this example more clear.

You could always implement IXmlSerializable on the entity object. Then, you would be able to dictate the structure of what is sent to the client (the client would get a different representation, obviously).
Either that, or if you can, add the DataContract attribute to the type, and the DataMember attribute to only the properties you wish to send over the wire.

Related

Create a Parent with existing children in EntityFramework core

I am building a Web API and have two models: Task and Feature:
public class Feature
{
[Key]
public long FeatureId { get; set; }
public string Analyst_comment { get; set; }
public virtual ICollection<User_Task> Tasks { get; set; }
public Feature()
{
}
}
public class User_Task
{
[Key]
public long TaskId { get; set; }
public string What { get; set; }
[ForeignKey("FeatureId")]
public long? FeatureId { get; set; }
public User_Task()
{
}
}
I create Tasks first and then create a Feature that combines few of them. Task creation is successful, however while creating a Feature with existing Tasks, my controller throws an error saying the task already exists:
My FeatureController has following method:
//Create
[HttpPost]
public IActionResult Create([FromBody] Feature item)
{
if (item == null)
{
return BadRequest();
}
** It basically expects that I am creating a Feature with brand new tasks, so I guess I will need some logic here to tell EF Core that incoming tasks with this feature already exist **
_featureRepository.Add(item);
return CreatedAtRoute("GetFeature", new { id = item.FeatureId }, item);
}
How to tell EF core that incoming Feature has Tasks that already exist and it just needs to update the references instead of creating new ones?
My context:
public class WebAPIDataContext : DbContext
{
public WebAPIDataContext(DbContextOptions<WebAPIDataContext> options)
: base(options)
{
}
public DbSet<User_Task> User_Tasks { get; set; }
public DbSet<Feature> Features { get; set; }
}
And repo:
public void Add(Feature item)
{
_context.Features.Add(item);
_context.SaveChanges();
}
When calling Add on a DBSet with a model that was not loaded from EF, it thinks it is untracked and will always assume it is new.
Instead, you need to load the existing record from the dbcontext and map the properties from the data passed into the API to the existing record. Typically that is a manual map from parameter object to domain. Then if you return an object back, you would map that new domain object to a DTO. You can use services like AutoMapper to map the domain to a DTO. When you're done mapping, you only need to call SaveChanges.
Generally speaking, loading the record and mapping the fields is a good thing for the security of your API. You wouldn't want to assume that the passed in data is pristine and honest. When you give the calling code access to all the properties of the entity, you may not be expecting them to change all the fields, and some of those fields could be sensitive.

Silverlight WCF reused types no methods

I feel like this should be really simple but I am having an issue figuring out what is going on. I am working with a WCF service and have "Reuse types in all referenced assemblies" on. I have some simple classes to transfer some data. The classes show up fine and all the basic members show up, but no methods do. Are methods not included in this? Do I have to specify this is what I want somehow? Here is some example code. I just switched out my names to make it a little more generic.
public class Car
{
public string CarColor { get; set; }
public string Model { get; set; }
public int Year { get; set; }
public string GenerateId()
{
return CarColor + Model + Year;
}
}
In this example I get CarColor, Model, and Year on the client side but not GenerateId.
So I ended up doing this a little different. It totally makes sense that only the data comes over. The problem is that I didn't want to have to have a new project to hold the data types. Its just a pain to have a new repository and a completely separate project for a handful of classes. Since I really only need the methods on the client side, I am just creating partial classes with them in it on the client side. That way I can pull the data structure from the service but still extend it to have the methods I need.
Service definition
public class Car
{
public string CarColor { get; set; }
public string Model { get; set; }
public int Year { get; set; }
}
Client partial class
public partial class Car
{
public string GenerateId()
{
return CarColor + Model + Year;
}
}

asp.net web api controllers accept POCO or generic data

I am new with ASP.NET Web API and have been researching this for some time now. Admittedly, I have decision paralysis. I want to make a REST-like API for a system with about 250 tables in the database. It's basically a 2 tier system with a UI and a data access layer, not using business objects or ORM.
I cannot decide if my Web API Controllers should accept/return:
a) IDictionary of name/value pairs, which I would package into sql parameters and pass to the data access layer and return a serialized ado.net data table
b) strongly typed complex object (POCO objects). For example: Account class with all properties matching up with fields in the database.
If I have to create POCO classes for every table in the system, there would be 250+ classes that essentially do nothing except package the data and pass it to our data access layer.
Further, it seems as if I need to create an ApiController for basically every table in the database that I want to expose via the Web Api because you only have GET, POST, PUT, DELETE per route? Please help, banging head on desk.
Please see answers below:
1.**Using **"IDictionary of name/value pairs" is fine if your resource supports GET methods only. If you want users to post or update data, how will you validate the data? In addition, if you want to add HATEOAS, how would you do that? In terms of extension, how would you support nested object hierarchy like the one below:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
public IList<PurchaseDetail> PurchaseHistory { get; set; }
}
public class PurchaseDetail
{
public int Id { get; set; }
public DateTime PurchaseDate { get; set; }
public decimal Cost { get; set; }
}
2. You can have more than one GET, POST,etc per resources by defining different routes. More from this link http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

DTOs and WCF RIA

I have a DTO which has a collection within it of another DTO which I populate server-side and send to the client. However, this inner DTO collection is not returned to the client.
I believe I need to use the [Include] and [Association] attributes so that WCF RIA services knows what to do, however my issue with this is there is no real association as such between the main DTO and the inner DTO collection, I am just using it to aggregate data from various sources for return to the client.
Is my understanding wrong in what I am trying to achieve, if not how do I get WCF RIA to send this inner DTO collection.
I should add that I am using automapper and want to achieve it using such.
Here is an example, I want to send back to the client in one chunk;
The competencies that the employee has.
The competencies that the employee requires for their job.
The GAP, which is the difference between 1 and 2.
public class CompetencyRequirementsDto
{
[Key]
public string CompanyId { get; set; }
[Key]
public string EmployeeNo { get; set; }
public string JobId { get; set; }
[Include]
[Association("EmployeeCompetencies","CompanyId, EmployeeNo","CompanyId, EmployeeNo")]
public IList<EmployeeCompetencyDto> EmployeeCompetencies { get; set; }
[Include]
[Association("JobCompetencies","JobId, CompanyId","JobId, CompanyId")]
public IList<JobCompetencyDto> JobCompetencies { get; set; }
[Include]
[Association("CompetencyGap", "JobId, CompanyId", "JobId, CompanyId")]
public IList<JobCompetencyDto> CompetencyGap { get; set; }
} }
Now item 1 works fine, but 2 and 3 don't? What I have found is that my DTO is created ok server side but when it gets to the client CompetencyGap(even when it has no values) has
been given JobCompetencies values.
If you are using ADO.Net Entity data model and using RIA Services against them then you have got an option to create associated metadata.
So to get the reference entities at you client side we need to modify both the our corresponding meta-data and as well as well the function of the domain service class which is fetching your data .
Here I am giving an example...
1. Just add [Include] attribute at the the top of the referenced data for example.
[MetadataTypeAttribute(typeof(Customer.CustomerMetadata))]
public partial class Customer
{
// This class allows you to attach custom attributes to properties
// of the Customer class.
//
// For example, the following marks the Xyz property as a
// required property and specifies the format for valid values:
// [Required]
// [RegularExpression("[A-Z][A-Za-z0-9]*")]
// [StringLength(32)]
// public string Xyz { get; set; }
internal sealed class CustomerMetadata
{
// Metadata classes are not meant to be instantiated.
private CustomerMetadata()
{
}
public int CustomerID { get; set; }
public string EmailAddress { get; set; }
public string FullName { get; set; }
[Include]
public EntityCollection<Order> Orders { get; set; }
public string Password { get; set; }
}
}
2. Modify the function in the domain service and add include there also for example.
public IQueryable<Customer> GetCustomers()
{
var res = this.ObjectContext.Customers.Include("Orders");
return res;
}
In your case the first part is done you just need to modify your domain service query to get reference entities.

Is the properties in Entity must be virtual when using FluentNhibernate?

Which entity FluentNHibernate uses as entity
I create some entity in Domain(or BLL), such as the following:
public class Role
{
public long ID { get; protected set; }
public string Name { get; set; }
public string Description { get; set; }
public List<User> Users { get; set; }
public Role()
{
Users = new List<User>();
}
}
And I want make use of FlunetNHibernate to map them, but get errors:
The following types may not be used as proxies:
Freeflying.Domain.Core.Profile: method get_ID should be 'public/protected virtual' or 'protected internal virtual'
Yes, I recall the programmer requirement when use FluentNHibernate, the entity should be like this:
public class Role
{
public virtual long ID { get; protected set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
}
But It looks wired. Do you think so? How do you do when using FluentNHibernate? I don't want go back to Domain layer and add virtual for every property.
This is a basic requirement for using NHibernate; It allows NHibernate to generate a proxy class that descends from your class for lazy loading and such.
I have not seen a method of removing this requirement, though if such a thing is possible it would mean that you could not use lazy loading of objects and/or properties.
Here's a blog post that explains this a bit more; It also offers a way to avoid marking your properties as virtual, although I would really recommend that you do not use this method (marking classes to avoid lazy loading) as the benefits of lazy loading in most circumstances far outweigh the cost of making your properties virtual.