SingleResult<T> not serializable in Web API when querying by key - odata

Trying to find single record using primary key CourseID against odata web.api using this:
var editedcourse = container.Courses.Where(c => c.CourseID == ID).SingleOrDefault();
This is error:
<m:innererror>
<m:message>The 'ObjectContent`1' type failed to serialize the response body for content type 'application/atom+xml; charset=utf-8'.</m:message>
<m:type>System.InvalidOperationException</m:type>
<m:stacktrace></m:stacktrace>
<m:internalexception>
<m:message>'SingleResult`1' cannot be serialized using the ODataMediaTypeFormatter.</m:message>
<m:type>System.Runtime.Serialization.SerializationException</m:type>

The web.api controller method by default was not queriable, thus client failed. Added annotation to fix: [Queryable(AllowedOrderByProperties = "Id")]

Try adding the code below to your WebApiConfig.cs file.
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
I think the first two lines are optional if you don't use Json format.
Refer to
http://social.msdn.microsoft.com/Forums/vstudio/en-US/a5adf07b-e622-4a12-872d-40c753417645/web-api-error-the-objectcontent1-type-failed-to-serialize-the-response-body-for-content?forum=wcf

I think you have to make sure any relations are loaded. As a workaround you could create a new DTO (data transfer object) and put all you need in it.

Related

Dynamic binding model for use in HttpClient

