Reputation: 38683
I have spent couple of weeks for this issue. but still I can't resolve this issue.
i am calling a web API service by using http
in angularjs
$http({
method: 'GET',
url: rootUrl + '/api/Project/ProjectList',
headers: {
'Content-Type': "application/json; charset=utf-8"
}
}).success(function (response) {
$scope.ProjectList = response;
}).error(function (response, errorCode) {
if (errorCode == 444) {
}
})
I have put break point in server and client side coding.
When i call the service, the server side method hit quickly
My server side method (am Using MVC WEB API with entity framework)
[ActionName("ProjectList")]
[HttpGet]
public IList<Project> ProjectList(Project projectModel)
{
return objIProjectService.ListOfProject();
}
I checked, the service return 8 records( 8 rows from database) with a break point in objIProjectService.ListOfProject();
this line.
everything is going good. But my (response) http.success and http.error
call back functions are hitting very slow.
Please see below image for the performance while i calling the http
methods
Finally the http error function
hit after 5 or 10 mins with this below error message.
System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown
This is the problem. Please let me know how can i solve it?
Actually am did something for this issue.
sql server 2008 r2
), then it's working. For example, if my database table have below than 7 rows, then it's working fast without that error. But if my table have more than 8 rows, then it's working very slowly and threw the error?? Why?? re could you please share your solution if you stuck this issue.
Upvotes: 21
Views: 16741
Reputation: 733
Going further with Chris Warnes suggestion and describing the possible reason.
Let me guess... you use entity framework with lazy loading enabled. So during serialization every navigational property you have is loading data lazily and recursively sometimes. For instance: Project
contains Worker
which contains reference to same Project
in some navigational property such as WorkerProjects
.
Serializer tries to make sense out of it, but it cannot, without some hint.
the easiest way to check what is going on, is to disable entity framework lazy loading and get that breakpoint there, right after ToList()
and just before the return
.
BTW. Serializing this kind of structure to JSON is - kind of - impossible. You need to have external mechanism (such as cycle.js is using XPath to encode such a reference) to deal with duplicated references and cycles.
Upvotes: 0
Reputation: 97
The HTTP specification doesn't impose a specific size limit for posts. The problem with GET queries is that the parameters are embedded in the URL, which is limited in size (this limit is browser and server dependent). Don't use a GET query for big data use a POST one.
there is another topic If you are using MVC and you working on big data, you need to use this one.
<appSettings>
<add key="aspnet:MaxJsonDeserializerMembers" value="150000" />
</appSettings>
or
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="1000000" />
</requestFiltering>
</security>
from : MSDN
I hope these will solve your problem.
Upvotes: 0
Reputation: 10927
The issue here is that the serializing of the information is taking to much time. You are accessing all the related classes of your project class, which may cause a significant damage when dealing with memory aspects.
you can resolve this in two ways:
One is to return your promises and then fetch the data:
return $http({
method: 'GET',
url: rootUrl + '/api/Project/ProjectList',
headers: {
'Content-Type': "application/json; charset=utf-8"
}
}).then(function (response) {
A second option will be in the code, using Entity framework or linq queries.
Use select queries to lower the burden on the server side and client side as follow:
var projectsQuery = from p in ProjectModel as pm where pm.Id = p.Id select p.SomeValue
return projectsQuery
this way you will be able to lower the burden of the data serializing and might possibly avoid the outOfMemoryExcexption.
There is no need in opening the Sql Profiler here since the data from the server side comes at a reasonable time.
Upvotes: 0
Reputation: 404
Open Sql Server Profiller and watch EF generated sql queries and results. And then try execute on sql window this raw queries. Probably you'ill understand after this.
Upvotes: 3
Reputation: 728
I think the problem is that the serialiser is accessing all the related properties on your project Class, so rather than directly returning the Entity Framework Class, create a new class to represent the data that you wish to send through your api (research further into DTO classes for further information)
You can use the Select
Linq method to get a list of your new dto class populated with the data from your EF call.
var projects = objIProjectService.ListOfProject();
return projects.Select(p => new ProjectDTO() {
ID = p.Id
//... other properties of DTO class
}).ToList();
even better, if you put this select method, into your EF query (i.e. context.projects.Select(/* select info here */).ToList()
, you can make sure EF is only bringing back the fields that you need
when building an API always check the json/XML response, make sure the serialised data contains what you were expecting it to produce. with entity framework this response can end up huge as it navigates through all the related tables pulling out all the linked information and then attempting to serialise it.
as a personal preference I always prefer to return an IHttpActionResult
it allows you to manage what is being sent back to the client especially when there are issues, the controller has a number of methods you can use to createthis i.e. OK(), BadRequest(), InternalServerError()
...
Upvotes: 12