views:

259

answers:

2

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.

+1  A: 

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.

casperOne
This is the simplest and, I believe, the totally correct answer.
EnocNRoll
Very simple and intuitive...I'll give it a shot. Thanks!
Keith
+1  A: 

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.

Code Monkey