4

I've been trying to find a flexible way of exposing an object through a 'view'. I'm probably better off explaining by way of example.

I have an Entity Framework entity model, and a web service that can be used to query it. I am able to return the entity classes themselves, but this would include some fields I might not want to share - IDs, for examples, or *Reference properties from any associations in the entity model.

I figure what I need is a view of the data, but I don't particular want to write a view wrapper class for every return type. I'm hoping I'll be able to define an interface and somehow make use of that. For example:

interface IPersonView
{
     string FirstName { get; }
     string LastName { get; }
}

-

// (Web service method)
IPersonView GetPerson(int id)
{
    var personEntity = [...];
    return GetView<IPersonView>(personEntity);
}

However, in order to do something like this, I'd have to have my entities implement the view interfaces. I was hoping for a more flexible 'duck-typed' approach as there may be many views of an object, and I don't really to want to have to implement them all.

I've had some success building a dynamic type by reflecting the interface and copying fields and properties across, but I'm not able to cast this back to the interface type in order to get strong typing on the web service.

Just looking for some comments and advice, both would be welcome. Thanks.

leppie
  • 115,091
  • 17
  • 196
  • 297
Barguast
  • 5,926
  • 9
  • 43
  • 73
  • Why don't you use [Data Contracts](http://msdn.microsoft.com/en-us/library/ms733127.aspx)? – Alex Filipovici Jan 24 '13 at 14:38
  • @Barguast: The casting should be pretty simply as you have the type as a generic type parameter. Maybe you can expand on what exactly was your problem with that approach – Daniel Hilgarth Jan 24 '13 at 14:40
  • You will have to define which properties to include and which to omit, maybe some type conversions. This could be done in many ways but explicit POCOs/DTOs or marking your entitities with attributes seem like the most straight forward options. This can't happen by magic. – Jodrell Jan 24 '13 at 14:45
  • The correct term in your case would be “data transfer object”, not views. Also note that WCF (and anything that uses SOAP for communication) does not support transferring interfaces (neither as parameter nor as return value) and dynamic types do not work either, as both client and server need to know the type beforehand. – poke Jan 24 '13 at 14:46
  • I've used DTO a lot, this idea actually came from it. The idea was that these interfaces simply define what properties of another object should be sent via the web service. I know that DTOs can be made to do this, but for the reason I gave in D Stanley's answer, I was hoping there might be another way. – Barguast Jan 24 '13 at 15:14

2 Answers2

3

You shouldn't ever really be passing entities directly out to a client, they should be used for persistance only. You should introduce DTOs/POCOs tailored to whatever data your API wants to return e.g.

public class PersonDto
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

// public API method
public PersonDto GetPersonApi(int id)
{
    var personEntity = // pull entity from db
    return new PersonDto()
    {
        FirstName = personEntity.FirstName,
        LastName = personEntity.LastName
    };
}

This keeps a clean separation between your persistence layer & public interface. You can use a tool like AutoMapper to do the legwork in terms of mapping the data across. Just setup a mapping once e.g. in your global asax:

protected void Application_Start()
{
    Mapper.CreateMap<Person, PersonDto>();
}
...
// public API method
public PersonDto GetPersonApi(int id)
{
    var personEntity = // pull entity from db
    return Mapper.Map<Person, PersonDto>(personEntity);
}
Community
  • 1
  • 1
James
  • 80,725
  • 18
  • 167
  • 237
  • I agree that AutoMapper or similar can help remove some tedium but, it is not challanging to create and maintain by hand. The manual method does offer the most flexibility. – Jodrell Jan 24 '13 at 14:56
  • @Jodrell Yep I agree, however, if you find yourself doing this all over the place or even just trying to map objects with lots of properties that's where the real benefit of AutoMapper (and the likes) comes in. – James Jan 24 '13 at 15:06
  • Thanks, I'm used to doing it the DTO way, I just often find myself needing various representations of the same entity. For example, some clients may need the name of the Person. Others may also need the date of birth. Others may also need the Company that person belongs to, or a list of colleagues, etc. These are effectively all different 'views' of the same entity, and I was hoping to be able to define this view as a structure-hinting interfaces rather than creating a DTO for each scenario. – Barguast Jan 24 '13 at 15:12
  • @Barguast if you wanted to get clever with AutoMapper for example, you could create dynamic property mappings which (based on config) would only map certain properties and leave the rest null/empty. However, it would be *far* more easier just to map the properties you need manually per each API call. – James Jan 24 '13 at 15:18
1

I typically see this done with AutoMapper or a similar tool. It makes mapping between similar classes much simpler. You still have to create the Views (which in an MVC-context would be a Model), but the most tedious part (the mapping) is taken care of for you so long as you use the same field names.

As a side note, sharing IDs and other reference data will be necessary if you want to update the data, since you'll need to know the keys in order to know which record(s) to update.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • I agree that AutoMapper or similar can help remove some tedium but, it is not challanging to do by hand. The manual method does offer the most flexibility. – Jodrell Jan 24 '13 at 14:55
  • I'll have a look at this tool and see if it'll help me. Thanks. – Barguast Jan 24 '13 at 15:15