Vấn đề của bạn là bạn đang chạy một truy vấn Oracle trả về một số lượng rất lớn kết quả, sau đó tải toàn bộ kết quả đó vào bộ nhớ trước khi tuần tự hóa nó ra HttpResponseMessage
.
Để giảm mức sử dụng bộ nhớ, bạn nên tìm và loại bỏ tất cả các trường hợp trong đó toàn bộ tập hợp kết quả từ truy vấn được tải vào một biểu diễn trung gian tạm thời (ví dụ:một DataTable
hoặc chuỗi JSON), và thay vào đó, truyền dữ liệu ra ngoài bằng DataReader
. Điều này tránh kéo mọi thứ vào bộ nhớ cùng một lúc theo câu trả lời này
.
Đầu tiên, từ theo dõi của bạn, có vẻ như bạn có Bật liên kết trình duyệt
đã kiểm tra. Vì điều này dường như cố gắng lưu vào bộ nhớ cache toàn bộ phản hồi trong một MemoryStream
, bạn sẽ muốn tắt nó như được giải thích trong FilePathResult ném OutOfMemoryException với tệp lớn
.
Tiếp theo, bạn có thể phát trực tuyến nội dung của IDataReader
trực tiếp sang JSON bằng Json.NET với lớp và trình chuyển đổi sau:
[JsonConverter(typeof(OracleDataTableJsonResponseConverter))]
public sealed class OracleDataTableJsonResponse
{
public string ConnectionString { get; private set; }
public string QueryString { get; private set; }
public OracleParameter[] Parameters { get; private set; }
public OracleDataTableJsonResponse(string connStr, string strQuery, OracleParameter[] prms)
{
this.ConnectionString = connStr;
this.QueryString = strQuery;
this.Parameters = prms;
}
}
class OracleDataTableJsonResponseConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(OracleDataTableJsonResponse);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException("OracleDataTableJsonResponse is only for writing JSON. To read, deserialize into a DataTable");
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var response = (OracleDataTableJsonResponse)value;
using (var dbconn = new OracleConnection(response.ConnectionString))
{
dbconn.Open();
using (var selectCommand = new OracleCommand(response.QueryString, dbconn))
{
if (response.Parameters != null)
selectCommand.Parameters.AddRange(response.Parameters);
using (var reader = selectCommand.ExecuteReader())
{
writer.WriteDataTable(reader, serializer);
}
}
}
}
}
public static class JsonExtensions
{
public static void WriteDataTable(this JsonWriter writer, IDataReader reader, JsonSerializer serializer)
{
if (writer == null || reader == null || serializer == null)
throw new ArgumentNullException();
writer.WriteStartArray();
while (reader.Read())
{
writer.WriteStartObject();
for (int i = 0; i < reader.FieldCount; i++)
{
writer.WritePropertyName(reader.GetName(i));
serializer.Serialize(writer, reader[i]);
}
writer.WriteEndObject();
}
writer.WriteEndArray();
}
}
Sau đó, sửa đổi mã của bạn để trông giống như sau:
public HttpResponseMessage Getdetails([FromUri] string[] id)
{
var prms = new List<OracleParameter>();
var connStr = ConfigurationManager.ConnectionStrings["PDataConnection"].ConnectionString;
var inconditions = id.Distinct().ToArray();
var strQuery = @"SELECT
STCD_PRIO_CATEGORY_DESCR.DESCR AS CATEGORY,
STCD_PRIO_CATEGORY_DESCR.SESSION_NUM AS SESSION_NUMBER,
Trunc(STCD_PRIO_CATEGORY_DESCR.START_DATE) AS SESSION_START_DATE,
STCD_PRIO_CATEGORY_DESCR.START_DATE AS SESSION_START_TIME ,
Trunc(STCD_PRIO_CATEGORY_DESCR.END_DATE) AS SESSION_END_DATE,
FROM
STCD_PRIO_CATEGORY_DESCR,
WHERE
STCD_PRIO_CATEGORY_DESCR.STD_REF IN(";
var sb = new StringBuilder(strQuery);
for (int x = 0; x < inconditions.Length; x++)
{
sb.Append(":p" + x + ",");
var p = new OracleParameter(":p" + x, OracleDbType.NVarchar2);
p.Value = inconditions[x];
prms.Add(p);
}
if (sb.Length > 0)// Should this be inconditions.Length > 0 ?
sb.Length--;
strQuery = sb.Append(")").ToString();
var returnObject = new { data = new OracleDataTableJsonResponse(connStr, strQuery, prms.ToArray()) };
var response = Request.CreateResponse(HttpStatusCode.OK, returnObject, MediaTypeHeaderValue.Parse("application/json"));
ContentDispositionHeaderValue contentDisposition = null;
if (ContentDispositionHeaderValue.TryParse("inline; filename=ProvantisStudyData.json", out contentDisposition))
{
response.Content.Headers.ContentDisposition = contentDisposition;
}
return response;
}
Điều này tránh DataSet
trong bộ nhớ biểu diễn kết quả.
Tình cờ, tôi nghĩ ra dòng
if (sb.Length > 0)
sb.Length--;
thay vào đó phải là:
if (inconditions.Length > 0)
sb.Length--;
Tôi tin rằng bạn đang cố gắng loại bỏ dấu phẩy ở cuối trong truy vấn, dấu phẩy này sẽ xuất hiện nếu và chỉ khi inconditions.Length > 0
Xin lưu ý - Tôi không phải là nhà phát triển Oracle và tôi chưa cài đặt Oracle. Để thử nghiệm, tôi đã mô phỏng OracleClient
các lớp sử dụng OleDbConnection
bên dưới và nó hoạt động tốt.