When a drupal application is consuming a WCF service that we inherited, it sends an xml that should result in an entity framework parameter. After some schema changes, we updated the entity framework model (edmx file). The problem is that when the client calls the service (with the same code as before) the usageritem parameter is not properly deserialized.
The call send to the method is the following:
<UpdateUsager xmlns="http://tempuri.org/">
<usageritem xmlns:a="http://schemas.datacontract.org/2004/07/CNVGestion.Domain" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i1">
<EntityKey xmlns="http://schemas.datacontract.org/2004/07/System.Data.Objects.DataClasses" xmlns:b="http://schemas.datacontract.org/2004/07/System.Data" i:nil="true"/><a:ADR1>7 rue Diffonty</a:ADR1> ....
The method that receives this call has the following header:
public string UpdateUsager(fUsagerItem usageritem, bool checkonly){
The edmx where the entity is declared has the following header
<edmx:Edmx Version="2.0" xmlns:edmx="http://schemas.microsoft.com/ado/2008/10/edmx">
<!-- EF Runtime content -->
<edmx:Runtime>
<!-- SSDL content -->
<edmx:StorageModels>
<Schema Namespace="FRONT.Store" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2005" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2009/02/edm/ssdl">
I wanted to know if there could not be a problem between the fact that this edmx was generated before using sql server 2005 and we are using sql server 2012 now to update it and we only changed the ProviderManifestToken="2005"..
Thank you for your help
Your question is a bit ambiguous - does the call to your service fails before entering your method or, if not, do you mean the parameter is null or some of its properties are null?
If the latter, I can only guess that updating the Entity Framework model from the database, changed the property order in fUsagerItem class. You can manually inspect the .xsd file referenced by service's WSDL and see how WCF expects the XML to be. Change the serialization order of properties with [DataMember(Order = ?)] attribute, though you'll have to put those in designer-generated classes (which is a bad idea).
It is generally considered that you shouldn't directly use entity framework objects in web service, especially when you consume the service from other frameworks like PHP. You have more control over the serialization process when you create your own Data Transport Objects: you can hide some properties or introduce new ones that don't exist in your database. If you can persuade your client to change their implementation, I'd recommend using DTO classes in your sevice (AutoMapper can help a lot mapping DTO objects to entities and vice-versa).
Related
I am using breezejs + angular with olingo Odata v2 as backend service. I am able to get metadata correctly from Odata in breeze with Navigation Properties. However, when I tried to create an entity with association to other Entities. What breeze generates for me is something like {"displayName":"may 13","id":-1,"FK_page_id":1,"position":3,"FK_status_id":1,"title":"may13","weightPercentage":76,"FK_widget_id":1}
When I called manager.saveChanges(), it tried to create a batch request. Inside the batch request, it tried to post to the entity type and all those linked entities. I don't think this is correct behavior. How can I save just to the Entity type and also add relations to other entities?
In evaluating Angular + Breeze, does it support tracking changes with the consumed DTOs from services back to the backend Entity Framework?
Yes and no. Breeze tracks the changes on the client, and when you call saveChanges(), it sends the changed entities (with information about what properties changed) to the server. What happens on the server is up to you, so you could use the received data to modify the states of entities in an existing EF context, and accumulate change tracking info in EF until you decide to save it to the DB.
The provided EF + WebApi server-side components don't do that, however. They are built to streamline the following use case:
Client performs add/update/delete operations on entities and calls saveChanges().
Server creates a new EF DbContext and applies the changes to it.
Server applies validation rules (in the BeforeSaveEntities method), and rejects the save if they fail.
Server DbContext saves the changes to the database.
In this scenario, there is no long-lived EF DbContext tracking the changes; the change tracking is done on the client, and EF is used to process those changes on the server and save them in the DB.
That probably covers 90% of what most applications require, but there are hooks in place to intercept the save and make server-side changes before the save, and you can override any parts that don't fit your needs.
I get a security error:
The inner exception is: {System.Security.SecurityException --->
System.Security.SecurityException: Security error.
UPDATE
My problem is because Categories type (that is passed trough WCF) has inside a Products collection. The Categories and the rest of the model types are generated code with Entity Framework. The Products member in Categories is of type EntityCollection.
The Products collection in class Categories: (generated code)
[XmlIgnoreAttribute()]
[SoapIgnoreAttribute()]
[DataMemberAttribute()]
[EdmRelationshipNavigationPropertyAttribute("inventory_db_bigModel", "Products_fk", "Products")]
public EntityCollection<Products> Products
The question is how do I declare the Products collection in the client ServiceReference ?
I tried with ObservableCollection and Generic List but it gives me the same Security Error.
The client ServiceReference code is generated code and I'm not sure how the solution is so that I do not have to edit it each time it's regenerated.
Have you set up the clientaccesspolicy.xml and/or crossdomain.xml on the WCF service?
By design Silverlight is barred from making cross domain calls to prevent security threats like cross-site forgery.
To enable a Silverlight control to access a service in another domain, the service must explicitly opt-in to allow cross-domain access. By opting-in, a service states that the operations it exposes can safely be invoked by a Silverlight control, without potentially damaging consequences to the data that the service stores.
To allow the connection you have to set up either a clientaccesspolicy.xml or crossdomain.xml file in the root of the service you wish to consume.
The MSDN has more information.
I am using a WCF service between the Client side UI (Silverlight 3.0) and the Data Layer. We are using NHibernate for Database Access. So please tell me if my below understanding is correct or not:
UI calls WCF for a Save Method (for eg).
The WCF has a Save method in it which actually encapsulates a Save method from the Data
Access Object.
The Data Access Object method of Save in turn encapsulates a default Save Method of
NHibernate which actually saves some Business Object/s into the Database.
Also can someone tell me that how do we pass objects from WCF to the UI (Silverlight 3.0) layer and vice versa. I have read that we use DTO for that. But how does a DTO work? Do they correspond to the 'Data Contracts' in the WCF? If not then is the DTO declared on WCF (server) side and Client side code as well?
No, not quite....
UI calls the client-side proxy method Save
the WCF runtime takes that call and all parameters being passed in, and serializes them into a message (typically a XML serialized message)
the WCF runtime sends the serialized message over some kind of a transport media (whatever it is)
on the server side, the WCF runtime takes the incoming message
the message is deserialized, the appropriate class and method to handle it are identified
typically: a new instance of a service class is instantiated to handle the request
the WCF runtime unpacks the parameters and calls that appropriate message on the service class
same steps - basically backwards - are done for response
Important point: the only thing between the client and the server is a serialized message (which could be sent by e-mail or pigeon courier) - there's no other connection - no "remote object call" or anything like that at all
marc_s mentions the client-side proxies, which can be generated via the service references in your Silverlight project. The generated proxies are decent enough and provide an async model for running requests from the Silverlight side; those will look mostly like remoted procedure calls.
Another approach is to use the leaner (but maybe more advanced?) channel factory directly. A simple example of that can be found here. Both methods take care of most of the serialization details for you.
I am planning to use WCF (not ria) in conjunction with Entity Framework 4 and STE (Self tracking entitites). If I understand this correctly my WCF should return an entity or collection of entities (using LIST for example and not IQueryable) to the client (in my case Silverlight).
The client then can change the entity or update it. At this point I believe it is self tracking? This is where I sort of get a bit confused as there are a lot of reported problems with STEs not tracking.
Anyway, then to update I just need to send back the entity to my WCF service on another method to do the update. I should be creating a new OBJECTCONTEXT every time? In every method?
If I am creating a new objectcontext every time in every method on my WCF then don't I need to re-attach the STE to the objectcontext?
So basically this alone wouldn't work??
using(var ctx = new MyContext())
{
ctx.Orders.ApplyChanges(order);
ctx.SaveChanges();
}
Or should I be creating the object context once in the constructor of the WCF service so that 1 call and every additional call using the same WCF instance uses the same objectcontext?
I could create and destroy the WCF service in each method call from the client - hence creating in effect a new objectcontext each time.
I understand that it isn't a good idea to keep the objectcontext alive for very long.
You are asking several questions so I will try to answer them separately:
Returning IQueryable:
You can't return IQueryalbe. IQueryable describes query which should be executed. When you try to return IQueryable from service it is being executed during serialization of service response. It usually causes exception because ObjectContext is already closed.
Tracking on client:
Yes STEs can track changes on a client if client uses STEs! Assembly with STEs should be shared between service and client.
Sharing ObjectContext:
Never share ObjectContext in server environment which updates data. Always create new ObjectContext instance for every call. I described reasons here.
Attaching STE
You don't need to attach STE. ApplyChanges will do everything for you. Also if you want to returen order back from your service operation you should call AcceptChanges on it.
Creating object context in service constructor:
Be aware that WCF has its own rules how to work with service instances. These rules are based on InstanceContextMode and used binding (and you can implement your own rules by implement IInstanceProvider). For example if you use BasicHttpBinding, default instancing will be PerCall which means that WCF will create new service instance for each request. But if you use NetTcpBinding instead, default instancing will be PerSession and WCF will reuse single service instance for all request comming from single client (single client proxy instance).
Reusing service proxy on a client:
This also depends on used binding and service instancing. When session oriented binding is used client proxy is related to single service instance. Calling methods on that proxy will always execute operations on the same service instance so service instance can be stateful (can contains data shared among calls). This is not generally good idea but it is possible. When using session oriented connection you have to deal with several problems which can arise (it is more complex). BasicHttpBinding does not allow sessions so even with single client proxy, each call is processed by new service instance.
You can attach an entity to a new object context, see http://msdn.microsoft.com/en-us/library/bb896271.aspx.
But, it will then have the state unchanged.
The way I would do it is:
to requery the database for the information
compare it with the object being sent in
Update the entity from the database with the changes
Then do a normal save changes
Edit
The above was for POCO, as pointed out in the comment
For STE, you create a new context each time but use "ApplyChanges", see: http://msdn.microsoft.com/en-us/library/ee789839.aspx