I have a Web Api that takes a complex object and adds it to the database.
var myWidgit= new Widgit() {
Name = "WidgitName",
Price = 50,
Category = "Appliance" };
HttpResponseMessage response = client.PostAsync("api/createwidgit", myWidgit);
I need to make a one off call to the API and I would like to avoid creating a separate class file for Widgit.
Is there a way to define the Widgit class and assign it values in the method that makes use of it? Sort of like a dynamic class just used in this method.
I think I figured it out ...
HttpResponseMessage response = client.PostAsync("api/createwidgit", new StringContent(string.Format("Name={0}&Price={1}&Category={2}", HttpUtility.UrlEncode("WidgitName"), HttpUtility.UrlEncode(50), HttpUtility.UrlEncode("Appliance"), Encoding.UTF8, "application/x-www-form-urlencoded"));
Essentially the dynamic object I was looking to create is accomplished using
new StringContent(string.Format("Name={0}&Price={1}&Category={2}", HttpUtility.UrlEncode("WidgitName"), HttpUtility.UrlEncode(50)), HttpUtility.UrlEncode("Appliance"), Encoding.UTF8,
"application/x-www-form-urlencoded")
Sorry I could not figure out better formatting

Web API 2 Odata 4 Parameter Issue

I'm having problems defining a function for odata4. The default get would work but I want to require a user parameter so a client set can be determined, other tables are involved so LINQ is required, I also return a DTO instead of the default table info (EF). Below is the code. I get a "Invalid EntitySetPath detected. 'bindingParameter/Client' is not a valid entity set path for procedure 'Default.GetClients'." What am I doing wrong here?
WebApiConfig
public static void Register(HttpConfiguration config)
{
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<client>("Client").EntityType.HasKey(p => p.int_id);
var function = builder.Function("GetClients");
function.Parameter<string>("user");
function.ReturnsCollectionFromEntitySet<client>("Client");
builder.EntitySet<ClientDTO>("ClientDTO");
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: null,
model: builder.GetEdmModel());
WebApp.Controller
[ODataRoute("GetClients(user={user})")]
[EnableQuery(PageSize=25)]
public IQueryable<ClientDTO> GetClients([FromODataUri] string user)
{
var clients = (from c in db.clients
join ...
If your OData controller is returning the DTO, the function should look like this:
var function = builder.Function("GetClients");
function.Parameter<string>("user");
function.ReturnsCollectionFromEntitySet<ClientDTO>("Client");
With your current setup, your OData route of GetClients says that it is returning a ClientDTO object, but your WebApiConfig is stating you are returning a Client object.
As the Entity Collection being returned is actually the DTO. The part that shows ("Client") is simply how the OData service will report the name of the object to the project consuming the OData service. For my own personal sanity, I typically include DTO as well so I know when I'm using a DTO and when I'm using a direct entity. So in my own setup i'd return ("ClientDTO"), just a personal preference.

how to get an unsaved entity on server but not for saving?

i need to send my unsaved entity from the client to the server but not for saving changes
but inorder to do a process using the data on the entity and then change some of it's values and pass it back to the client
is this possible?
if not what are my options?
i tried to export the entity and then send it to a method on the webapi controller that gets a JObject but didn't find a way to deserialize it to the server entity
We did have a similar problem and found a solution as follows:
You need to take into consideration the way breeze manages it's objects.
1.Create custom saveBundle.
Consider complex order object.You need to fill your save bundle with each nested object inside order.
Like:
var saveBundle = new Array();
saveBundle.push(order.SaleAccountingInfo);
saveBundle.push(order.CostAccountingInfo);
saveBundle.push(order);
2.Create custom save options, where you can point to your custom Save Method on server
Like:
var so = new breeze.SaveOptions({ resourceName: "BookOrder" });
3.Call standard breeze function and pass it created params
manager.saveChanges(saveBundle, so).fail(function () {
// manager.rejectChanges();TODO check what needed
deferred.resolve(true);
});
On server you need to have you custom function ready and hook some breeze delegates
[HttpPost]
public SaveResult BookOrder(JObject orderBundle)
{
context.BeforeSaveEntityDelegate = OrderBeforeSaveEntity;
context.BeforeSaveEntitiesDelegate = SaveOrder;
context.AfterSaveEntitiesDelegate = BookOrderAfterSave;
try
{
return context.SaveChanges(orderBundle);
}
catch (Exception)
{
throw;
}
}
You can a lot of stuff in first two delegates but it is the last one you are looking for
private void BookOrderAfterSave(Dictionary<Type, List<EntityInfo>> orderSaveMap, List<KeyMapping> orderKeyMappings)
{
var orderEntity = orderSaveMap.Where(c => c.Key == typeof(BL.Orders.Order)).Select(d => d.Value).SingleOrDefault();
BL.Orders.Order order = (BL.Orders.Order)orderEntity[0].Entity; //your entity
//logic here
}
Hope it points to right direction.
we are doing something similar here. it'll save the entity so i'm not sure if this fits your question.
you can do:
entity.entityAspect.setModified()
then issue a saveChange()
then you can do your calculations on the server.
in our case we are using breeze.webapi so we are doing this in the beforeSave(entity) method.
breeze by design sends the changed entity then back to the client where the cache gets updated with your changes done on the server.

RestSharp Serializer Setter has no effect

I am struggling to make RestSharp talk with MVC API with EF4 and I'm very close to making it work. In order to overcome the interface limitation of the stock serializer I am using the Json.NET serializer. For the deserialization it worked out of the box but I can't make RestSharp use my custom serializer. The method Serializeis not getting called. Everything compiled great but doesn't work. Here is the code:
var client = CreateClient();
// client.Authenticator = new HttpBasicAuthenticator(username, password);
var request = new RestRequest("api/{type}s", Method.GET);
request.AddUrlSegment("type", typeof(T).Name);
request.RequestFormat = DataFormat.Json;
request.AddParameter("criteria", criteria);
IRestResponse<List<T>> response = client.Execute<List<T>>(request);
HandleResponse(response);
return response.Data;
Any ideas?
Edit
I tried to follow an example and change the post method to accept JObject and it worked!. But trying to call jitem.ToObject<Item>() caused the following exception:
Error converting value "System.Collections.Generic.List`1[DataAbstractionLayer.Poco.ItemCheckpoint]" to type 'System.Collections.Generic.ICollection`1[DataAbstractionLayer.Poco.ItemCheckpoint]'.
But more interesting is the inner exception:
Could not cast or convert from System.String to System.Collections.Generic.ICollection`1[DataAbstractionLayer.Poco.ItemCheckpoint].
Could it be that Json.NET converts collection items automatically to string?

Using the Json.NET serializer in an MVC4 project

I'm starting to learn Json.NET, but I'm having trouble using its serializer. I have a new MVC4 project with a Web.API service:
public class PTE_TestsController : ApiController {
PTE_TestsRepository _repository = new PTE_TestsRepository();
// GET /api/PTE_Tests/5
public HttpResponseMessage<string> Get(int id) {
try {
PTE_Test test = _repository.GetTest(id);
return new HttpResponseMessage<string>(JsonConvert.SerializeObject(test));
} catch {
return new HttpResponseMessage<string>(HttpStatusCode.NotFound);
}
}
}
JsonConvert.SerializeObject() works as expected and returns a string. My Web.API controller returns that as part of an HttpResponseMessage. The end result, when viewed in Fiddler, is not JSON data, but JSON data being serialized again (I think):
"{\"ID\":1,\"Name\":\"Talar Tilt\",\"TagID\":1,\"PracticeID\":1,
\"SpecificAreaID\":1,\"TypeID\":1,\"VideoID\":1,\"PicID\":1}"
Does someone know how to turn off the default serializer so I can use Json.NET directly? By the way, I'm not using the default serializer because I can't figure out how to make it work with complex objects (PTE_Test will eventually contain members of type List).
Alternately, it will also solve my problem if someone can explain how to use the default serializer with complex objects. MSDN's explanation didn't help me.
Rick Strahl has a blog on that here with a code that works.
As others have pointed out, you need to create a formatter and replace the DataContractSerializer with the JSON.NET serializer. Although, if you're not in a rush for JSON.NET specifically, rumor has it that next beta/rc is going to have support for JSON.NET built in.
Conceptually, however, you're missing part of the magic of WebAPI. With WebAPI you return your object in it's native state (or IQueryable if you want OData support). After your function call finishes the Formatter's take over and convert it into the proper shape based on the client request.
So in your original code, you converted PTE_Test into a JSON string and returned it, at which point the JSON Formatter kicked in and serialized the string. I modified your code as follows:
public class PTE_TestsController : ApiController {
PTE_TestsRepository _repository = new PTE_TestsRepository();
public HttpResponseMessage<PTE_Test> Get(int id) {
try {
PTE_Test test = _repository.GetTest(id);
return new HttpResponseMessage(test);
} catch {
return new HttpResponseMessage<string>(HttpStatusCode.NotFound);
}
}
}
Notice how your function returns PTE_Test instead of string. Assuming the request came in with a request header of Accept = application/json then the JSON formatter will be invoked. If the request had a header of : Accept = text/xml the XML formatter is invoked.
There's a decent article on the topic here. If you're a visual learner, Scott Gu shows some examples using fiddler in this video, starting around 37 minutes. Pedro Reys digs a little deeper into content negotiation here.
The way to do this is to use formatters.
Check out: https://github.com/WebApiContrib/WebAPIContrib/tree/master/src/WebApiContrib.Formatting.JsonNet.
Json.NET support will be in the RC release of Web API.

Resources