WCF call yields 400 Bad Request

Posts   
 
    
HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 10-Jan-2011 13:27:38   

Hi,

Using LLBLGen 3.0, WCF, .NET 3.5, WPF SmartClient

I have made some WCF services that transfers llblgen entities (adapter generated) from server to client. This works fine for collections with thousands of entities. But when I transfer new entities from client to server, I get an "400 bad request" error. It has something to do with MaxMessageSize, so I set all sizes and quotas on the wcf-binding to really big values, and I keep getting "bad request". When I enable wcf logging, even the logger fails with "Exception of type 'System.ServiceModel.Diagnostics.PlainXmlWriter+MaxSizeExceededException' was thrown.". In my logfolder, there is then a really huge log file.

I already tried just sending a "UnitOfWork2" entity over the wire (serialized using the NetDataContractSerializer) and this runs out of memory.

The entities are really quite small (just 10 or so fields of int's and long's), but they are created on the client, not coming out of the database. The intention is to send them to the server, where they will be inserted in the DB.

Is there any restriction or caveat with serializing newly created entities ?

HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 10-Jan-2011 14:40:38   

I have some more info on this issue (bug ?) While everything pointed to the maximum messagesize, it has to do with relationships between the entities.

I have a GridEntity, which has some parameter fields, and a collection of CellEntities (that have a foreign key GridId)

On the client side, I have the following code :


            GridEntity grid = new GridEntity();
            grid.Rows = numRows;
            grid.Columns = numColumns;
            for (int i = 0; i < numRows; i++)
            {
                for (int j = 0; j < numColumns; j++)
                {
                    CellEntity cell = new CellEntity();
                    cell.Row = i;
                    cell.Column = j;
                    grid.CellEntities.Add(cell);
                }
            }

Then I sent this entity to my WCF Proxy , using the channelfactory :


            IGridService gridservice = ChannelFactory.CreateChannel();

Here's the interesting part : when there is no related entity, the WCF call proceeds. When there is a relationship, i get the "400 bad request" error (with no innerexception). This is both when using the NetDataContractSerializer, as well as the default llblgen serializer

These are the case :


           gridservice.SaveGrid(grid); <-- 400 BAD REQUEST


           grid.Cells.Clear();
           gridservice.SaveGrid(grid); <-- succeeds


           CellEntity cell = grid.Cells[0];
           gridservice.SaveCell(cell); <-- 400 BAD REQUEST


           CellEntity cell = grid.Cells[0];
           cell.GridEntity = null;
           gridservice.SaveCell(cell); <-- succeeds

This leads me to believe there is an issue with serializing relationships of newly created entities ? When I serialized entities fetched from the database using prefetchpaths, I can successfully sent them from the server to the client.

HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 10-Jan-2011 15:28:17   

It was indeed the MaxMessageSizeReceived property that needed to be increased. The serialization of the relationship made it exceed it's max size. (It seems that everything is serialized as long and deep as there are relationships ? - Is this controllable ?)

But now on the server, when I do a recursive save of the root entity (GridEntity) that came from the client, it fails because the generated query tries to insert NULL for the foreign key in the subobjects (the GridId in CellEntity). Isn't this supposed to be resolved automatically. I tried a UnitOfWork2 and it's the same ...

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 10-Jan-2011 16:25:38   

But now on the server, when I do a recursive save of the root entity (GridEntity) that came from the client, it fails because the generated query tries to insert NULL for the foreign key in the subobjects (the GridId in CellEntity).

Please post the Client Code that builds the graph to be saved.

HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 10-Jan-2011 18:39:48   

Client side is very simple :


    GridEntity grid = new GridEntity();
            grid.Rows = numRows;
            grid.Columns = numColumns;
            for (int i = 0; i < numRows; i++)
            {
                for (int j = 0; j < numColumns; j++)
                {
                    CellEntity cell = new CellEntity();
                    cell.Row = i;
                    cell.Column = j;
                    grid.CellEntities.Add(cell);
                }
            }

I even tried adding the following line in the inner loop, but it's the same result:


                    cell.Grid = grid;

When I add a breakpoint on the server and inspect the grid-entity right before it's saved, it contains the correct collection of cells, and for each cell-entity, IsNew is set to true (as it should). Also, each cell has it's Grid-property set to the correct instance, but cell.gridId == 0 (normal, because at this point the entity is not yet saved). I was under the impression that adapter.SaveEntity(grid, null, true, true) should save the grid-entity, and recusively all cells, setting the correct gridId FK along the way ?

Edit : I tried also the following server-side code :


            DataAccessAdapter adapter = new DataAccessAdapter();
            adapter.SaveEntity(grid,true,false);
            adapter.SaveEntityCollection(grid.Cells);

And I get the same error. What's weird is when I inspect the grid-variable after the first save, it's id is still 0 (although it's inserted in Oracle), and the properties in the quickwatch window I get : Rows = 'grid.Rows' threw an exception of type 'SD.LLBLGen.Pro.ORMSupportClasses.ORMEntityOutOfSyncException'. This should not happen since I set RefetchAfterSave = true in the adapter.SaveEntity ? The second save then fails because it tries to insert NULL in the gridId FK.

I then tried instanciating the servercode directly from the client (bypassing the WCF layer) and it still fails ... Could it be something to do with Oracle and sequences ? (I'm used to working with SQLserver normally, and never had that the id wasn't filled in after a save)

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 11-Jan-2011 09:04:25   

You have traced it to the root simple_smile Most probably the Sequence is not set in the Designer.

HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 11-Jan-2011 09:11:13   

That will probably be the case.

Digging a little deeper, I have set all tracing in the config file to verbose so I can see what's going on. After saving the first grid-entity, the PK is still null (<undefined value>), so the RefetchAfterSave uses the where-clause "where id = null". No wonder that doesn't work and the entity is still "out of sync".

Now i'll go figure out how to do that sequence stuff in the designer. (Is there no way to let LLBLgen figure that out automatically when getting the metadata ?) I never had such a hassle with SQLServer simple_smile

Kind regards.

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 11-Jan-2011 09:26:25   

SQL Server has 2 Sequences (SCOPE_IDENTITY & @@IDENTITY). One of them is picked by default according to the target database version.

All you need to do is to make sure the correct sequence is assigned to the field. Go to: Entity->Edit->Field Mappings Then you can find a column in the fields grid called "Sequence name", that's where you can change the sequence.

Also make sure you read this: Trigger based sequence values (Oracle/Firebird)

HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 11-Jan-2011 09:32:35   

Sweet, it works !!!!

thanks once again for the patience and support !

Kind regards.