GWT: Getting 404 when submitting AJAX request in my GWTTestCase - ajax

I'm using Eclipse Indigo on win XP and trying to write a GWT test case for my GWT 2.4 application. Specifically, I'm trying to test an AJAX request, but I'm getting a 404. I thought GWT will spin up its own server in hosted mode? My code is
public class GetHtmlTest extends GWTTestCase {
public void gwtSetUp() {
...
submitButton = new Button();
DOM.setElementAttribute(submitButton.getElement(), "id", Productplus_gwt.SUBMIT_BUTTON_ID);
...
}
#Test
public void testSuccessEvent() {
nameField.setText(VALID_ID);
submitButton.click();
Timer timer = new Timer() {
public void run() {
final Element contentDiv = DOM.getElementById(Productplus_gwt.CONTENT_DIV_ID);
final String divText = contentDiv.getInnerText();
assertNotNull(divText);
assertEquals(-1, divText.toLowerCase().indexOf("error") );
finishTest();
}
};
timer.schedule(100);
delayTestFinish(2000);
} // testSuccessEvent
Ultimately, clicking the button causes this AJAX call ...
productPlusService.getHtml(docId, new AsyncCallback<String>() {
public void onFailure(Throwable caught) {
submitButtonElement.setAttribute("enabled", Boolean.TRUE.toString());
contentDiv.setInnerHTML("<span>Error: " + caught.getMessage() + "</span>");
}
public void onSuccess(String result) {
submitButtonElement.setAttribute("enabled", Boolean.TRUE.toString());
contentDiv.setInnerHTML(result);
// Format tabs
postHtmlProcessing();
}
});
I run the test by right clicking on it, selecting "Run As" and "GWT Test Case". The error in the console was
[WARN] 404 - POST /com.myco.clearing.productplus.Productplus_gwt.JUnit/getHtml (10.40.70.197) 1444 bytes
Request headers
Host: 10.40.70.197:2084
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19
Accept-Language: en-us
Accept: */*
Connection: Keep-Alive
Referer: http://10.40.70.197:2084/com.myco.clearing.productplus.Productplus_gwt.JUnit/junit-standards.html?gwt.codesvr=10.40.70.197:2080
X-GWT-Permutation: HostedMode
X-GWT-Module-Base: http://10.40.70.197:2084/com.myco.clearing.productplus.Productplus_gwt.JUnit/
Content-Type: text/x-gwt-rpc; charset=utf-8
Content-Length: 217
Response headers
Content-Type: text/html; charset=iso-8859-1
Content-Length: 1444
Any ideas what's going wrong? Thanks, - Dave

For JUnit tests, you have to declare your servlets in your module's gwt.xml using the <servlet path="..." class="..." /> element.

Related

ASP.NET MVC Ajax Post has no data

I've struggled with this one for too long, maybe I'm missing something simple. I've been trying to use an ajax form to avoid reloading the whole page after submitting a form. Everything is looking fine, and Chrome DevTools is showing a good post holding all of my data. When I get to my action in the controller, my view model is empty and in its initialized state. So my though is it has something to do with the way the values are getting mapped to my model on the server side.
This is sort of my code, I was aiming for more than this but I've stripped a lot of it away while trying to trouble shoot. I feel like this is the most basic possible form of Ajax form post. I tried making the names and variables generic to try and simplify, so if something don't add up that might be why.
Please help I'm going crazy.
View:
#model EmiExpress.Web.Areas.Reports.Models.TurnkeyLiability.AddNewReportFormVm
#using (Ajax.BeginForm("NewReport", "Reports",
new AjaxOptions { HttpMethod = "POST" } ))
{
<div>
#Html.TextBoxFor(model => model.GroupId)
</div>
<div>
#Html.DevExpress().CheckBoxFor(
model => model.Save,
s =>
{
s.Text = "Save Values?";
}
).GetHtml()
</div>
<div>
<input type="submit" value="Submit Data" id="btnSubmit" />
</div>
}
Controller Action:
[HttpPost]
public ActionResult NewReport(AddNewReportFormVm viewModel)
{
int x = 5;
if (ModelState.IsValid)
{
x = 10; //just some junk while I try to get this working
}
return PartialView("Controls/_cbpReportRunLoading", x);
}
Model:
public class AddNewReportFormVm
{
public AddNewReportFormVm()
{
GroupId = "";
Save = false;
}
[Required]
public string GroupId{ get; private set; }
public bool Save{get; set;}
}
Network Response Headers:
Cache-Control: private
Content-Length: 1130
Content-Type: text/html; charset=utf-8
Date: Tue, 12 Jun 2018 02:41:05 GMT
Persistent-Auth: true
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
X-AspNetMvc-Version: 5.2
X-Powered-By: ASP.NET
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcc3RlZmFudG91YmlhXHNvdXJjZVxyZXBvc1xFbWlFeHByZXNzXEVtaUV4cHJlc3MuV2ViXFJlcG9ydHNcVHVybmtleUxpYWJpbGl0eVxSdW5OZXdSZXBvcnQ=?=
Request Headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Length: 2300
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
DXCss: 0_2312,1_50,1_53,1_51,0_2317,1_40,1_17,0_2214,1_16,0_2219,0_2221,0_2225,1_18,1_4,0_2257,18_3,18_11,18_7,0_2261,0_2313,1_34,0_2273,16_3,16_11,16_7,0_2277,1_44,0_2192,24_359,24_364,24_360,1_20,9_12,9_15,0_2338,9_1,0_2342,9_4,1_7,15_0,15_4,/Content/Site.css,/Areas/Reports/Content/TurnkeyLiability.css
DXScript: 1_228,1_226,1_227,1_225,1_304,1_211,1_185,1_221,1_188,1_182,1_280,1_293,1_271,1_287,1_290,1_184,17_42,17_3,1_286,1_189,17_8,1_298,1_193,17_10,1_288,1_195,1_194,17_11,1_209,1_217,1_296,1_279,1_302,1_254,1_235,1_247,1_303,1_222,17_12,1_297,17_41,1_190,1_223,1_291,1_289,1_196,1_256,1_263,1_262,1_255,1_252,1_259,1_253,1_261,1_258,1_257,1_248,1_244,1_242,1_251,1_250,1_249,1_246,1_245,1_260,1_241,1_238,1_239,1_240,1_243,17_15,17_17,1_272,1_273,17_19,1_274,1_275,17_20,17_21,1_224,17_14,1_277,17_24,17_28,1_281,17_25,1_294,17_27,1_292,1_295,17_32,1_299,17_36,17_40,1_192,1_285,18_36,18_38,18_33,18_42,18_37,18_35,17_31,1_208,1_206,1_212,1_201,1_215,1_203,1_205,1_204,1_284,1_198,1_213,17_1,1_197,17_0,1_199,17_2,1_200,17_4,1_202,1_219,17_7,17_23,1_207,17_9,1_276,1_216,17_22,1_214,1_218,17_38,1_220,16_52,16_152,16_47,16_36,16_153,16_28,16_27,16_48,16_50,16_32,16_41,16_159,16_154,16_34,16_51,16_54,16_40,16_158,16_43,16_44,16_33,16_162,16_46,16_45,16_55,16_49,16_31,16_38,16_37,16_39,16_53,16_42,16_26,16_29,16_30,17_35,16_160,16_35,10_11,10_10,10_12,10_13,10_14,17_6,1_236,17_16,1_229,24_401,24_400,24_402,24_403,24_406,24_407,24_408,24_404,24_405,1_230,24_379,24_380,9_45,9_36,24_388,24_398,9_38,9_37,17_30,9_46,17_44,9_42,9_39,9_31,17_29,9_41,9_32,9_44,9_43,9_40,15_16,15_14,15_10,15_11,15_13,20_0,1_237,9_48,9_47
Host: localhost:57144
Origin: http://localhost:57144
Referer: http://localhost:57144/Reports/TurnkeyLiability
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36
X-Requested-With: XMLHttpRequest
Form Data:
GroupId: abc
Save: C
DXScript: 1_228,1_226,1_227,1_225,1_304,1_211,1_185,1_221,1_188,1_182,1_280,1_293,1_271,1_287,1_290,1_184,17_42,17_3,1_286,1_189,17_8,1_298,1_193,17_10,1_288,1_195,1_194,17_11,1_209,1_217,1_296,1_279,1_302,1_254,1_235,1_247,1_303,1_222,17_12,1_297,17_41,1_190,1_223,1_291,1_289,1_196,1_256,1_263,1_262,1_255,1_252,1_259,1_253,1_261,1_258,1_257,1_248,1_244,1_242,1_251,1_250,1_249,1_246,1_245,1_260,1_241,1_238,1_239,1_240,1_243,17_15,17_17,1_272,1_273,17_19,1_274,1_275,17_20,17_21,1_224,17_14,1_277,17_24,17_28,1_281,17_25,1_294,17_27,1_292,1_295,17_32,1_299,17_36,17_40,1_192,1_285,18_36,18_38,18_33,18_42,18_37,18_35,17_31,1_208,1_206,1_212,1_201,1_215,1_203,1_205,1_204,1_284,1_198,1_213,17_1,1_197,17_0,1_199,17_2,1_200,17_4,1_202,1_219,17_7,17_23,1_207,17_9,1_276,1_216,17_22,1_214,1_218,17_38,1_220,16_52,16_152,16_47,16_36,16_153,16_28,16_27,16_48,16_50,16_32,16_41,16_159,16_154,16_34,16_51,16_54,16_40,16_158,16_43,16_44,16_33,16_162,16_46,16_45,16_55,16_49,16_31,16_38,16_37,16_39,16_53,16_42,16_26,16_29,16_30,17_35,16_160,16_35,10_11,10_10,10_12,10_13,10_14,17_6,1_236,17_16,1_229,24_401,24_400,24_402,24_403,24_406,24_407,24_408,24_404,24_405,1_230,24_379,24_380,9_45,9_36,24_388,24_398,9_38,9_37,17_30,9_46,17_44,9_42,9_39,9_31,17_29,9_41,9_32,9_44,9_43,9_40,15_16,15_14,15_10,15_11,15_13,20_0,1_237,9_48,9_47
DXCss: 0_2312,1_50,1_53,1_51,0_2317,1_40,1_17,0_2214,1_16,0_2219,0_2221,0_2225,1_18,1_4,0_2257,18_3,18_11,18_7,0_2261,0_2313,1_34,0_2273,16_3,16_11,16_7,0_2277,1_44,0_2192,24_359,24_364,24_360,1_20,9_12,9_15,0_2338,9_1,0_2342,9_4,1_7,15_0,15_4,/Content/Site.css,/Areas/Reports/Content/TurnkeyLiability.css
DXMVCEditorsValues: {"Save":true}
X-Requested-With: XMLHttpRequest

.Net properties are missing in the response got from AngularJs Ajax call to Asp.Net Web Api

I am making an ajax call using AngularJS $http to Asp.Net Web Api.
$http({
method: 'GET',
url: '/api/PatientCategoryApi/PatCat',
params: dataTemp,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).then(function successCallback(response) {
$scope.modelObject.resultData = response.data;
alert(JSON.stringify(response.data));
}, function errorCallback(response) {
$scope.modelObject.result = response;
});
The web api action has the following signature
public PaginatedList<PatientCategory> PatCat(PaginatedRequestCommand cmd){...}
The PaginatedList type is as follows.
public class PaginatedList<T> : List<T>
{
public int PageIndex { get; private set; }
public int PageSize { get; private set; }
public int TotalCount { get; private set; }
public int TotalPageCount { get; private set; }
public bool HasPreviousPage
{
get
{
return (PageIndex > 1);
}
}
public bool HasNextPage
{
get
{
return (PageIndex < TotalPageCount);
}
}
}
I have removed the ctor as its not required here. So its just a wrapper to a list of T and in this case T is PatientCategory.
I am able to access the list from the response object after the ajax call. But I am not able to find the properties of the PaginatedList such as
PageIndex, PageSize and so on in the response object. Even as I use fiddler, I can clearly see the array of PatientCategory objects but as the properties of the PaginatedList are missing.
[{"Id":1,"Code":"H05120000003","Name":"Regular","Description":"The Regular Patient Category","ModifiedTime":"2015-10-01T19:34:33.727","History":null,"MyXmlColumn":null},{"Id":2,"Code":"BH130000001","Name":"STAFF_CHGD_TO_REGULAR","Description":null,"ModifiedTime":"2015-10-01T19:46:07.093","History":null,"MyXmlColumn":null},{"Id":3,"Code":"BH130000001","Name":"STAFF_CHGD_TO_REGULAR","Description":null,"ModifiedTime":"2015-10-01T19:52:03.773","History":null,"MyXmlColumn":null}]
So how can I access those properties as well in the response?
The request and response that show up in Fiddler are as follows.
Request
GET http://localhost:50849/api/PatientCategoryApi/PatCat?Page=1&Take=3 HTTP/1.1
Host: localhost:50849
Connection: keep-alive
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36
Referer: http://localhost:50849/PatientCategory/Index
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Response
HTTP/1.1 200 OK
Content-Length: 479
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/8.0
X-SourceFiles: =?UTF-8?B?RDpcQlZIXEF2YmhIaXNcQXZiaEhpcy5XZWJcYXBpXFBhdGllbnRDYXRlZ29yeUFwaVxQYXRDYXQ=?=
X-Powered-By: ASP.NET
Date: Thu, 15 Oct 2015 01:43:57 GMT
[{"Id":1,"Code":"H05120000003","Name":"Regular","Description":"The Regular Patient Category","ModifiedTime":"2015-10-01T19:34:33.727","History":null,"MyXmlColumn":null},{"Id":2,"Code":"BH130000001","Name":"STAFF_CHGD_TO_REGULAR","Description":null,"ModifiedTime":"2015-10-01T19:46:07.093","History":null,"MyXmlColumn":null},{"Id":3,"Code":"BH130000001","Name":"STAFF_CHGD_TO_REGULAR","Description":null,"ModifiedTime":"2015-10-01T19:52:03.773","History":null,"MyXmlColumn":null}]
Asp.net web api use NewtonJson.dll to make a Javascript serialization. When newtonjson find a class implement IEnumerable, it will serialize this object to an Javascript object like this [{},{}], it seems newtonjson only serialize the IEnumebrable object, other properties are ignored. Also you can add the NewtonSoft.Json.JsonObject to the class PagenatedList, this attribute will tell newtonjson serialize the data to a javascript plain object like this {p1: "", p2: ""}, but you will find the IEnumebrable data lost. To solve this, you should custom a new CustomJsonConverter inherited from JsonConverter, and add the attribute to your PagenatedList like this:
[Newtonsoft.Json.JsonConverter(typeof(CustomJsonConverter))
public class PagenatedList<T>:List<T>
//your class code

WebApi 2.1 PUT throw error 415

I'm trying to update data using WebApi PUT method. My code working fine before, but suddenly I start to get this error.
"Message":"The request contains an entity body but no Content-Type header. The inferred media type 'application/octet-stream' is not supported for this resource.","ExceptionMessage":"No MediaTypeFormatter is available to read an object of type 'xEmployee' from content with media type 'application/octet-stream'.","ExceptionType":"System.Net.Http.UnsupportedMediaTypeException".
This is headers:
Response Header.
HTTP/1.1 415 Unsupported Media Type
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/7.5
Set-Cookie: Role=D65520F37D105E39C1A92C15CD482E378F32A769592AC7D8305285A5B9B90362F7F2F13F14E6DC220E44D26940B06B52E7460EF13184F245805AF9523D1072464F4BD06AFB4F8AEB8B7D8BF607A8922C6041A3A4C636BF3B26388E606A94FE43; expires=Tue, 07-Oct-2014 09:49:56 GMT; path=/
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Tue, 07 Oct 2014 09:19:56 GMT
Content-Length: 809
Request Header:
PUT /api/xemployees/2110481232 HTTP/1.1
Host: guideonline.ilvestour.office
Connection: keep-alive
Content-Length: 229
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://guideonline.ilvestour.office
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
Content-Type: application/json; charset=UTF-8"
Referer: http://guideonline.ilvestour.office/account
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: .ASPXAUTH=215C424A0A023F5B42775B7A73B08FEC8CB36E7200FBA430EADF2F300A84500571F8B5EE980C3EF2913FE160978973CDBC50BDD216E16FC342EF0B566D0944ECFD901DF471DEF9F6E5D272B52F2450CC0A1FB96BCC6B3B6E7A7C07343D4DFBD66; Role=DE678EE89D7089B8CD74B202E00C53CA9AE9E4C40B506C5C4EEF56E7962F38ED86F6BFD34E5FD3A6DD6ECCCF61AF768CAB0C1D7C5F15A8638F9454B24DF3208F021EB638235420574C6420CA5A19F0B6BD07BAC303FF79612D6C1AF246563A7
Request Payloadview source
{"Kod":2110481232, "Сотрудник": "Lena", "Telephon": "088-6734227", "Password":"rimosa57", "email":"samoylova-elena#mail.ru", "CrWho":"OMEGA.Administrator", "CrWhen":"2014-10-07T09:20:05.735Z"}
Nothing special in Controller code:
[Authorize(Roles = "Admin, User")]
public async Task<IHttpActionResult> PutxEmployee(int id, xEmployee xEmployee)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != xEmployee.Kod)
{
return BadRequest();
}
try
{
var user = db.xEmployee.Find(id);
user.Сотрудник = xEmployee.Сотрудник;
user.Telephon = xEmployee.Telephon;
user.Password = xEmployee.Password;
user.email = xEmployee.email;
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!xEmployeeExists(id))
{
return NotFound();
}
else
{
throw;
}
}
catch (DbEntityValidationException e)
{
foreach (var eve in e.EntityValidationErrors)
{
var path = "C:/error.txt";
using (StreamWriter sw = File.CreateText(path))
{
sw.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
eve.Entry.Entity.GetType().Name, eve.Entry.State);
}
using (StreamWriter sw1 = File.CreateText("C:/error1.txt"))
foreach (var ve in eve.ValidationErrors)
{
sw1.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
ve.PropertyName, ve.ErrorMessage);
}
}
throw;
}
return StatusCode(HttpStatusCode.NoContent);
}
Same as WebApiConfig:
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.Culture = new CultureInfo("ru-RU");
config.Formatters.Remove(config.Formatters.XmlFormatter);
}
There seems to be a typo (last ") in the request's Content-Type header:
Content-Type: application/json; charset=UTF-8"
When this header is missing or malformed, the server will automatically use application/octet-stream by default, as described by this post.
I were facing similar problem. Though i have a Content-Type declare it was still sending same error.
What I did is added Accept Header and it started working.
Accept: application/json
Content-Type: application/json
Also, make sure there's only one header Content-Type. In my case, my rest client was implicitly sending the empty Content-Type which got overridden by Content-Type: application/json hence the error.

Cannot redirect after HTTP headers have been sent MVC3

I am getting this error in an MVC3 application when using the RedirectPermanent(url) method on a base controller. Buffering the output, suggested by other StackOverflow answers, has had no effect.
protected void Application_BeginRequest(object sender, EventArgs e)
{
Context.Response.BufferOutput = true;
}
The redirect is triggered as the first action result on the default controller on this web site:
http://www.autoquoter.com
I don't have any code that directly adds a header. That being the case, is there any way to determine what is adding a response header?
Here is the network log from webkit's debugger for the first page of the web site.
Request URL:http://www.autoquoter.com/
Request Method:GET
Status Code:301 Moved Permanently
Request Headers
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent:Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2
Response Headers
Cache-Control:no-cache, no-store, must-revalidate
Content-Length:128
Content-Type:text/html; charset=utf-8
Date:Thu, 21 Mar 2013 17:10:38 GMT
Expires:-1
Location:/aq/en/Home
Pragma:no-cache
Server:Microsoft-IIS/6.0
X-AspNet-Version:4.0.30319
X-AspNetMvc-Version:3.0
X-Powered-By:ASP.NET
Looks like I have solved this. There was another redirect based upon host name buried inside of a NoCacheAttribute filter. This was setting properties on Response object in the OnResultExecuting method.
I renamed the method to OnActionExecuting so it would be triggered sooner, and replaced a manual redirect with a RedirectResult. I also now avoid updating the cache settings if I'm already redirecting.
Before:
if (currentHost != prefHost && filterContext.HttpContext.Response.StatusCode != 301)
{
var Url = filterContext.HttpContext.Request.Url.Scheme + "://" + prefHost + filterContext.HttpContext.Request.Url.PathAndQuery;
filterContext.HttpContext.Response.StatusCode = 301;
filterContext.HttpContext.Response.RedirectLocation = Url;
filterContext.HttpContext.Response.End();
return;
}
filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.SetNoStore();
After:
if (currentHost != prefHost && filterContext.HttpContext.Response.StatusCode != 301)
{
var Url = filterContext.HttpContext.Request.Url.Scheme + "://" + prefHost + filterContext.HttpContext.Request.Url.PathAndQuery;
filterContext.Result = new RedirectResult(Url, true);
disableCache = false;
}
if (disableCache)
{
filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.SetNoStore();
}
base.OnActionExecuting(filterContext);

Asp.Net WebApi OData with DataJs throws an error

I just created a really simple ASP.Net WebApi project. I used NuGet to download the latest OData in WebAPI – RC release. I also download DataJs and Knockout via NuGet. All my dependencies are up to date. I created a simple "Books" class and wired everything together using HttpConfiguration.EnableOData(IEdmModel). I also added the [Queryable] attribute to my Get action in the controller. There is not database involved, I hard-coded the data I want returned. Basically, I did the minimum amount of changes to run my project with WebApi and OData.
When I try to query the OData service using DataJs, I get a 500 Internal Server Error in the response, but if I browse to the URL directly I can see the XML data. I've included the request, response, my C# class, the Javascript code, and the Global.asax code. What am I missing to get this to work?
REQUEST
Response Headers
Cache-Control private
Content-Length 966
Content-Type application/json; odata=fullmetadata; charset=utf-8
DataServiceVersion 3.0;
Date Fri, 21 Dec 2012 22:13:27 GMT
Server Microsoft-IIS/8.0
X-AspNet-Version 4.0.30319
X-Powered-By ASP.NET
X-SourceFiles =?UTF-8?B?YzpcdXNlcnNcanVzdGluXGRvY3VtZW50c1x2aXN1YWwgc3R1ZGlvIDIwMTJcUHJvamVjdHNcRGF0YUpzU3Bpa2VcRGF0YUpzU3Bpa2VcYXBpXEJvb2tz?=
Request Headers
Accept application/atomsvc+xml;q=0.8, application/json;odata=fullmetadata;q=0.7, application/json;q=0.5, */*;q=0.1
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Connection keep-alive
Cookie glimpseState=null; glimpseLatestVersion=0.87; glimpseOptions=null; glimpseClientName=null
Host localhost:31652
MaxDataServiceVersion 3.0
Referer http://{localhost}/
User-Agent Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0
RESPONSE
{
"odata.error":{
"code":"","message":{
"lang":"en-US","value":"An error has occurred."
},"innererror":{
"message":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; odata=fullmetadata; charset=utf-8'.","type":"System.InvalidOperationException","stacktrace":"","internalexception":{
"message":"The related entity set could not be found. The related entity set is required to serialize the payload.","type":"System.Runtime.Serialization.SerializationException","stacktrace":" at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteObject(Object graph, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)\r\n at System.Web.Http.OData.Formatter.ODataMediaTypeFormatter.<>c__DisplayClass8.<WriteToStreamAsync>b__7()\r\n at System.Threading.Tasks.TaskHelpers.RunSynchronously(Action action, CancellationToken token)"
}
}
}
}
C# Class
namespace DataJsSpike.Models
{
public class Book
{
public string ISBN { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string Publisher { get; set; }
}
}
Javascript Code
// the URL of the first page to retrieve
var startPage = "api/Books";
var viewModel = new Object();
viewModel.books = ko.observable();
// On initialization, make a request for the first page
$(document).ready(function () {
LoadDataJs();
function LoadDataJs() {
OData.read(startPage, function (data) {
viewModel.books(data.results);
ko.applyBindings(viewModel);
});
}
});
Global.asax
public class WebApiApplication : HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
var modelBuilder = new ODataConventionModelBuilder();
EntityTypeConfiguration<Book> bookConfiguration = modelBuilder.Entity<Book>();
bookConfiguration.HasKey(x => x.ISBN);
modelBuilder.EntitySet<Book>("Books");
IEdmModel model = modelBuilder.GetEdmModel();
GlobalConfiguration.Configuration.EnableOData(model, "api");
}
}
EnableOData actually registers a route for you, but since you registered routes before it ran, those routes take precedence. If you remove this line:
RouteConfig.RegisterRoutes(RouteTable.Routes);
I think it should work out. The request needs to come in on an OData route for the OData formatting to work because the route parses the OData path and gives the formatter information about things like the Entity Set that's being accessed.

Resources