I have a WCF server application using Entity Framework 5.0 and POCO entities. The server serializes POCOs directly to the client application over WCF (I managed to do this by following instructions in the following blog post: http://www.sanderstechnology.com/?p=10142). This has been working pretty well until I encountered a new problem today.
I have a simple situation in my data model shown in the following image: http://roponenp.kapsi.fi/images/datamodel.png
In my server I have a method that can be used for getting blocks:
[OperationContract]
[ApplyDataContractResolver]
[CyclicReferencesAware(true)]
List<Block> GetBlocks();
I need to include projects linked to the blocks to my response, so I do the following:
public List<Block> GetBlocks()
{
using (ModelContainer db = new ModelContainer())
{
db.Configuration.ProxyCreationEnabled = false;
db.Configuration.LazyLoadingEnabled = false;
return db.Block.Include(it => it.Project).ToList();
}
}
In my database I have instances of types ProjectA and ProjectB (that are inherited from Project). So the LINQ query above includes actually types of ProjectA and ProjectB to my response. Those types get serialized and are sent to the client. When this happens, I get the following error in the client side (there comes no errors in the server application):
The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.
The problem seems to be that in my data contract type Block is linked to type Project. However, my response returns data containing types ProjectA and ProjectB linked to Blocks.
I have no idea how I can solve this problem. I think it can be solved by implementing a custom DataContractResolver, but I haven't found any working examples how this could be done.
Any ideas?
You will need a KnownType Attribute if your object contains other types than obvious (for example interface implementations or derived classes).
Check the example in the MSDN, it's pretty good.
[ServiceContract]
[KnownType(typeof(ProjectA))]
[KnownType(typeof(ProjectB))]
class SomeService
{
[OperationContract]
[ApplyDataContractResolver]
[CyclicReferencesAware(true)]
List<Block> GetBlocks();
Related
The issue I'm having is quite an unusual one. I am writing a WCF service that can perform a variety of functions on a set of collections in MongoDB.
2 of the collections are made from classes I have created locally within the WCF service, and all operations when called externally by the client complete with no dramas.
The 3rd collection is created from a class that is defined externally and I cannot access or change this code.
One of my method is to Find all documents within this collection within a defined scope and take the odd bit of information for the response to the caller. This works fine on the driver I built into my WCF service but when a client calls the service externally, (I found this out after flooding the service with trace) I receive the following error:
Could not load file or assembly 'MongoDB.Bson...' or one of its dependencies
The strange thing is, when other methods perform updates on this collection, again there are no issues and the update completes successfully.
I am drawn to think that the caller to the WCF service is missing something. It's the only explanation as to why a local driver works but calling the method externally coughs and dies.
EDIT:
So this is the code that sets up my Mongo Collections:
client = new MongoClient(connectionString);
server = client.GetServer();
database = server.GetDatabase(b.DatabaseName);
c1 = database.GetCollection<MyType1>("collection1");
c2 = database.GetCollection<MyType2>("collection2");
c3 = database.GetCollection<ExternalType>("collection3");
To return a list of records within a certain scope from a collection, I use the following:
var scopeQuery = Query.EQ("Scope", scopeValue);
var results = c1.Find(scopeQuery).ToList();
As I said, c1 and c2 are collections created from types that are local to the WCF service. If I perform a find on these then I get my documents back, no dramas.
If I perform a Find(query) on c3, the collection populated documents created by the external type (it's a class from a 3rd party DLL), then I get the recorded error, but only when I call the method from a client. It works fine when called from a local driver (my WCF service test application).
Note also that the following works fine, both in the driver and when called from the client:
var scopeQuery = Query.EQ("Scope", scopeValue);
var update = Update.Set("SomeField", someValue);
c3.Update(scopeQuery, update);
Any help would be welcome at this point!
Cheers!
I have a WCF service project that is faulting when I am trying to eager load entities. (.Include).
My setup is like this:
WCF Service Library Project
Class Library Project -- Edmx is housed there
Class Library Project -- View Models housed there
WPF Project
I have spent some time trying to fix this serialization issue when I am eager loading entities.
Here is where I am now. The below works:
[OperationContract]
[FaultContract(typeof(HandleException))]
[ApplyProxyDataContractResolver]
List<Item> GetItems();
using (var dbContext = new MyEntities())
{
dbContext.Configuration.LazyLoadingEnabled = false;
return dbContext.Items.ToList();
}
And displays this:
But this faults and gives the generic error message
Failed to invoke the service. Possible causes: The service is offline or inaccessible; the client-side configuration does not match the proxy; the existing proxy is invalid. Refer to the stack trace for more detail. You can try to recover by starting a new proxy, restoring to default configuration, or refreshing the service.
This is what is throwing the exception
return dbContext.Items.Include(x => x.Category).ToList();
I have tried changing the return type to Item and then something like this
return dbContext.Items.Include(x => x.Category).FirstOrDefault(t => t.Category.CategoryId == t.CategoryId);
And I have added [CyclicReferencesAware(true)] but the test client is still bombing out.
Categories are a self referencing hierarchy -- I think that is why it can't handle it.
How can I resolve this?
Thanks.
WcfTestClient.exe can't handle cyclic references - have you tried testing with your own custom code?
it's a kind of client-server architecture problem.
I have 2 projects in my solution: one project for the client side working with Entity Framework and SQL Server Compact database and another one for the server side also working with Entity Framework but with a real SQL Server database. Both databases have exactly the same database schema, so although they are using different .edmx files, the generated entities looks the same and only differ in namespaces. By the way I'm using the ADO.NET DbContext Generator to generate persistence ignorant entity classes. So far so good. Now I wrote a (quite large) class with all the server database access methods inside, e.g.:
public User CreateUser(string userId, string username, bool isGlobalAdmin)
{
using (var context = new ServerEntities())
{
try
{
var user = new User
{
UserID = userId,
Username = username,
IsGlobalAdmin = isGlobalAdmin
};
context.User.Add(user);
context.SaveChanges();
return user;
}
catch (Exception ex)
{
HandleEfException(ex);
}
}
return null;
}
The problem is that I need the same class with the same methods on the client side. So I would copy this class to the client project, rename ServerEntities into ClientEntities and change the namespace for using client entities. This is quite ugly, because I need to maintain both classes, if something changes. Is there a way to abstract the whole thing and use the same class (which is located in a separate prject the other two projects refer to) on both sides (client and server)?
I would really appreciate your help.
Best,
Antony
If the databases are guaranteed to be identical, why do you need both sets of entities? Just use one set so they are interoperable.
You can do the following:
#if SERVER
using (var context = new ServerEntities())
#elif CLIENT
using (var context = new ClientEntities())
#endif
Then, in the project properties for both projects, under Build and then the Conditional Compliation Symbols box, you can add the token for each. So, in the server project, add SERVERand in the client, add CLIENT. If there are already tokens there, separate with semicolon (;).
Whichever project you put the class in, add it as a link to the second project. For instance, if the class file lives in the server project, in the client project, go to Add -> Existing item. Select the file, but then click the arrow by Open and click "Add as Link". This will ensure there is only one copy linked to both projects.
When each is compiled, the compiler will look at the tokens, evaluate them, and it will use the ClientEntities line in the Client project and the ServerEntities in the Server project.
You can do the same preprocessor directives for namespaces if needed. Here is an MSDN article explaining the directives.
I'm developing a Remoting classes library so that I can keep database interaction and business object on the server and not on clients.
I'd like to be able to return my own objects to the clients so that they can interact with them through the server itself.
For example (semi-pseudocode):
Server
class Database { ... }
class Utility
{
public User getUser(username)
{
return new User(username);
}
}
class User
{
public string[] getPerms()
{
return Database.query("select * from permission where user = " + this.username);
}
}
Client
Utility utility = (Utility)getRemotingClass("Utility");
User user = Utility.getUser("admin");
string[] perms = user.getPerms();
How can I organize my classes/namespaces? I'm particularly wondering about class references and scalability of my system.
Any kind of criticism/suggestion is really appreciated.
I don't mean to beat a drum, but you might want to look into WCF. Remoting is very chatty and the real support for maintaining clean interfaces by .Net is being done through WCF and message passing, as opposed to full object state management through remoting.
What it sounds like you are doing is developing a middle tier for management of the database connections. Just make sure you don't end up redeveloping the interface to SQL server.
I tend to put all the 'shared' (Data Transfer Object) classes in a separate DLL which both the server and the client reference (you could put them in the same DLL as the server classes if you're going to distribute it with the client code anyway).
By putting them in a separate assembly, you reinforce the de-coupling of the DTOs and the underlying technology used to remotely transfer them.
This means that if you end up rewriting the remote call technology, you won't have to touch the DTOs and can just re-use the assembly.
Don't forget to mark the DTOs as with the [Serailizable] attribute so they can be transported between the client and the server.
Herbie
I'm connecting to a web service hosted by a third-party provider. I've added a service reference in my project to the web service, VS has generated all the references and classes needed.
I'm connecting with this piece of code (client name and methods anonymized):
using (var client = new Client())
{
try
{
client.Open();
var response = client.Method(...);
return response.Status;
}
catch (SoapException ex)
{
throw CreateServiceException(ex);
}
finally
{
client.Close();
}
}
When reaching the client.Open(), I get an exception with this message:
The top XML element '_return' from
namespace '' references distinct types
System.Boolean and
Service.Status.
Use XML attributes to specify another
XML name or namespace for the element
or types.
In reference.cs, I can see that the "_return" variable is decorated with
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="", Order=0)]
Is there a problem with the wsdl, the generated service reference or in my code?
Update: Generating the service as an old school Web Service solves the problem. I've marked Sixto's answer as accepted for now, but I'm still curious what could've caused the problem and if any parameters to the service generator could solve the original problem.
If you were able to create a service reference then the WSDL is valid. The exception message is saying you have namespace/type ambiguity problem with _return. The generated code is probably using it in some context as a boolean and in another context as a Service.Status type.
I don’t call the ClientBase.Open method before invoking a service method because I’ve never seen the need for it. I do always call the Close & Abort methods as appropriate. The Open method basically just changes the state of the client to no longer be configurable. I’m not sure how that would trigger code in the generated class since it is an inherited method. I’d try just removing that line and see if you get the same exception. Otherwise, if you haven’t already done so, search the generated code for all the places _return is used and see if you can manually sort-out the appropriate type. You may need different names for each context.
Another way to troubleshoot the WSDL is to create a Web Reference (assuming it’s an HTTP based service) and see if the generate code works as expected. If it does work, go with the ASMX client unless you have a need for WCF proxy capabilities.