I have succesfully implemented a RESTful Web Service using the .NET 4.0 framework with MVC 4 and the ApiController class.
I have a method, let's say GetMovies ("/api/movies") that returns an IQueryable<Movie>. Serialization is done using DataContractSerializer, of course. The problem is in the name of the returned list, because it is ArrayOfMovie:
<ArrayOfMovie>
<Movie></Movie>
<Movie></Movie>
...
<Movie></Movie>
</ArrayOfMovie>
I cannot create a custom class, let's say Movies, and add a [CollectionDataContract(Name = "movies")] annotation (as suggested at https://stackoverflow.com/a/4593167/801065) because I cannot extend IQueryable without implementing all of its methods. And I most definitely need an IQueryable for OData/jQuery processing.
How can I solve this? Is there an annotation that can help me?
This is the solution I found.
You need to put a group class in the main class you want to serialize.
[DataContract(Name = "movies")]
public class group
{
[DataMember(Name="movies")]
public IQueryable<Movie> Movies;
}
Related
I am exploring the idea of implementing a web service api using WCF Data Services and EF4. Realizing that some operations require complex business logic, I decided to create a partial class the same name as the main EF data context partial class and implement additional methods there to handle the more complex business logic. When the EF context object is used directly, the additional method shows up (via intellisense) and works properly. When the EF classes are exposed through a WCF Data Service and a Service Reference is created and consumed in another project, the new method does not show up in intellisense or in the generated Service.cs file (of course, I updated the reference and even deleted it and re-added it). The native data methods (i.e. context.AddObject() and context.AddToPeople()) work properly, but the new method isn't even available.
My EF classes look something like this:
namespace PeopleModel
{
//EF generated class
public partial class PeopleEntities : ObjectContext
{
//Constructors here
//Partial Methods here
//etc....
}
//Entity classes here
//My added partial class
public partial class PeopleEntities
{
public void AddPerson(Person person)
{
base.AddObject("People", person);
}
}
}
There's nothing special about the .svc file. The Reference.cs file containing the auto generated proxy classes do not have the new "AddPerson()" method.
My questions are:
1. Any idea why the web service doesn't see the added partial class, but when directly using the EF objects the method is there and works properly?
2. Is using a partial class with additional methods a good solution to the problem of handling complex business rules with an EF generated model?
I like the idea of letting the oData framework provide a querying mechanism on the exposed data objects and the fact that you can have a restful web service with some of the benefits of SOAP.
Service operations are only recognized if they are present on the class which derives from DataService. The WCF Data Service will not look into the context class for these. Also note that methods are not exposed by default, you need to attribute them with either WebGet or WebInvoke and allow access to them in your InitializeService implementation.
http://msdn.microsoft.com/en-us/library/cc668788.aspx
I am new to entity framework and mvc.
I am trying to understand what a Controller should pass to the view.
Should it be the class from Models (MySolution.Models.Story) or the class from the entity framework (MySolution.Story).
The problem is that if I pick the one from entity framework, then the DataTypes and html-helpers are not working correctly. If I pick the class from models, then I can't convert from the entity class to the model class, for example:
TrendEntities TrendDB = new TrendEntities();
public ActionResult Details(int id) {
var Country = TrendDB.Countries.FirstOrDefault(c => c.CountryId ==id);
return View(Country);
}
Just use the adp.net entity framework POCO templates to generate. download the template. right click in the entity designer and select "add code generation item" and choose the poco template. Now your objects dont have all of the 'entity framework baggage' with them. Proxies are automatically created behind the scenes and you don't need to do any object mapping.
You can find this template by adding a new item to visual studio 2010, and searching the online templates from within the add dialog for POCO. The template name is:
ADO.NET C# POCO Entity Generator
You are looking for either AutoMapper or ValueInjecter. These two libraries are "Object to Object" mappers, which are designed for mapping values from one object to another object. I have only used AutoMapper before. It is great and pretty easy to pick up. I've heard good things about ValueInjecter as well.
After some investigation, I figured out that I had a design problem.
Long story short, REMEMBER that in MVC 3 we need a to define the following class in the model
public class StoryDBContext : DbContext
{
public DbSet<Story> Stories {get; set;}
}
And then in the controller THAT's the one to use when accessing the Entity Framework.
In the previous version we were not defining the above class and were using the TrendEntities class (that was created by the framework) to access the DB.
That's a bit confusing...
So, in my example, TrendDB should be of type StoryDBContext instead of TrendEntities and things are working as expected.
Use a ViewModel. This is a class that you declare having the properties you want to display on your View.
For example:
var country = TrendDB.Countries.FirstOrDefault(c => c.CountryId == id);
CountryDetails details = new CountryDetails();
details.FirstValueToShow = country.Name;
return View(details);
Remember to strongly type your Details view to the ViewModel.
How do bind my domain object Car to View?
MVC says "your class must have default constructor". But I don't want to change any business rules by creating a default constructor. The only solution I can see - is to use CarView in my View and then map it to Car.
P.S. NHibernate wants a default constructor too, but it can be protected. This I can do.
IMHO, its a good idea to seperate the objects that go to your view from you domain objects. This has a long list of advantages (which I am not going into now).
You can then use Automapper to map your view models to your domain objects
You could create the object yourself and call UpdateModel to do the binding instead:
public ActionResult MyAction()
{
var car = new MyCar(somethingToPassIntoTheConstructor);
UpdateModel(car);
// Do stuff with car.
}
EF + WCF Ria Service:
Suppose I have entity People, because it is a partial class, so I can extend it to add a method to it:
partial class People{
static string GetMyString(){
//......
return string;
}
}
then at client side, I want to method GetMyString available for entity People. what's the best way to implement this?
In your server side project, you should have (but is not necessary) a People.cs class that contains your metadata, such as attributes for validation.
Also in your server project, create a public partial class named People.shared.cs. In this class you can add your methods such as the GetMyString() method. The People.shared.cs class gets code-generated (copied) to the client project.
I'm trying to set up NHibernate in an ASP.NET MVC application using a DDD approach. However, I do get an error when trying to lazy load an objects related entity. Heres how I've structured my application:
Infrastructure layer:
Contains mapping files, repository implementations and a NHibernate bootstrapper to configure and build a session factory.
Heres a repository example:
public class CustomerRepository : ICustomerRepository
{
public Customer GetCustomerById(int customerId)
{
using (var session = NHibernateBootstrapper.OpenSession())
return session.Get<Customer>(customerId);
}
}
Domain layer:
Has simple POCO classes, repository and service interfaces
Application layer:
Contains Service implementations.
Heres a service example:
public class CustomerService : ICustomerService
{
private ICustomerRepository _repository;
public CustomerService(ICustomerRepository repository)
{
_repository = repository;
}
public Customer GetCustomerById(int customerId)
{
return _repository.GetCustomerById(customerId);
}
}
Presentation layer:
Contains the ASP.NET MVC application. And this is where I discovered my problem.
Using the MVC approach, I have a controller which, using the CustomerService service, gets a customer and displays the customer in a View (strongly typed). This customer has a related entity Contact, and when I try to access it in my View using Model.Contact, where Model is my Customer object, I get an LazyInitializationException.
I know why I get this. It's because the session used to retrieve the Customer in the CustomerRepository is dead by now. My problem is how I can fix this. I would like if I could avoid getting the related Contact entity for the Customer in my repository, because some views only need the Customer data, not the Contact data. If this is possible at all?
So to the question: is it possible to wait querying the database, until the presentation layer needs the related entity Contact?
I think that what I need is something like what this article describes. I just can't figure out how to implement it in infrastructure layer, or where should it be implemented?
Thanks in advance. Any help will be much appreciated!
As for session management it is common to use single session per request. You can see an example of implementation here. It is an open source project that were designed to setup new asp.net applications with the help of Nhibernate wery easy. source code can be founded here.
Hope it helps.
I also recommend Sharp Architecture.
Another approach, as well as suggestion, is to avoid passing entities to views. There're other problems with it except session management - business rules leaking into views, bloated/spagetti code in there, etc. Use ViewModel approach.
Another problem you'll get is storing your entities in Session. Once you try to get your Customer from Session["customer"] you'll get the same exception. There're several solutions to this, for example storing IDs, or adding repository methods to prevent lazy-loading of objects you're going to store in session - read NHibernate's SetFetchMode - which, of course, you can also use to pass entity to views. But as I said you better stick with ViewModel approach. Google for ViewModel, or refer to ASP.NET MVC In Action book, which uses samples of code from http://code.google.com/p/codecampserver/. Also read this, for example.
Are all your properties and methods in your Customer class marked virtual?
How are you opening and closing your session? I use an ActionFilterAttribute called TransactionPerRequest and decorate all my controllers with it.
Check out this for an implementation.