ASP.NET MVC4 Web API Controller serialization - entity-framework

I am trying to create a RESTful web service that returns a list of products using ASP.NET MVC4 Web API. Here is my controller class
public class ProductController : ApiController
{
public IEnumerable<Product> GetProducts()
{
WebCatalogContext dbcontext = DatabaseConfig.Instance.Context;
List<Product> plist = dbcontext.Products.ToList();
return plist;
}
}
When I run my service and call the following URL from my browser :/api/Product, I get System.Runtime.Serialization.SerializationException. I looked into my plist object and there is no problem with it.
Here is my data model:
[DataContract(Name = "p")]
[Serializable]
public class Product
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[DataMember(Name = "id")]
public int Id { get; set; }
[Required, MaxLength(50)]
[DataMember(Name = "ti")]
public string Title { get; set; }
[Required]
[DataMember(Name = "de")]
public string Description { get; set; }
[Required]
[DataMember(Name = "ph")]
public string PhotoURL { get; set; }
[DataMember(Name = "ca")]
public virtual ProductCategory Category { get; set; }
}
[DataContract(Name="pc")]
[Serializable]
public class ProductCategory
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[DataMember(Name="id")]
public int Id { get; set; }
[DataMember(Name="nm")]
public string Name { get; set; }
}
When I remove the reference to ProductCategory from my Product class, all things work just fine. But, when I include it I get the following exception.
Type 'System.Data.Entity.DynamicProxies.Product_664E9A0AA1F165A26C342B508BFFF1279FD3FE059285225BDA19F407A29A9CAD' with data contract name 'Product_664E9A0AA1F165A26C342B508BFFF1279FD3FE059285225BDA19F407A29A9CAD:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
Any idea about what I am missing?
Regards

Entity Framework has wrapped your POCO with an EF Proxy POCO so it can perform lazy loading - this uses the Virtual attribute to create a 'lazy-loadable' navigation property. I expect that is where the serialization error comes from.
You could make a new class and map the POCO to that - then pass the DTO style class from the controller. I've never returned an EF object directly from the API (I always map to some something else) so I don't know another option.
EF POCO to DTO (data transfer object) is relatively painless if you use a tool like http://valueinjecter.codeplex.com/ or http://automapper.org/

To support Lazy Loading for navigation properties which is declared as virtual, EF will generate the proxies for any models which have navigation properties which leads to this kind of exception.
For very simple application, you can use model from EF as DTOs (if having no navigation properties), but for complex application, you should do separate and differ between DTOs and domain models. It should not be mapping 1:1 between DTO and domain model.
Therefore, in your case, you create more DTO model for Web API layer, it will be fine.

Related

Entity Framework 6 load derived class of entity

In Entity Framework 6, given class A and derived class B: A, I would like to load entities A into instances of B without having to code for each property.
So given:
public class A
{
public Guid AId { get; set; }
public string Value { get; set; }
}
public class B: A
{
[NotMapped]
public string OtherValue { get; set; }
}
public MyDbContext: DbContext
{
public DbSet<A> As { get; set; }
}
I would like to:
using (MyDbContext db = new MyDbContext())
{
IEnumerable<B> Bs = db.As.LoadBsSomehow()
}
I'm guessing I could add DbSet<B> Bs { get; set; } and then in OnModelCreate I could override the table name to As perhaps. I'd like to avoid that if I can.
The purpose of doing this is that we need view models that need the underlying model plus some other properties and I don't want to mess up the models with all the different view model properties. This would simplify coding and maintenance for when the main model is changed -- the inheritance would automatically handle the changes in the derived class (view models).
I can then set the additional properties of the Bs in a Select or other method.
Also, I do NOT want to use reflection. I can code that up if I need it. I'd rather find out if EF 6 has the ability to do this natively.
UPDATE: I can do DbContext.Database.SqlQuery<T>. I would prefer to be able to use LINQ instead of writing SQL. I have no problem writing SQL, but LINQ is much more maintainable from a code perspective. Perhaps if I can use LINQ to create an IQueryable<B> and get the SQL for it?

asp.net mvc4 entity framework 4: Unable to create a Controller, and I've tried everything

