locked
Can't create/insert object using Data Services (Internal Server Error 500) RRS feed

  • Question

  • I am trying to use Data Services to create a new object.  Here's what is good:

    • Successfully running VS2008 SP1 Beta1
    • Created EDM successfully in an ASP.NET web site.
    • Created DataService file successfully in the ASP.NET web site.
    • Can use EDM directly in an .aspx file within that site to query data.
    • Added a Silverlight (S2B2) project to the solution.
    • Used DataSvrUtil to generate client-side DataServiceContract classes for Silverlight.
    • Successfully used the S2B2 System.Data.Services.Client DataServices client to query data in Silverlight.
    • Imported the file generated by DataSvrUtil into the ASP.NET web site and changed the namespace so I can use the .NET Data Services client classes to try querying the Data Service without using Silverlight.
    • Successfully used the DataService classes within an aspx page in the web site.

    The problem I'm getting comes when I try to add a new object either in Silverlight or in the aspx page.  I imported the generated client classes into the web site project so I could eliminate Silverlight as a potential problem.  It turns out that I'm getting the same exception in both cases.

     

    Here is my code for adding a new object:

     

    Code Snippet

    SonixtreamModelClient.SonixtreamEntities entClient = new SonixtreamModelClient.SonixtreamEntities(new Uri(http://localhost:3267/solon.net/SonixtreamDataService.svc));

     

    SonixtreamModelClient.InventoryCutType cutType = entClient.InventoryCutType.First() as SonixtreamModelClient.InventoryCutType;

     

    SonixtreamModelClient.StationInventory newInv = new SonixtreamModelClient.StationInventory();

    newInv.Artist = "SI(Server): " + DateTime.Now.ToLongTimeString();

    newInv.InventoryCutType = cutType;

    newInv.OrgId = 647;

    entClient.AddObject("StationInventory", newInv);

     

    DataServiceResponse resp = entClient.SaveChanges();

     

    foreach (ChangesetResponse csr in resp) {

    foreach (EntityDescriptor ent in csr) {

    StationInventory inv = ent.Entity as StationInventory;

    if (ent.Error != null) {

    Debug.WriteLine("error: " + ent.Error.ToString());

    } else {

    Debug.WriteLine ("success: " + newInv.id);

    }

    }

    }

     

     

     

    The Debug.WriteLine line that displays the error is being hit, and it is writing out this exception:

     

    error: System.Net.WebException: The remote server returned an error: (500) Internal Server Error.

    at System.Net.HttpWebRequest.GetResponse()

    at System.Data.Services.Client.DataServiceContext.SaveChangesAsyncResult.BeginNextChange()

     

    My assumption was possibly that I don't have support for the PUT HTTP verb enabled.  But I don't know how to enable that verb, either when using VS2008 as a file-based web server or if I host the site in IIS7.  My research online indicates that I would need something called WebDAV to add onto IIS7 to support PUT (and DELETE), but that doesn't seem right, since nothing I've seen in the documentation about Data Services mentions the need for anything like that.

     

    Also, here are my entity set access rules from my DataService:

     

    config.SetEntitySetAccessRule("InventoryCutType", EntitySetRights.AllRead);

    config.SetEntitySetAccessRule("StationInventory", EntitySetRights.AllWrite);

     

    Or perhaps the issue is that I'm adding a linked object (the InventoryCutType)?  I'm just setting that value, and I'm not doing a Batch save...should I be using AddLink or something?

     

    Any thoughts?

     

    Thanks,

     

    David Cater

    Thursday, August 7, 2008 9:35 PM

Answers

  • I experimented some more and researched some more, and eventually I was able to get the code working.  This post was helpful:

     

    http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3675199&SiteID=1 

     

    This is the final code that worked.  The key was passing "Batch" as the save options:

     

    Code Snippet

    SonixtreamModelClient.InventoryCutType cutType = entClient.InventoryCutType.First() as SonixtreamModelClient.InventoryCutType;

    SonixtreamModelClient.StationInventory newInv = new SonixtreamModelClient.StationInventory();

     

    newInv.Artist = "SI(Server): " + DateTime.Now.ToLongTimeString();

    newInv.OrgId = 647;

    entClient.AddToStationInventory(newInv);

     

    entClient.AddLink(newInv, "InventoryCutType", cutType);

    entClient.MergeOption = System.Data.Services.Client.MergeOption.AppendOnly;

     

    DataServiceResponse resp2 = entClient.SaveChanges(SaveChangesOptions.Batch);

    foreach (ChangesetResponse csr2 in resp2) {

    foreach (EntityDescriptor ent2 in csr2) {

    SonixtreamModelClient.StationInventory inv = ent2.Entity as SonixtreamModelClient.StationInventory;

    if (ent2.Error != null) {

    Debug.WriteLine("error: " + ent2.Error.ToString());

    } else {

    Debug.WriteLine("success: " + newInv.id);

    }

    }

    }

     

     

     

    David

    Thursday, August 7, 2008 10:04 PM
  •  

    Can you check the response property of the WEbException or check if there are any InnerExceptions which show you the error ?

    or alternatively , you can use Fiddler to see the error on the wire.

    You can download fiddler here : http://www.fiddlertool.com/fiddler

    to be able to capture traces ,change this line  :

     

    SonixtreamModelClient.SonixtreamEntities(new Uri(http://localhost:3267/solon.net/SonixtreamDataService.svc));

     

    to be

     

     

    there is a period "." after localhost.

     

    Thursday, August 7, 2008 10:24 PM
    Moderator

All replies

  • I did try changing to the following code, and I got a different exception:

     

    entClient.AddLink(newInv, "InventoryCutType", cutType);

    //newInv.InventoryCutType = cutType;

     

    I got the exception "The context is not currently tracking the entity".  I'm not sure what that means (this is my first day experimenting with Data Services).

     

    Also, I did experiment with adding a new InventoryCutType instead of a new StationInventory object (InventoryCutType is much simpler, a basic reference table).  That worked successfully and the new record was added to the database.  So I suspect the problem is with the link from StationInventory to InventoryCutType (represented as a NavigationProperty in the edmx file).

     

    Thanks for any help anyone can offer.

     

    David

    Thursday, August 7, 2008 9:47 PM
  •  

    Hi David,

     You can get detailed error messages by turning on Dev Error Mode . Please see here :

    http://blogs.msdn.com/phaniraj/archive/2008/06/18/debugging-ado-net-data-services.aspx

     

    WIthout a clear idea of how your store (database) looks like , I can guess that the insert is failing because of some database constraint . again , it would be helpful to debug this issue if you got the complete error information by enabling the above options.

     

    Thursday, August 7, 2008 10:02 PM
    Moderator
  • I experimented some more and researched some more, and eventually I was able to get the code working.  This post was helpful:

     

    http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3675199&SiteID=1 

     

    This is the final code that worked.  The key was passing "Batch" as the save options:

     

    Code Snippet

    SonixtreamModelClient.InventoryCutType cutType = entClient.InventoryCutType.First() as SonixtreamModelClient.InventoryCutType;

    SonixtreamModelClient.StationInventory newInv = new SonixtreamModelClient.StationInventory();

     

    newInv.Artist = "SI(Server): " + DateTime.Now.ToLongTimeString();

    newInv.OrgId = 647;

    entClient.AddToStationInventory(newInv);

     

    entClient.AddLink(newInv, "InventoryCutType", cutType);

    entClient.MergeOption = System.Data.Services.Client.MergeOption.AppendOnly;

     

    DataServiceResponse resp2 = entClient.SaveChanges(SaveChangesOptions.Batch);

    foreach (ChangesetResponse csr2 in resp2) {

    foreach (EntityDescriptor ent2 in csr2) {

    SonixtreamModelClient.StationInventory inv = ent2.Entity as SonixtreamModelClient.StationInventory;

    if (ent2.Error != null) {

    Debug.WriteLine("error: " + ent2.Error.ToString());

    } else {

    Debug.WriteLine("success: " + newInv.id);

    }

    }

    }

     

     

     

    David

    Thursday, August 7, 2008 10:04 PM
  • Thanks, Phani.  That sounds really useful.  Unfortunately, I think I may be doing something incorrectly.  I set UseVerboseErrors to true as specified in that link you sent.  I already had IncludeExceptionDetailInFaults set to true in the ServiceBehavior. 

     

    I removed the SaveChangesOptions.Batch parameter to SaveChanges to force the error state to occur again.  The call to SaveChanges is not raising an exception.  As shown in the code, the error is being returned in the EntityDescriptor returned as part of the ChangesetResponse objects.  The error was the same:

     

    System.Net.WebException: The remote server returned an error: (500) Internal Server Error.

    at System.Net.HttpWebRequest.GetResponse()

    at System.Data.Services.Client.DataServiceContext.SaveChangesAsyncResult.BeginNextChange()

     

    Any thoughts on where else I might see the Verbose error details?

     

    Thanks,

     

    David

    Thursday, August 7, 2008 10:10 PM
  •  

    Can you check the response property of the WEbException or check if there are any InnerExceptions which show you the error ?

    or alternatively , you can use Fiddler to see the error on the wire.

    You can download fiddler here : http://www.fiddlertool.com/fiddler

    to be able to capture traces ,change this line  :

     

    SonixtreamModelClient.SonixtreamEntities(new Uri(http://localhost:3267/solon.net/SonixtreamDataService.svc));

     

    to be

     

     

    there is a period "." after localhost.

     

    Thursday, August 7, 2008 10:24 PM
    Moderator
  • Thanks the pointers.  Those techniques are really helpful.  Here are the results and some additional information about a bug other people might run into:

     

    1. Checking WebException.Response.  Once I knew what to look for, that showed me exactly what the error was.  Here's the code I'm using to check it (abbreviated):

     

    Code Snippet

    foreach (ChangesetResponse csr2 in resp2) {

    foreach (EntityDescriptor ent2 in csr2) {

    if (ent2.Error != null) {

    WebException we = ent2.Error as WebException;

    if (we != null) {

    StreamReader rdr = new StreamReader(we.Response.GetResponseStream());

    string s = rdr.ReadToEnd();

    }

    }

    }

    }

     

     

    Here's the resulting string:

     

    Entities in 'SonixtreamEntities.StationInventory' participate in the 'FK_StationInventory_InventoryCutType' relationship. 0 related 'InventoryCutType' were found. 1 'InventoryCutType' is expected.

     

    So that's much better than the "500 Internal Server Error" I was getting before.

     

    2. Using Fiddler.  It took me a bit to figure out exactly what was going on, but once I did this was very helpful.  As Phani said, my Entities object is initialized with:

     

    new Uri("http://localhost.:3267/solon.net/SonixtreamDataService.svc")

     

    Note the "." after localhost.  In Fiddler, when I made the call to BeginSaveChanges I saw this request come across:

     

    POST /solon.net/SonixtreamDataService.svc/StationInventory HTTP/1.1

    User-Agent: Microsoft ADO.NET Data Services

    Accept: application/atom+xml,application/xml

    Content-Type: application/atom+xml

    Host: localhost.:3267

    Content-Length: 800

    Expect: 100-continue

     

    That was followed by the Atom data for the record I was adding.  Initially the response for that request was showing as:

     

    [Fiddler] Connection to localhost. failed.<BR>Exception Text: No connection could be made because the target machine actively refused it

     

    A bit of research online led me to go to Tools -> Fiddler Options in Fiddler and turn off the "Enable IPv6 (if available)" check box.  Once I did that, got the following response in Fiddler:

     

    Entities in 'SonixtreamEntities.StationInventory' participate in the 'FK_StationInventory_InventoryCutType' relationship. 0 related 'InventoryCutType' were found. 1 'InventoryCutType' is expected.

     

    ...followed by the stack trace.  So I was able to see the full error this way as well, as Phani suggested.

     

    3. Server error: Could not load file or assembly 'App_Web...'  In the process of debugging this, I started getting another Internal Server Error making a different data services call.  Fortunately I was now armed with my new debugging techniques.  Looking at the request in Fiddler showed me the following response being returned from the server, embedded in lots of HTML formatting code:

     

    Could not load file or assembly 'App_Web_4jg3elmi, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified...

     

    I had run into this earlier in the day.  This appears to be a long-standing issue with ASP.NET:

    http://forums.asp.net/t/986130.aspx?PageIndex=1 .  I resolved this myself by setting the compilation Debug option to false in web.config, running my program, then setting the Debug option back to true.  Once I did that, that particular error went away (temporarily).  I don't have a final solution for that yet, but doing the Debug trick is letting me continue with my development.

     

    Thanks again for your help, Phani!

     

    David

    Friday, August 8, 2008 4:47 PM
  • Wow ! Thanks for writing  this up David !
    I am sure it will be really useful for the other users.

    From the error it looks like the ENtity types InventoryCutType and
    StationInventory have a 1:1 association between them.

    You can setup a link between them in the CLient Layer by using the AddLink API.

    Code Snippet

    entClient.AddLink(newInv,"InventoryCutType", cutType); //<-- this is to add the link between the entities

     

     

    The SaveChangesOptions.Batch is because we have a bug in Beta1 bits which doesnt allow
    inserting and linking an entity in the same request unless you use Batch .

    Change your code to be :


    Code Snippet

    SonixtreamModelClient.SonixtreamEntities entClient = new SonixtreamModelClient.SonixtreamEntities(new Uri(http://localhost:3267/solon.net/SonixtreamDataService.svc));

    SonixtreamModelClient.InventoryCutType cutType = entClient.InventoryCutType.First()
        as SonixtreamModelClient.InventoryCutType;

    SonixtreamModelClient.StationInventory newInv = new SonixtreamModelClient.StationInventory();

    newInv.Artist = "SI(Server): " + DateTime.Now.ToLongTimeString();

    newInv.InventoryCutType = cutType;
    newInv.OrgId = 647;

    entClient.AddObject("StationInventory", newInv);
    entClient.AddLink(newInv,"InventoryCutType", cutType); //<-- this is to add the link between the entities

    DataServiceResponse resp = entClient.SaveChanges(SaveChangesOptions.Batch);

    foreach (ChangesetResponse csr in resp) {

      foreach (EntityDescriptor ent in csr) {

        StationInventory inv = ent.Entity as StationInventory;

          if (ent.Error != null) {

           Debug.WriteLine("error: " + ent.Error.ToString());

          } else {

    Debug.WriteLine ("success: " + newInv.id); }
      }
    }


     

     

     

    you can learn about how to use the client layer to work with associations here :

    Working with Associations in ADO.NET Data Services
    Friday, August 8, 2008 5:22 PM
    Moderator