EF4 Self-Tracking entities and WCF serialization creates stack overflow - wcf

I try to get above configuration working, but with no luck.
Step 1)
I started a new solution with a WCF Service Application project.
Step 2)
In this project, I added an edmx file and create a very simple model:
Entity Parent with Id and DisplayName
Entity Child with Id and ChildDisplayName
Association from Parent to Child, 1-to-m, resulting in NavigationProperties on both entities.
I generatedthe database without any problems. After generation, I inserted one Parent object with two related Child objects manually to the database.
Step 3)
I added the code generation, using the ADO.NET Self-Tracking Entity Generator.
I know that this should be done in diffrent assemblies, but to make it straight and easy, I put it all to the same project (the WCF project)
Step 4)
I just changed the IService Interface to create a simple get
[OperationContract]
Parent GetRootData(Int32 Id);
In the corresponding implementation, I take an Page object from the context and return it:
using (PpjSteContainer _context = new PpjSteContainer() )
{
return _context.ParentSet.Include("Child").Single(x => x.Id == Id);
}
Problem:
If I now run this project (the Service1.svc is start page), VS2010 automatically generates the test client to invoke the service. But once I invoke the service, I get an StackOverflowException! Debugging on the server side looks ok until it returns the object graph.
If I remove the Include("Child") everything is ok, but of course the Child objects are missing now.
I have no idea what I'm missing. I read a lot of howto's and guides, but all do it the way I did it (at least that's what I think)...
I tried the School example here, but this does not work for me as it seems the database generation and the coding in the example does not match.
So, I would much appreciate if someone could guide me how to make this work.
P.S.
Yes, all Entity-Classes are marked "[DataContract(IsReference = true)]"
Lazy-Loading is set to "false" in the edmx file
Edit:
I changed the WCF to be hosted in a console app and no longer in IIS. Of course then I had to write my own little test client.
Funny enough, now everything's working.
I of course have no idea why, but at least for my testing this is a solution...

Have a look here. Basically you have to make the serializer aware of cycles in the navigation properties.

Related

Steps to use Entity Framework in WCF

I have a question using Entity Framework in WCF. I am using .NET 4.5 with EF DbContext.
Here are the things I know to do to use EF in WCF. May be they are insufficient or some are not required.
Create EF ADO.NET Model.
Seperate the POCO classes to a seperate project (ProjectName: Entities) by using DbContext template generator.
Point the TT template of the POCO project to the edmx file in the data project (ProjectName: Data). "..\Data\MyEdmx.edmx"
Add [DataContract(IsReference(True))] and [DataMemeber] attributes in the .TT file of the POCO project so that the classes and properties will have the serialization attributes. Add Runtime.Serialization reference to the project and add the namespace to .TT file. This enables not to lose your attribute declaration while recreating the classes on a save of the .TT file or adding new entities.
Add ProjectName: Entities reference to Data project.
Turn off ProxyCreation and LazyLoading in the Context.tt file in the data project.
Add (ProjectName: Entities) and (ProjectName: Data) to your wcf service project.
Copy the EntityFramework connection string to your WCF project.
All your select methods in the service, must use .Include if you want the navigation objects to be populated. This gives better control when you want to load or or when you want limit data to show. Also, you don't get the child/related automatically due to lazyloading turned off.
Insert or Update or Delete, the service has to create the context and manually set the object state to be modified or added? Otherwise the changes will not be saved. Use the DbContext.Attach to attach and set the state of the entity appropriately Added,Modified, etc.
The problem I had was I could not find a good example of the steps to perform to use EF with WCF. I was able to see only bits and pieces. May be I am a late entrant to the WCF EF world hence could not find.
Not sure if I can use proxies WCF. I haven't understood completely the advantage of proxies yet.
I also read recommendations to use DTO as a layer between EF and the service. This requires a mapper to be in place. I don't know if I need it right away. But the idea is clear that it helps hide any unnecessary database columns showing in the business object. For example, audit columns such as created by, updated by etc we dont to show in the client.
I did not choose to use DataServices as I lose other binding options that I get from WCF. I don't know if it is a good thing to lose the simplicity of DataServices thinking about the future requirements of clients that require/support other binding mechanisms.
Any recommendations is appreciated.
Additional Update
I did find this in MSDN http://msdn.microsoft.com/en-us/library/ee705457(v=vs.100).aspx. Some of the links were pointing to pre-release documentation. But this gives some more ideas for me in using EF and WCF.
This articles shows how to use proxies with WCF, change tracking of POCO. This is a good start for me. If any one has more advise please provide your thoughts.
Update 2
*Another Excellent Link for N-Tier*
http://msdn.microsoft.com/en-us/magazine/dd882522.aspx
I am glad that the time I am spending is really educating me!
I progressed on using EF with WCF after lot of reading here and in other forums.
I followed the steps ahead. I was able to see the advantage of using DTO. This really allows you to hide fields that you don't need to expose to the client or other services. But I am holding back on introducing DTO due to time constraints.
I used context.Attach, context.Add and context.Entry.
I also did a small prototype to use WCF Data Service. That was very fast paced development. I am holding back on using WCF data services for now due to time constraint in learning its features.

Share POCO types between WCF Data Service and Client Generated by Add Service Reference

I have a WCF Data Service layer that is exposing POCO entities generated by the POCO T4 template. These POCO entities are created in their own project (i.e. Company.ProjectName.Entities) because I'd like to share them wherever possible.
I have a set of interfaces in another project (Company.ProjectName.Clients) that reference these POCO types by adding an assembly reference to the Company.ProjectName.Entities.dll. One of the implementation of these interfaces is a .NET client that I want to consumes the service using the WCF Data Service Client Library.
I've used the Add Service Reference to add service reference. This generated the DataServiceContext client class and the POCO entities that are used by the service. However, these POCO types gemerated by the Add Service Reference utility now have a different namespace (i.e. Company.ProjectName.Clients.Implementation.WcfDsReference).
What that means is that the POCO types defined in the interfaces cannot be used by the types generated by the utility without have to cast or map.
i.e. Suppose I have:
1. POCO Entity: Company.ProjectName.Entities.Account
2. Interface: interface IRepository<Company.ProjectName.Entities.Account>{....}
3. Implementation: ServiceClientRepository : IRepository<Company.ProjectName.Entities.Account>
4. WcfDsReference: Company.ProjectName.Clients.Implementation.WcfDsReference
& Company.ProjectName.Clients.Implementation.WcfDsReference.Account
Let's say I want to create a DataServiceQuery query on the Account, I won't be able to do this:
var client = new WcfDsReference(baseUrl);
var accounts = client.CreateQuery<Company.ProjectName.Entities.Account>(...)
OR: client.AddToAccounts(Company.ProjectName.Entities.Account)
, because the CreateQuery<T>() expects T to be of type & Company.ProjectName.Clients.Implementation.WcfDsReference.Account
What I currently have to do is to pass the correct entity to the CreateQuery method and have to map the results back to the type the interface understands. (Possible with a mapper but doesn't seems like a good solution.)
So the question is, is there a way to get the Add Service Reference utility to generate methods that use the POCO types that are in the Company.ProjectName.Entities namespace?
One solution I am thinking of is to not use the utility to generate the DataServiceContext and other types, but to create my own.
The other solution is to update the IRepository<T> interface to use the POCO types generated by the utility. But this sounds a little bit hacky.
Is there any better solution that anyone has come up with or if there's any suggestion?
Ok, a few hours after starting the bounty I found out why it wasn't working as expected on my end.
It turns out that the sharing process is quite easy. All that needs to be done is mark the model classes with the [DataServiceKey] attribute. This article explains the process quite well, in the 'Exposing another Data Model' section
With that in mind, what I was trying to do is the following:
Placing the model on a separate class library project C, sharing it with both webapplication projects A and B
Create the data service on project A
Add the service reference on project B
Delete the generated model proxies out of the service reference, and update it to use my model classes in project C
Add the DataServiceKey attribute to the models, specifying the correct keys
When I tried this it did not work, giving me the following error:
There is a type mismatch between the client and the service. Type
{MyType} is not an entity type, but the type in the
response payload represents an entity type. Please ensure that types
defined on the client match the data model of the service, or update
the service reference on the client.
This problem was caused by a version mismatch between project C (which was using the stock implementations on the System.Data.OData assemblies) and the client project B that was calling the service (using the Microsoft.Data.OData assemblies in the packages). By matching the version on both ends, it worked the first time.
After all this, one problem remained though: The service reference procedure is still not detecting the models to be shared, meaning proxies are being created as usual. This led me to opt out of the automatic service integration mechanic, instead forcing me to go forward with a simple class of my own to serve as the client to the Wcf Data service. Basically, it's a heavily trimmed version of the normally autogenerated class:
using System;
using System.Data.Services.Client;
using System.Data.Services.Common;
using Model;
public class DataServiceClient : DataServiceContext
{
private readonly Lazy<DataServiceQuery<Unit>> m_units;
public DataServiceClient(Uri _uri)
: base(_uri, DataServiceProtocolVersion.V3)
{
m_units = new Lazy<DataServiceQuery<Unit>>(() => CreateQuery<Unit>("Units"));
}
public DataServiceQuery<Unit> Units
{
get { return m_units.Value; }
}
}
This is simple enough because I'm only using the service in readonly mode. I would still like to use the service reference feature though, potentially avoiding future maintenance problems, as evidenced by the hardcoded EntitySet name in this simple case. At the moment, I'm using this implementation and have deleted the service reference altogether.
I would really like to see this fully integrated with the service reference approach if anyone can share a workaround to it, but this custom method is acceptable for our current needs.

MVC SPA w/o EF: You must write an attribute 'type'='object' after writing the attribute with local name '__type'

So I have a very normalized model, and I'm trying to create a single page application in MVC4 which wants to use an entity framework object. My problem is I can't manage to create an entity in EF with the kind of complex mapping that I need (I have checked multiple guides, but I can't seem to make one entity from multiple tables that contain different primary keys... I found a solution using updateable views, but that's really just pushing the abstraction down to the db layer).
So I thought I could create a POCO object using an EF query to create the object, then on insert/update/delete I could just take the POCO data and update the underlying 3 tables.
Well I hit a roadblock just trying to tweak an existing working controller to try and learn what's going on.
Let's imagine I have a working SPA controller that looks like this:
public partial class FooController : DbDataController<aspnetEntities>
{
public IQueryable<Foos> GetFoos() { ... }
}
I just change it a bit to return my new POCO data object Bar, which let's imagine has the exact same fields as Foo for the moment:
public partial class FooController : DbDataController<aspnetEntities>
{
public IQueryable<Bars> GetBars() { ... }
}
Over in FooViewModel.js I update the operation name to GetBars, and the type from
var entityType = "Foo:#Models";
to
var entityType = "Bar:#Models";
I hit my operation directly and I get:
OLD
<ArrayOfFoo><Foo><Property>true</Property></Foo></ArrayOfFoo>
NEW
<ArrayOfBar><Bar><Property>true</Property></Bar></ArrayOfBar>
So the controller looks like it's giving me what I expect, but when I try to put the whole thing together the SPA flashes up:
You must write an attribute 'type'='object' after writing the attribute with local name '__type'.
I'm guessing somehow I need to get type data into KO? I'm not sure where that might be however, I've been crawling through the JS for hours, but I'm not even clear on where it's failing. Any input would be greatly appreciated.
The problem you are experiencing is connected to the fact you are using POCO instead of the standard EF. It should be related to the webapi serializer that somehow doesn't recognize the class as serializable. Anyway it is a bug that will be removed in the RC. Give a look to this thread for workarounds:
http://forums.asp.net/t/1773173.aspx/1?You+must+write+an+attribute+type+object+after+writing+the+attribute+with+local+name+__type+

Simplest way to use NHibernate for the official "ASP.Net MVC 3 Getting Started"-Tutorial

Clarified Updated Question - Start
In the official MVC 3 Getting Started-tutorial it seems to me that all we have to do to get ORM working are two steps.
First adding the simple MovieDBContext-code as described at the end of part 4 ..
public class MovieDBContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
}
.. and second in the beginning of part 5, with a simple right-click on the Controllers folder we can auto-generate a MoviesController that implements CRUD()-functionality using Entity Framework by simply telling which Model to use.
Now when using the web-application we can already write and read from the database.
What would be the simplest (or a simple) way to get this done for our Movie-Model with NHibernate instead of using Entity Framework?
Clarified Updated Question - End
Original question (only for additional background-info):
I'm trying to create an ASP.Net MVC 3 application that uses NHibernate and Postgres.
Background Info
Development is done on Windows with Visual Web Developer Express, the production environment will be/should be Linux+Mono.
Steps that have worked so far:
An ASP.Net Dynamic Data Entities Web Application using Npgsql and Postgres as the DB.
Successfully run on Windows development machine.
(Following this tutorial)
An ASP.Net MVC 3 application without using a database/model yet:
Succesfully run on Windows development machine and deployed to Linux production environment using Mono and Nginx. (Only as a proof of concept for myself not as a web app used by the public.)
An ASP.Net MVC 3 application with a model using SQL Server Express as the DB.
Successfully run on my Windows development machine.
(Following the MVC 3 Getting Started-tutorial)
Question
So far I managed to get Postgres to work with a "Dynamic Data Entities Web Application" but with an MVC 3 Web app I'm stuck on where/how to start. For the last mentioned MVC-3-Movie-Webapp I want to switch the DB from SQL Server Express to Postgres using NHibernate and Npgsql (NHibernate since Mono doesn't support Entity Framework).
When you look at the end of part 4 there's the simple MovieDBContext-code
public class MovieDBContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
}
and in the beginning of part 5, we autogenerate CRUD-stuff using Entity Framework by simply telling which Model to use.
(MoviesController.cs, Create.cshtml, Delete.cshtml, Details.cshtml, Edit.cshtml, and Index.cshtml)
So I have that working with Entity Framework and SQL Server Express, but how would I achieve the same result by using NHibernate? (doesn't have to be with postgres immediately, sticking with SQL-Server as a first step would be fine) (Hopefully with similar simplicity, but getting the result itself would be great)
I found a lot of old stuff and how I would manually map things, but what would be a good-up to date standard way of achieving this with NHibernate for MVC 3?
(The closest thing I found was the source code mentioned in this thread, but it's 64 MB unzipped I got several "Projects not loaded successfully"-errors and the author said he uses MVC 2 so I think it's a little over my head for being a complete NHibernate noob.)
I think showing how this is done could be very useful for others as well, since the original tutorial is very easy to follow and is linked as the official starting point for MVC 3 app-development on http://www.asp.net/mvc ("Your First ASP.NET MVC App").
So I think this would be a great up to date example about how to use NHibernate with MVC 3.
Actually, those automated things haven't helpful enough in real world applications. We have to separate concerns and by using DataContext in UI Layer is not a good practice because that dependency will cause problems like lack of test-ability, violation of best practices. I think you need to have following things of your project
Separation of Concern (Layered Architecture - UI Layer, Servie Layer, Domain Layer, Infrastructure Layer)
Generic Repository and Unit of Work wrapping (Database functionalities, ORM - EF, NHibernate, etc
In your Service Layer process repositories and unit of work processings and expose Data Transfer objects or your domain objects (POCOs) to UI Layer
Use IOC to inject dependencies will help you to minimize dependencies
Create Unit test and Integration tests
Use Continuous Integration and Source control prefer (Distributed: Mercurial)
Useful References:
(Sharp Architecture) http://sharparchitecture.codeplex.com/
(IOC Container) http://www.castleproject.org/container/
(Generic repository) http://code.google.com/p/genericrepository/
NuGet is your friend. Here's a good example of using NuGet to automatically wire in your dependencies and configuration pretty much automatically.
Hope this helps.
Suggestion, don't get hung up on all the automatic stuff that the tutorials are showing you. Microsoft is just trying to show that you can easily get things started if you don't try to do anything unique.
Now for your situation. When you're making a controller, you're wanting to bind that controller with a type of model that you created somewhere. With nHibernate I'm thinking that you'll have manually created these POCO's and that you're using one of the many ways to map those POCO's through nHibernate to your database.
You won't be able to use the Entity Framework options because they're depending upon the features of the framework to provide information on the object, database, etc. Easiest things is to just make a controller that either gives you the options for CRUD or use an empty controller to build up your own ActionResults.
Hope this helps some and good luck with your project.

EF4 POCO WCF Serialization problems (no lazy loading, proxy/no proxy, circular references, etc)

OK, I want to make sure I cover my situation and everything I've tried thoroughly. I'm pretty sure what I need/want can be done, but I haven't quite found the perfect combination for success.
I'm utilizing Entity Framework 4 RTM and its POCO support. I'm looking to query for an entity (Config) that contains a many-to-many relationship with another entity (App). I turn off lazy loading and disable proxy creation for the context and explicitly load the navigation property (either through .Include() or .LoadProperty()). However, when the navigation property is loaded (that is, Apps is loaded for a given Config), the App objects that were loaded already contain references to the Configs that have been brought to memory. This creates a circular reference.
Now I know the DataContractSerializer that WCF uses can handle circular references, by setting the preserveObjectReferences parameter to true. I've tried this with a couple of different attribute implementations I've found online. It is needed to prevent the "the object graph contains circular references and cannot be serialized" error. However, it doesn't prevent the serialization of the entire graph, back and forth between Config and App.
If I invoke it via WcfTestClient.exe, I get a stackoverflow (ha!) exception from the client and I'm hosed. I get different results from different invocation environments (C# unit test with a local reference to the web service appears to work ok though I still can drill back and forth between Configs and Apps endlessly, but calling it from a coldfusion environment only returns the first Config in the list and errors out on the others.) My main goal is to have a serialized representation of the graph I explicitly load from EF (ie: list of Configs, each with their Apps, but no App back to Config navigation.)
NOTE: I've also tried using the ProxyDataContractResolver technique and keeping the proxy creation enabled from my context. This blows up complaining about unknown types encountered. I read that the ProxyDataContractResolver didn't fully work in Beta2, but should work in RTM.
For some reference, here is roughly how I'm querying the data in the service:
var repo = BootStrapper.AppCtx["AppMeta.ConfigRepository"] as IRepository<Config>;
repo.DisableLazyLoading();
repo.DisableProxyCreation();
//var temp2 = repo.Include(cfg => cfg.Apps).Where(cfg => cfg.Environment.Equals(environment)).ToArray();
var temp2 = repo.FindAll(cfg => cfg.Environment.Equals(environment)).ToArray();
foreach (var cfg in temp2)
{
repo.LoadProperty(cfg, c => c.Apps);
}
return temp2;
I think the crux of my problem is when loading up navigation properties for POCO objects from Entity Framework 4, it prepopulates navigation properties for objects already in memory. This in turn hoses up the WCF serialization, despite every effort made to properly handle circular references.
I know it's a lot of information, but it's really standing in my way of going forward with EF4/POCO in our system. I've found several articles and blogs touching upon these subjects, but for the life of me, I cannot resolve this issue. Feel free to simply ask questions and help me brainstorm this situation.
PS: For the sake of being thorough, I am injecting the WCF services using the HEAD build of Spring.NET for the fix to Spring.ServiceModel.Activation.ServiceHostFactory. However I don't think this is the source of the problem.
EDIT: The ProxyDataContractResolver class works correctly if I don't have the circular references. (i.e.: I make the setter of App.Configs to be private, which prevents serialization of the property.) It blows up, it appears, when it hits Configs via the App object -- they don't seem to be recognized as the same type as the top level Configs.
EDIT2: It appears that either EF or WCF doesn't recognize that the entities are indeed equal. i.e.: 'Config' is the same as a particular 'Config.Apps[x].Configs[y]'. The entity keys are properly set in the CSDL for each model and I've overridden the Equals() function to compare entities based on their 'Id' property. This fits the symptoms as no circular reference error is thrown, yet it is indeed a circular reference (and blows up WcfTestClient.exe) AND the ProxyDataContractResolver blows up when it hits the 'Config.Apps[x].Configs[y]' level of Configs. (It doesn't know how to map a Config proxy. The ProxyDataContractResolver works otherwise. It's like it knows how to handle the initial round of entities, but the second level it considers as different entities.)
Wow, I can be wordy. Sorry folks!
You might want to check out my blog post on this specific scenario - please email me if it doesn't help fix your current predicament! I've included a sample solution as well.
Please drop me some feedback either way, I'd really like to hear from more people on this particular issue - especially with the implementation problems on the client end of things.
hrmm, I may not have fully understood the issue, but everytime I run into circular references with WCF the answer is to change [DataContract] on the offending classes to [DataContract(IsReference = true)].
This is a huge help compared to all the drek of messing with the contract resolvers that was needed pre WCF 3.5 SP1.
Hope this helps.
Faced the same issue today and used Value Injecter to solve it. It's as simple as:
var dynamicProxyMember = _repository.FindOne<Member>(m=>m.Id = 1);
var member = new Member().InjectFrom(dynamicProxyMember) as Member;
We couldnt afford disabling ProxyCreation
Try setting myContext.ContextOptions.ProxyCreationEnabled = false;
If the problem is solved (like mine) then you've not followed the steps mentioned in: http://msdn.microsoft.com/en-us/library/ee705457.aspx
This solved the problem for me.
You can use the ApplyDataContractResolverAttribute and a ProxyDataContractResolver along with the CyclicReferencesAwareAttribute. At first this produces error like this one - as if there is no DataContractResolver specified at all:
Type 'System.Data.Entity.DynamicProxies.Whatever_E6......A9' with data contract name 'Whatever_E6......A9: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.
It will work with one simple change.
In the ApplyCyclicDataContractSerializerOperationBehavior, the constructors for the DataContractSerializer must also pass in the DataContractResolver. This is left out of all the versions I have seen online.
Example:
public class ApplyCyclicDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
private readonly Int32 _maxItemsInObjectGraph;
private readonly bool _ignoreExtensionDataObject;
public ApplyCyclicDataContractSerializerOperationBehavior(OperationDescription operationDescription, Int32 maxItemsInObjectGraph, bool ignoreExtensionDataObject, bool preserveObjectReferences)
: base(operationDescription)
{
_maxItemsInObjectGraph = maxItemsInObjectGraph;
_ignoreExtensionDataObject = ignoreExtensionDataObject;
}
public override XmlObjectSerializer CreateSerializer(Type type, String name, String ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes,
_maxItemsInObjectGraph,
_ignoreExtensionDataObject,
true,
null /*dataContractSurrogate*/,
DataContractResolver); // <-----------------------------
}
public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes,
_maxItemsInObjectGraph,
_ignoreExtensionDataObject,
true,
null /*dataContractSurrogate*/,
DataContractResolver); // <-----------------------------
}
}