Returning specifically shaped POCOs to ASP.NET MVC actions - asp.net-mvc

In my ASP.NET MVC project, my actions typically call a Service layer to get data. I use the same dozen or so POCOs for all my models. I also plan on using the Service layer in console applications and maybe expose a web api at some point.
To make my database operations more efficient, my service layer only hydrates the properties in the model that are relevant to the particular method (which at this point is mostly driven by the needs of my controller actions).
So for example I might have a class Order with properties Id, Name, Description, Amount, Items. For a given service call I might only need to populate Id, Name, Items. A consumer of that service won't necessarily know that Amount is 0 only because it didn't populate the property.
Similarly, the consumer won't know whether Items is empty b/c there actually aren't any items, or whether this particular service method just doesn't populate that property.
And for a third example, say one of my views displays an ItemCount. I don't want to fully populate my Items collection, I just need an additional property on my "model". I don't want to add this property to my POCO that other service methods will be using because it's not going to be populated anywhere else.
So the natural solution is to make a POCO designed specifically for that method with only those 3 properties. That way the consumer can know that all properties will be populated with its real values. The downside to this is that I'll end writing tons of similarly shaped models.
Any advice on which method works best?

You could use Nullable Types to indicate the missing properties with a null.
For example:
class Order {
public int Id {get;set;}
public string Name {get;set;}
public string Description {get;set;}
public decimal? Amount {get;set;}
public List<Item> Items {get;set;}
}
And then if Items == null, it wasn't set. If it's an empty new List<Item>(), it's set but empty. Same for Amount. If Amount.HasValue == false, it wasn't set. If Amount.Value is 0.0d, it's set and the item is free.

Why don't you use LINQ projection?
One service method does something like:
return DbContext.Orders.Select(o => new { Id = o.Id, Name = o.Name, Description = o.Description });
while the other service method does something like:
return DbContext.Orders.Select(o => o);
I'm not sure how your application is architected, but this may be a way around creating 100's of POCO's.
Hope this helps! Good luck.

You could pass in a selector Func that returns dynamic:
public IEnumerable<dynamic> GetOrders(Func<Order, dynamic> selector) { ... }
I'm not sure how you are accessing data, but the following shows how this would work using a List<T>:
class Program
{
static void Main(string[] args)
{
var service = new Service();
var orderNames = service.GetOrders(o => new { o.Name });
foreach (var name in orderNames)
Console.WriteLine(name.Name);
Console.ReadLine();
}
}
public class Service
{
private List<Order> _orders = new List<Order>
{
new Order { Id = 1, Name = "foo", Description = "test order 1", Amount = 1.23m },
new Order { Id = 2, Name = "bar", Description = "test order 1", Amount = 3.45m },
new Order { Id = 3, Name = "baz", Description = "test order 1", Amount = 5.67m }
};
public IEnumerable<dynamic> GetOrders(Func<Order, dynamic> selector)
{
return _orders.Select(selector);
}
}
public class Order
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Amount { get; set; }
}

The use of nullable values is a good solution, however it has the downside you have no way to matk required fields. That is you cannot use a required attribute on any property. So if there is field that is obligatory in some views you have no way to represent it.
If you don't need required fileds validation this is ok. Otherwise, you need a way to represent which fileds are actually used, and then to write a custom validation provider.
A simple way to do this is to use a "Mask" class with the same property names of the original class, but with all fields boolean: a true values means the field is in use.
I used a similar solution in a system where the properties to be shown are configured in a configuration files...so it was the unique option for me since I had no possibility to represent all combination of properties. HOWEVER, I used the "Mask" class also in the View, so I was able to do all the job with just one View..with a lot of ifs.
Now if your 150 service methods and probably about 150 Views...are all different, then maybe it is simpler to use also several classes ...that is in the worst case 150 classes..the extra work to write them is negligible if compared to the effort of preparing 150 different Views.
However this doesnt mean you need 150 POCO classes. You might use an unique POCO class that is copied into an adequate class just into the presentation Layer. The advantage of this approach is that you can put different validation attributes on the various classes and you don't need to write a custom Validation provider.