I'm building a website using Visual Studio 2012 with MVC4 and Entity Framework 4.
I created all my model classes, with all their attributes (with some relationships between them). So far, my classes only have a bunch of attributes (no methods yet).
But whenever I try to create a controller for a class that has a collection in it, I get this error: Unable to retrieve metadata for 'model name'. Value cannot be null. Parameter name: key.
I've googled it and found different solutions, but none of them worked: I tried renaming all my primary key attributes to "Id" (they are also all annotated with [Key]), I also tried commenting out the constructor in the Data Context class, I checked my connection is named DefaultConnection...
This is one of the classes for which I'm being unable to create a controller:
public class JobOffer
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int JobOfferId { get; set; }
public Company Company { get; set; }
public OfferState State { get; set; }
public virtual ICollection<OfferApplicant> Applicants { get; set; }
public virtual ICollection<Requirement> Requirements { get; set; }
}
(I already tried without the [DatabaseGeneratedAttribute] annotation and it didn't help)
The OfferState class is an abstract class that has 2 subclasses: Open and Closed (they're there to implement a State pattern).
The OfferApplicant class maps 1 JobOffer with 1 Applicant, since that was a many-to-many relationships, so I created a new table.
The Requirement class is also an abstract class that has a few subclasses, like Age, Education, Area, etc., and also a CompositeRequirement, which has a public virtual ICollection Requirements { get; set; } collection (it's a Composite pattern).
The classes don't even have methods yet, all they have are their properties.
Any clues?
Thanks!!

Entity Framework code first: DbSets and navigation properties

A little new to EF, so please bear with me if the answer to this is obvious. I'm doing a tutorial that uses EF, and two DbSets are defined like this:
public DbSet<BrokerageAccount> BrokerageAccounts { get; set; }
public DbSet<Customer> Customers { get; set; }
The customer class looks like this-- it's a POCO (some code cut for brevity):
public class Customer
{
public Customer()
{
BrokerageAccounts = new HashSet<BrokerageAccount>();
}
// Primitive properties
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
// Navigation properties
public ICollection<BrokerageAccount> BrokerageAccounts { get; set; }
}
}
The BrokerageAccount class is a POCO as well, very similar in design to Customer.
So far so good. The code I have a question about is below. There is an association made in the main program between Customer and BrokerageAccount that I don't follow. The code reads like this:
public Customer GetCustomer(string custId)
{
using (var context = DataContext)
{
return context.Customers
.Include("BrokerageAccounts").SingleOrDefault(c => c.CustomerCode == custId);
}
}
I can't figure out how the association/join is made between Customer and BrokerageAccount. I don't see any config or other files in my VS 2010 project that tells what associates the two DbSets, what foreign key column to use, etc.
Perhaps I'm missing something obvious or a mapping file of some sort, but just because Customer has an ICollection of BrokerageAccount along with a comment above that says "Navigation Properties", doesn't make it so. In EF, how are those associations established?
The normal way of setting up the navigation properties is to use the ModelBuilder, This gives you a fluent api to set up the associations, take a look at this for some in depth stuff about how you go about this.
http://xhalent.wordpress.com/2011/01/21/configuring-entity-framework-4-codefirst/
Entity framework will guess at what you meant if you dont set up the nav properties manually, in the above case it will probably set up your nav properties as expected as you only have a single 1-* relationship between customer and BrokerageAccount which appears to be named sensibly.
There is also an attribute method that you can use to set up the navigation properties.

MVC 3.0 newbie - how do I set display name?

Consider this class used for DB mapping.
[Bind()]
public class ActiveType
{
[Key()]
public int ID { get; set; }
[Display(Name = "Navn")]
public string Name
{
get;
set;
}
public string Prefix { get; set; }
public string Suffix { get; set; }
}
As you can see, I tried to use the Display annotation to make MVC use that name when it auto-generates entity-framework CRUD pages. However, it ignores it. How do I change this? Is it possible through annotations?
If you are genarating your domain classes it will remove the attributes you have added.
It seems like you are using the domain object in entity framework layer for the model in MVC layer. This is not a good practice. You need to create separate view models (http://blogs.msdn.com/b/simonince/archive/2010/01/26/view-models-in-asp-net-mvc.aspx) for the MVC layer. Because you need to separate the presentation logic from the data layer.
You can use something like AutoMapper to map domain object to view model. http://sourceforge.net/projects/automapper-dn/
The example I provided actually worked, but not for auto-generated EF pages, where it would ignore it in some cases.

Entity Framework - DataAnnotations

Using MVC3 and Entity Framework.
Am trying to get validation flowing from data model
Question: On an entity framework save, how can I automatically put in the [MetadataType tag below for my buddy class?
[EdmEntityTypeAttribute(NamespaceName="ModelValidationTestModel", Name="Person")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
[MetadataType(typeof(Person_Validation))] // I want EF to put this line in automatically
public partial class Person : EntityObject
...
[Bind(Exclude="PersonID")]
public class Person_Validation
{
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public int Age { get; set; }
[Required]
public string Email { get; set; }
}
Using example from: http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx
I think the best option is not to mess with the class generated by EF. Instead define your own partial class:
[MetadataType(typeof(Person_Validation))]
public partial class Person
{
//rest of class may be empty
}
You can do this in the same file as the Person_Validation class if you like.
It's not automatic, but it is safe (your changes won't get lost). This approach will work with any code generation framework (that uses partial classes), not just EF.
Data Annotations/attributes are baked at compile time and you cannot add them dynamically. I would recommend you to avoid passing/getting your EF models to/from the views. You should be using view models which are classes specifically tailored to the needs of a given view. It is those view models that will handle the would handle view specific validations such required, format, ...). You could then use AutoMapper to have your controller map between your view models and the EF models.