250116 ‐ Data null - cywongg/2025 GitHub Wiki
The issue in your code is likely due to the Task.Run(async () => await GetCorporateActions(from, to, prStocks)).Result
combined with the subsequent Where(ca => ca != null)
. The error message indicates that the source sequence (qDataPdi
) is null
at some point, despite your attempt to filter out null
values with Where(ca => ca != null)
.
Here’s a detailed explanation of the issue and how to handle it better:
-
Task.Run
with.Result
:- Using
Task.Run
in combination with.Result
is a blocking operation. It can lead to deadlocks or unintended behavior in situations where the synchronization context is involved (e.g., in UI frameworks like WPF or ASP.NET). - If
GetCorporateActions
throws an exception, the exception is wrapped in anAggregateException
byTask.Run
. This might not be handled properly in your code.
- Using
-
GetCorporateActions
might returnnull
:- If
GetCorporateActions
returnsnull
for any reason (e.g., network issues, empty data, or unhandled exceptions), then callingWhere
onnull
will throw aNullReferenceException
.
- If
-
Misleading Filtering Logic:
- Filtering with
Where(ca => ca != null)
assumes that the source collection (qDataPdi
) is non-null, but ifqDataPdi
itself isnull
, LINQ will still fail.
- Filtering with
-
Ensure
GetCorporateActions
Never Returns Null:- Modify
GetCorporateActions
to always return a non-null collection. If no results are found, ensure it returns an empty collection (new Collection<CorporateAction>()
) instead ofnull
.
private async Task<Collection<CorporateAction>> GetCorporateActions(DateTime from, DateTime to, Collection<string> eliotids) { try { Uri buildUri = _httpServiceUriBuilder .SetPath("corporate-actions") .SetParam("source", "BBG") .SetParam("exDateFrom", from.ToString("yyyy-MM-dd")) .SetParam("exDateTo", to.ToString("yyyy-MM-dd")) .BuildUri(); // Example call to fetch data (replace with actual implementation) Collection<CorporateAction> result = await FetchCorporateActionsFromApi(buildUri); // Ensure non-null result return result ?? new Collection<CorporateAction>(); } catch (Exception) { // Log and return empty collection in case of failure return new Collection<CorporateAction>(); } }
- Modify
-
Avoid Blocking Code:
- Instead of
Task.Run
combined with.Result
, useasync
andawait
throughout your code to avoid blocking calls. This ensures proper exception propagation and prevents deadlocks.
public async Task<Collection<CorporateAction>> GetActiveCorporateActions(DateTime from, DateTime to, Collection<string> prStocks) { Collection<CorporateAction> qDataPdi; try { qDataPdi = await GetCorporateActions(from, to, prStocks); // Filter out null items (if any) return qDataPdi.Where(ca => ca != null).ToList(); } catch (Exception e) { Elastic.addError("Error occurred when getting CA from qData: " + e.Message, e.StackTrace); return new List<CorporateAction>(); } }
- Instead of
-
Handle Null Collection Safely in LINQ:
- Before applying LINQ operations like
Where
, ensure the collection is notnull
. Use null-coalescing operators (??
) or conditional checks.
qDataPdi = (await GetCorporateActions(from, to, prStocks)) ?? new Collection<CorporateAction>(); return qDataPdi.Where(ca => ca != null).ToList();
- Before applying LINQ operations like
-
Improve Logging:
- Log the exception details clearly to understand the root cause. Include inner exceptions when dealing with
AggregateException
.
catch (Exception e) { Elastic.addError("Error occurred when getting CA from qData: " + e.Message, e.ToString()); return new List<CorporateAction>(); }
- Log the exception details clearly to understand the root cause. Include inner exceptions when dealing with
Here’s the refactored version of your code:
public async Task<Collection<CorporateAction>> GetActiveCorporateActions(DateTime from, DateTime to, Collection<string> prStocks)
{
try
{
// Fetch data and ensure non-null result
var qDataPdi = (await GetCorporateActions(from, to, prStocks)) ?? new Collection<CorporateAction>();
// Filter out null items
return qDataPdi.Where(ca => ca != null).ToList();
}
catch (Exception e)
{
// Log the error and return an empty collection
Elastic.addError("Error occurred when getting CA from qData: " + e.Message, e.ToString());
return new List<CorporateAction>();
}
}
private async Task<Collection<CorporateAction>> GetCorporateActions(DateTime from, DateTime to, Collection<string> eliotids)
{
try
{
Uri buildUri = _httpServiceUriBuilder
.SetPath("corporate-actions")
.SetParam("source", "BBG")
.SetParam("exDateFrom", from.ToString("yyyy-MM-dd"))
.SetParam("exDateTo", to.ToString("yyyy-MM-dd"))
.BuildUri();
// Example call to fetch data (replace with actual implementation)
Collection<CorporateAction> result = await FetchCorporateActionsFromApi(buildUri);
// Ensure non-null result
return result ?? new Collection<CorporateAction>();
}
catch (Exception)
{
// Log and return empty collection in case of failure
return new Collection<CorporateAction>();
}
}
-
Avoid Blocking Calls:
- Use
async/await
instead ofTask.Run
+.Result
.
- Use
-
Handle Null Safely:
- Ensure
GetCorporateActions
never returnsnull
. - Use null-coalescing (
??
) to handle unexpected null values.
- Ensure
-
Better Logging:
- Log exceptions with full details to aid debugging.
-
Null-Filtering:
- Apply
Where(ca => ca != null)
only after ensuring the source collection is notnull
.
- Apply
This approach ensures robust error handling and avoids common pitfalls like deadlocks and null reference exceptions.