Return the entire POCO with nullable types as mentioned by #sbolm. You can then create a ViewModel per MVC page view that receives a model with the specific properties it needs. This will take more performance (insignificant) and code, but it keeps your service layer clean, and keeps your views "dumb" in that they are only given what they need and have no direct relation to the service layer.
I.e. (example class from #sbolm)
class Order {
public int Id {get;set;}
public string Name {get;set;}
public string Description {get;set;}
public decimal? Amount {get;set;}
public List<Item> Items {get;set;}
}
// MVC View only needs to know the name and description, manually "map" the POCO properties into this view model and send it to the view
class OrderViewModel {
public string Name {get;set;}
public string Description {get;set;}
}

I would suggest that instead of modifying the models or creating wrapper models, you have to name the service methods such that they are self-explanatory and reveals the consumer what they returns.
The problem with the nullable approach is it makes the user to feel that the property is not required or mandatory and they try inserting instances of those types without setting those properties. Is it won't be bad having nullables every-where?
It won't be a good approach to change the domain models since all you want is just to populate some of the properties instead of that you create service with names and descriptions that are self-explanatory.
Take the Order class itself as the example, say one service method returns the Order with all the items and the other one returns only the details of the Order but not the items. Then obviously you may have to create two service methods GetOrderItems and GetOrderDetail, this sounds so simple, yes it is! but notice the service method names itself tells the client what it is going to return. In the GetOrderDetail you can return an empty items or null (but here I suggest a null) that doesn't matter much.
So for new cases you don't need to frequently change the models but all you got to do is add or remove the service methods and that's fine. Since you are creating a service you can create a strong documentation that says what method does what.

I would not performance optimize this to much unless you realy get performance problems.
I would only distinguish between returning a flat object and an object with a more complete object graph.
I would have methods returning flat objects called something like GetOrder, GetProduct.
If more complete object graphs are requested they would be called : GetOrderWithDetails.
Do you use the POCO classes for the typed views? If yes: try to make new classes that serve as dedicated ViewModels. These ViewModels would contain POCO classes. This will help you keeping the POCO classes clean.

To expand on the nullable idea, you could use the fluentvalidation library to still have validation on the types dependent on whether they are null or not. This would allow you to have a field be required as long as it was not null or any other validation scheme you can think of. Example from my own code as I had a similar requirement:
Imports FluentValidation
Public Class ParamViewModelValidator
Inherits AbstractValidator(Of ParamViewModel)
Public Sub New()
RuleFor(Function(x) x.TextBoxInput).NotEmpty.[When](Function(x) Not (IsNothing(x.TextBoxInput)))
RuleFor(Function(x) x.DropdownListInput).NotEmpty.[When](Function(x) Not (IsNothing(x.DropdownListInput)))
End Sub
End Class

Related

OData swallowing objects in navigation property

I have a problem with an OData controller that is a little unusual compared to the others I have. It is the first one working completely from memory - no database involved.
The returned entity is:
public class TrdRun {
[Key]
public Guid Identity { get; set; }
public TrdTrade [] Trades { get; set; }
TrdTrade is also an entity set (which if queries goes against a database). But in this particular case I want to return all trades associated as active from a run, and I an do so WITHOUT going to the database.
My problem? The following code:
[ODataRoute]
public IEnumerable<Reflexo.Api.TrdRun> Get(ODataQueryOptions options) {
var instances = Repository.TrdInstance.AsEnumerable();
var runs = new List<Reflexo.Api.TrdRun>();
foreach (var instance in instances) {
runs.Add(Get(instance.Identifier));
}
return runs;
}
correctly configures runs to have the trades initialized - but WebApi decides to swallow them.
What is a way to configure it to return the data "as given" without further filtering? I know about the AutoExpandAttribute (Which I would love to avoid - I do not want the API classes marked with OData attributes), but I have not enabled Query, so I would expect the return data to be returned as I set it up.
The value of the Trades property is not being serialized because the default behavior of ODataMediaTypeFormatter is to not follow navigation properties, regardless of what is in memory. You could override this behavior by using $expand in the query string of the request, or AutoExpandAttribute on the Trades property in the class definition, but both approaches require decorating your controller method with EnableQueryAttribute.
If you don't want to do any of that, you can still programmatically specify auto-expansion of Trades in your service configuration as follows:
// Let builder be an instance of ODataModelBuilder or a derived class.
builder.EntityType<TrdRun>().CollectionProperty(r => r.Trades).AutoExpand = true;
Minor issue: With the programmatic approach, if the client requests full metadata (e.g., odata.metadata=full in the Accept header), the OData serializer will not include full metadata in the auto-expanded objects.

What is the proper way to reference another model from within a view?

I have two models: Reptile and Species. A Reptile has a Species, stored as an ID in the database:
How should I set up the details controller action/view for Reptile so that it displays the Title property of the Species instead of the ID that the Reptile uses?
My initial thought was just to grab the data in the controller and pass it in the ViewBag, but this seems inappropriate, and overly complex when it's time to setup the list action.
What's the proper way to do this?
It seems like I need to make a view model, but what confuses me is how to properly design it so that there aren't too many database calls.
Here is my initial attempt at a ViewModel:
public class ReptileDetailsModel
{
[Required]
public String Species { get; set; }
//etc...
public ReptileDetailsModel(Reptile reptile)
{
this.Species = reptile.Species.Title;
// etc...
}
}
Another way to achieve the same thing in more generic way is to use AutoMapper
Few advantages I can think of:
Automatically map exact properties (you only need specify anything that is exception to the rule)
Centralized in one class / method, whatever
Ability to ignore, map to another classes properties, even custom logic
Non intrusive, it is up to you how / when you want to use it.
In your particular instance I would create a mapper something like
Mapper.CreateMap<Reptile, ReptileDetailsModel>()
.ForMember(dest => dest.Species,
options => options.MapFrom(source => source.Species.Title));
This mapper info need to be registered somewhere. In MVC projects I have been involved, I would register a mapper into global.asax.
Then in your controller, you would want to invoke the mapper to map your reptile instance to your model
ReptileDetailsModel model = Mapper.Map<ReptileDetailsModel>(reptile);
There are many ways to use the AutoMapper within MVC, but this is probably a start.
I didn't realize it at the time, but I was using:
public ActionResult Index()
{
using (var db = new ModelsContainer())
{
return View(db.Reptiles.ToList());
}
}
This was causing the database (and thus model property) to expire before the view was rendered, causing this error (adding for search engines):
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
Set the Species class as a model for your strongly typed Reptile View. Then display the Title property of it. Your action method should look like this:
public ActionResult Reptile(Reptile rep)
{
return View(db.Species.Where(x=>x.ID == rep.SpeciesID).Single());
}
this way you would only need to call database once in order to generate the view.

Benefits of not passing entities to view

I usually see people telling that you should not pass entities to your View. They say you should use a DTO/VO/ViewModel/AnyOtherThingYouWant instead, as using an entity would increase the coupling.
Ignoring the moments where I do need some extra logic (or I don't need all the properties), I fail to see any benefits in doing this. For example, consider the following class:
public class Contact {
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
I see lots of code that creates another class, like this:
public class ContactDTO {
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
use it in the View and then do this:
someMapper.Map(contactDto).To<Contact>();
I can't see how better this is than simply using the Contact class, as your View would be coupled to a class that is coupled to the entity's class. So, every change in one should be replicated into the other. From my point of view, the 'middle' object is there just to add complexity, but not real value.
I know that there's no 'one size fits all' solution (as sometimes, using the middle object would make sense), but do we really need adding code like this? What are the real benefits?
Think of it this way: a view is a projection of your domain. It's a specific representation of your business model. So you need to use a view model which will represent this projection. It could be a subset of the domain model but it could also be an aggregation of multiple domain models if the view requires it. The example you provided is just a specific case where there is a 1:1 mapping between the domain model and the view model because of the requirements of this specific view. But that's only one specific view. I suppose that your application has many views and different representations of your domain entities.
There are many view specific things that make your domain models unsuitable and thus the need of view models. For example validation. A given domain model property could be required in some view and not required on another view (think of Id property in Create/Update views). If you don't use a view model but have your Create controller action directly take the domain model you will have a problem if your domain model Id property is decorated with the Required attribute.
There are many other examples. If I had one advice to give you when developing an ASP.NET MVC application it would be this: always define specific view models for your views and never pass/take domain models to/from views and this stands true even in cases where you have a 1:1 mapping between your domain model and the view model.
The cited approach is a kind of purism. If you do not need to transform (reduce, merge, whatever) your domain objects and they are directly usable in your view as they are, use them - you can introduce DTO via refactoring later, when necessary.
So you have to take into consideration what Darin Dimitrov said but keep in mind that DTOs and similar are here to make your work easier. I recall one project I worked on - more than 90% of DTOs were ono-to-one copies of the domain objects - this is totally useless and only adds to the maintenance cost.

EF Code First: How do I make a virtual collection private while still having it correctly create my database model?

I am using Code First to automatically generate my database, and this works perfectly, generating an Orders table and an OrderLines table as expected when I add some test data.
I have the following Order class:
public class Order
{
public int OrderID { get; set; }
public void AddItem(string productCode, int quantity)
{
var existingLine = OrderLines.FirstOrDefault(x => x.ProductOption.ProductCode == item.ProductCode);
if (existingLine == null)
OrderLines.Add(new OrderLine { ProductOption = item, Quantity = quantity });
else
existingLine.Quantity += quantity;
}
public void RemoveItem(string productCode)
{
OrderLines.Remove(OrderLines.Where(x => x.ProductOption.ProductCode == productCode).FirstOrDefault());
}
public virtual ICollection<OrderLine> OrderLines { get; set; }
public Order()
{
OrderLines = new List<OrderLine>();
}
}
What I really want is to encapsulate the OrderLines collection, making it impossible for consumers of the class to directly add and remove items to/from it (using the Add / Remove methods of ICollection) and instead forcing them to use my custom AddItem and RemoveItem methods.
Normally I could just make the collection private, but I can't do that because it needs to be virtual for EF to correctly create the OrderLines table/foreign keys.
This answer seems to suggest that making the property internal would do the trick, but I tried, and in that case no OrderLines table is created.
Is there any way that this can be accomplished, or should I have designed this differently somehow? Any help much appreciated!
Update
After a bit more searching, I found this question which is rather more clearly stated than mine; however, it's still unanswered. The poster does link to this post which seems to suggest it can't really be done in the way I'm thinking of, but does anyone have any more up-to-date information?
I don't know if it's possible to do what you are asking or not, but I'm not sure it's the best design. The problem that I am seeing is you are firmly integrating your business logic into your business entities, and I think this will turn into confusion down the road.
Take the following scenario under consideration. Say you have a new requirement where you want users to be able to remove all items from an order. The only way to do it with your entity is to create a new RemoveAllItems() method to your Order class which does that. Now say you have a new requirement to Remove all items from an order that are in a specific category. That then means that you have to add yet another method.
This causes really bloated classes, and there is one major issue you will come up with. If you (or another developer) want to look at an entity and determine it's data structure, you can't at a glance because it's so intertwined with business logic.
What I would suggest is that you keep your entities as pure data structures, keeping all their relationships public. Then you need to create a service layer, which can consist of small or big classes (however you want to organize them) that actually perform the business functions. So for example, you can have a OrderItemService class, which has methods for adding, editing, and removing items from an order. All your business logic is performed in this class, and you just have to enforce that only service classes are allowed to interact with db entities.
Now, if you are looking for how a particular business process is performed, you know to look in the service layer classes, and if you want to look at how a data structure or entity is organized, you look at the entity. This keeps everything clean and very mantainable.
I'm far from an expert on code first and I haven't tried the following but is it possible to use the ReadOnlyCollectionBase and create a read only list similar to this MSDN article?
Well what you can do is set your collection as private and make the relationship using fluent API in the OnModelCreating, as shown below, I don't know if this will work, just make a try:
public class YourContext : DbContext
{
public DbSet<Order> Orders { get; set; }
public DbSet<OrderLine> OrderLines { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>()
.HasMany(o => o.OrderLines)
.WithRequired(l => l.OrderId)
.HasForeignKey(l => l.OrderId);
}
}
This will make your OrderLines as readonly:
public class YourContext : DbContext
{
public DbSet<Order> Orders { get; set; }
public DbSet<OrderLine> OrderLines
{
get { return set<OrderLine>(); }
}
}
I hope this can help you, please take a look a this blog post: EF Feature CTP5: Fluent API Samples

My custom ASP.NET MVC entity binding: is it a good solution?

Suppose I want to allow to select our entity (from a dropdown, etc) on a page, let's say Product. As a result I may receive this:
public ActionResult SelectedAction(Guid productId)
{
}
But, I want to use model binders power, so instead I write model binder to get my product from repository and instead use
public ActionResult SelectedAction(Product product)
{
if (ModelState.IsValid) {} else {}
}
My model binder will set model state to false if product is invalid.
Now, there're problems with this approach:
It's not always easy to use strongly-typed methods like Html.ActionLink(c => c.SelectedAction(id)) since we need to pass Product, not id.
It's not good to use entities as controller parameters, anyway.
If model state is invalid, and I want to redirect back and show error, I can't preserve selected product! Because bound product is not set and my id is not there. I'd like to do RedirectToAction(c => c.Redisplay(product)) but of course this is not possible.
Now, seems like I'm back to use "Guid productId" as parameter... However, there's one solution that I'd like to present and discuss.
public class EntityViewModel<T> where T : BaseEntity
{
public EntityViewModel(Guid id)
{
this.Id = id;
}
public static implicit operator EntityViewModel<T>(T entity)
{
return new EntityViewModel<T>(entity.Id);
}
public override string ToString()
{
return Id.ToString();
}
public Guid Id { get; set; }
public T Instance { get; set; }
}
Now, if I use
public ActionResult SelectedAction(EntityViewModel<Product> product)
{
if (ModelState.IsValid) {} else {}
}
all the problems are solved:
I can pass EntityViewModel with only Id set if I have only Id.
I don't use entity as parameter. Moreover, I
can use EntityViewModel as property inside another ViewModel.
I can pass EntityViewModel back to RedirectToController and it will keep its Id value, which will be
redisplayed to user along with the validation messages (thanks to MVCContrib and ModelStateToTempData / PassParametersDuringRedirect).
The model binder will get Instance from the repository and will set model state errors like "Not found in database" and so on. And I can use things like ActionLink(c => c.Action(Model.MyProductViewModelProperty)).
The question is, are there any drawbacks here? I can't see anything bad but I'm still new to MVC and may miss some important things. Maybe there're better and approved ways? Maybe this is why everybody uses entity IDs as input parameters and properties?
Overall that looks like a good appoach to me...
As an alternative, you could use POCO for your viewmodel then I think all 3 problems would be solved automatically. Have you seen the Automapper project that allows an Entity to DTO approach? This would give you more flexibility by separating you ViewModel from your EntityModel, but really depends on the complexity of you application you are building.
MVC's ViewDataExtensions might also be useful instead of creating custom containers to hold various viewmodel objects as you mention in number 2.
MVCContrib's ModelStateToTempData should work for any serializable object (must be serializable for any out of process sessionstate providers eg. SQL, Velocity etc.), so you could use that even without wrapping your entity classes couldn't you?

Resources