WPF CosmosDB ReadNextAsync() hangs when is calling in background_worker - wpf

In WPF I have background_worker and in it I have to make request to Cosmos DB, request that use iterator:
_worker_GenerateReport.DoWork += _worker_GenerateReport_DoWork;
This is method for backgroundWorker:
void _worker_GenerateReport_DoWork(object sender, DoWorkEventArgs e)
var result = QueryItemsAsync2(connectionString, queryToDownloadData.ToString());
And method. In this method on GetAwaiter().GetResult(); it hangs:
private async Task<IEnumerable<DTO_Proj>> QueryItemsAsync2(
ConnectionString connectionString, string sqlQueryText)
{
QueryDefinition queryDefinition = new QueryDefinition(sqlQueryText);
var container = cosmosClient.GetContainer(connectionString.DatabaseID,
connectionString.Collection);
FeedIterator<DTO_Proj> resultSet =
container.GetItemQueryIterator<DTO_Proj>(queryDefinition,
requestOptions: new QueryRequestOptions()
{
//MaxItemCount = 1000,
MaxConcurrency = 1
});
while (resultSet.HasMoreResults)
{
Task<FeedResponse<DTO_Proj>> response = resultSet.ReadNextAsync();
var result = response.GetAwaiter().GetResult();
}
}
I have to write once again. I removed BackgroundWorker and I see that the problem is with fetching items from CosmosDB.
Now I have in xaml button:
<Button VerticalAlignment="Bottom" Grid.Row="1" HorizontalAlignment="Left" Command="{Binding Path=Command_GenerateReport2}" IsEnabled="{Binding Path=IsUIEnabled, UpdateSourceTrigger=PropertyChanged}">report2</Button>
in MVVM command is created as follow:
Command_GenerateReport2 = new MVVM.RelayCommand(p => Can_GenerateReport(), a => generateReport2());
Method generateReport2:
private void generateReport2()
{
ConnectionString connectionString = CreateConnectionStringAzureDB(serverToUse);
string queryTest = " SELECT * FROM c WHERE c.Proj = 2544912 ";
var result = QueryItemsAsync2(connectionString, queryTest);
}
And method QueryItemsAsync2:
private async Task<IEnumerable<DTO_Proj>> QueryItemsAsync2(ConnectionString connectionString, string sqlQueryText)
{
QueryDefinition queryDefinition = new QueryDefinition(sqlQueryText);
var container = cosmosClient.GetContainer(connectionString.DatabaseID, connectionString.Collection);
FeedIterator<DTO_Proj> resultSet = container.GetItemQueryIterator<DTO_Proj>(
queryDefinition,
requestOptions: new QueryRequestOptions()
{
MaxItemCount = 1000,
MaxConcurrency = 1
});
while (resultSet.HasMoreResults)
{
Task<FeedResponse<DTO_Proj>> response = resultSet.ReadNextAsync();
response.Wait();
...
And I have two CosmosDB containers. On one of them resultSet.ReadNextAsync() works and on the second hangs on this line. Configuration of these containers I think is the same. The difference is that on one container there is a lot of data and application hangs on it, on the second works but there is little data.

You should read the items asynchronously and not block by calling GetAwaiter().GetResult():
while (resultSet.HasMoreResults)
{
var item = await resultSet.ReadNextAsync();
...
}
Then you don't need to use a BackgroundWorker or involve any background threads. You could simply call and await the asynchronous QueryItemsAsync2 method:
var result = await QueryItemsAsync2(connectionString, queryToDownloadData.ToString());

Related

ABP framework / parallel programming

I have one AsyncPeriodicBackgroundWorkerBase base class(DataValidateWorker) which runs 1 minute interval.
I need to send the data I get from the DB to a third party web service and update the results in the db. A Web service response arrives in about 30-40 seconds. For this reason, I need to send Web service queries simultaneously, not sequentially.
For this reason, I wrote code in accordance with parallel programming as seen below. I cannot pull the database connection for the Task I wrote. DB connection closed, I got many errors like Executing.
How can I create the db connection for my Task?
Would it be better to write this job in an external application (exe or service) instead of ABP?
public class DataValidateWorker : AsyncPeriodicBackgroundWorkerBase
{
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly IDataFilter _dataFilter;
public DataValidateWorker(AbpAsyncTimer timer, IServiceScopeFactory serviceScopeFactory, IDataFilter dataFilter, IUnitOfWorkManager unitOfWorkManager) : base(timer, serviceScopeFactory)
{
_dataFilter = dataFilter;
_unitOfWorkManager = unitOfWorkManager;
Timer.Period = 60 * 1000; // 60 seconds
}
[UnitOfWork]
protected async override Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext)
{
try
{
var notificationValidationRepository = workerContext.ServiceProvider.GetRequiredService<IRepository<NotificationValidation, int>>();
var notificationValidationItems = await notificationValidationRepository.GetQueryableAsync();
List<NotificationValidation> list = new List<NotificationValidation>();
using (var uow = _unitOfWorkManager.Begin())
{
using (_dataFilter.Disable<IMultiTenant>())
{
list = notificationValidationItems.Where(x => x.RecordDateTime <= DateTime.Now && x.ValidationResult == (int)ValidationResult.NotStarted).ToList();
}
}
NotificationValidationArgs jobArgs = new NotificationValidationArgs();
foreach (var item in list)
{
jobArgs.notificationValidationId = item.Id;
Task taskA = Task.Factory.StartNew(async (Object obj) =>
{
// doing some third party web service operations and db operations
}, jobArgs);
}
}
catch (Exception ex)
{
Logger.LogCritical(2001, ex, DateTime.Now.ToString() + " -> DataValidateWorker -> try 1 -> RDMS uow");
}
}
}
You don't await any of tasks, so lifetime of object ends while your task is still running.
Try to store all of the tasks in a collection and await them before method execution finishes.
Something like below:
public class DataValidateWorker : AsyncPeriodicBackgroundWorkerBase
{
public DataValidateWorker(AbpAsyncTimer timer, IServiceScopeFactory serviceScopeFactory) : base(timer, serviceScopeFactory)
{
}
protected override async Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext)
{
var tasks = new List<Task>();
foreach (var item in list)
{
tasks.Add(YourLongJob(arg)); // don't await here. collect in a collection
}
await Task.WhenAll(tasks); // wait until all of them is completed.
}
private async Task YourLongJob(object arg)
{
await Task.Delay(30 * 1000); // a long job
}
}

MongoDB Compass returns all rows when I run a filter

I am trying to run a filter in MongoDB Compass and it returns all rows instead of the row that I am looking for. I can run the filter on example databases that are similar to my database without any problem.
https://i.stack.imgur.com/IBivJ.png
Here is the code that I am using to add records and select from them.
public class NoSQLDataAccess
{
// Create an instance of data factory
public NoSQLDataFactory noSQLDataFactory;
public List<dynamic> DocumentDetails { get; set; }
private IMongoCollection<dynamic> collection;
private BsonDocument bsonDocument = new BsonDocument();
public NoSQLDataAccess() { }
public void TestNoSQL()
{
MongoClient client;
IMongoDatabase database;
string connectionString = ConfigurationManager.AppSettings["NoSQLConnectionString"];
client = new MongoClient(connectionString);
database = client.GetDatabase("TestDatabase");
collection = database.GetCollection<dynamic>("TestCollection");
// Insert
List<Layer> layers = new List<Layer>();
layers.Add(new Layer { LayerId = 117368, Description = "BOOTHLAYER" });
layers.Add(new Layer { LayerId = 117369, Description = "DRAWINGLAYER" });
layers.Add(new Layer { LayerId = 117370, Description = "LAYER3" });
List<Element> elements = new List<Element>();
elements.Add(new Element { ElementId = 9250122, Type = "polyline" });
elements.Add(new Element { ElementId = 9250123, Type = "polyline" });
List<dynamic> documentDetails = new List<dynamic>();
documentDetails.Add(new DrawingDTO { Layers = layers, Elements = elements });
collection.InsertMany(documentDetails);
List<FilterDetails> filterDetails = new List<FilterDetails>();
filterDetails.Add(new FilterDetails { Type = "layers.id", Value = "117368" });
foreach (FilterDetails detail in filterDetails)
{
bsonDocument.Add(new BsonElement(detail.Type, detail.Value));
}
List<dynamic> results = collection.Find(bsonDocument.ToBsonDocument()).ToList();
}
}
I have been able to get the result I need with MongoDB shell but I have not been able to replicate the results in C#.
Here is the solution in MongoDB shell:
db.TestCollection.find({"layers.id": 117368}, {_id:0, layers: {$elemMatch: {id: 117368}}}).pretty();
I have found a post that is similar to my question that works for them. The C# code that I attached is how I will access it after I get it working properly. I use MongoDB Compass to test finds/inserts/updates/deletes.
Retrieve only the queried element in an object array in MongoDB collection

NancyFX on Krestrel - Response Stream Closed

I'm attempting it make a simple proxy server that will try to stream back data from an IP camera (the IP camera doesn't honor OPTIONS and has some other issues!). I tried doing this using NancyFX and Krestrel with the following proxy module. The idea was to just get 1028 bytes of data in and write it to the output stream asynchronously until canceled.
Here is a sample Nancy Module:
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using Nancy;
namespace Server.Modules
{
public class Proxy : NancyModule
{
public Proxy() : base("api/proxy")
{
Get("/", ProxyPage);
}
private async Task<Response> ProxyPage(dynamic args, CancellationToken cancellationToken)
{
// Create HttpClient
using (var httpClient = new HttpClient()) // Make this global/cached and indexed by auth code
{
// Handle Authentication
var auth = string.Empty;
if (!string.IsNullOrEmpty(Request.Headers.Authorization) && Request.Headers.Authorization.Contains(" "))
auth = Request.Headers.Authorization.Split(' ')[1];
else if (!string.IsNullOrEmpty(Request.Query.authorization))
auth = Request.Query.authorization;
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", auth);
// Create Proxy REsponse object
var proxyResponse = new Response();
// Get Async
HttpResponseMessage response = await httpClient.GetAsync(Request.Query["url"],
HttpCompletionOption.ResponseHeadersRead, cancellationToken);
// Set Content Type
proxyResponse.ContentType = response.Content.Headers.ContentType.ToString();
// Set Status Code
proxyResponse.StatusCode = (HttpStatusCode)(int)response.StatusCode;
// Handle stream writing
proxyResponse.Contents = async s =>
{
var result = response.Content.ReadAsStreamAsync();
var data = new byte[1028];
int bytesRead;
while (!cancellationToken.IsCancellationRequested && (bytesRead = await result.Result.ReadAsync(data, 0, data.Length, cancellationToken)) > 0)
{
await s.WriteAsync(data, 0, bytesRead, cancellationToken);
await s.FlushAsync(cancellationToken);
}
response.Dispose();
};
// Return Response container
return proxyResponse;
}
}
}
}
When I run it, I get through the while loop a couple times but then get an exception in FrameResponseStream (Krestrel): "System.ObjectDisposedException: 'Cannot access a disposed object.'" It appears that the stream is being closed (_state = FrameStreamState.Closed -- https://github.com/aspnet/KestrelHttpServer/blob/rel/2.0.0/src/Microsoft.AspNetCore.Server.Kestrel.Core/Internal/Http/FrameResponseStream.cs) prematurely but I cannot figure out why or what I need to change to resolve it!
You should use ResponseContentRead instead of ResponseHeadersRead
HttpResponseMessage response = await httpClient.GetAsync(Request.Query["url"],
HttpCompletionOption.ResponseContentRead, cancellationToken);

Web API 2, return string as a file

I have a Web API 2 POST endpoint which takes a parameter, queries the database and returns an xml string as the response.
public async Task<IHttpActionResult> Post(long groupId)
{
People people = await _someService.GetPeople(groupId);
XElement peopleXml = _xmlService.ConverToXml(people);
return Ok(peopleXml);
}
How do I to return the xml as a file instead?
Figured it out myself, but I hope there is a simpler way -
public async Task<IHttpActionResult> Post(long groupId)
{
People people = await _someService.GetPeople(groupId);
XElement peopleXml = _xmlService.ConverToXml(people);
byte[] toBytes = Encoding.Unicode.GetBytes(peopleXml.ToString());
var stream = new MemoryStream(toBytes);
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(stream)
};
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = "test.txt"
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
var response = ResponseMessage(result);
return response;
}

OptionSetValue does not contain constructor which takes one argument

I am creating a silverlight application as a web resource for CRM 2011. Now i am creating a ServiceAppointment record in DB and after creating it i want to change its Status to "reserved" instead of requested.
I googled about this and come across the examples like Close a Service Activity Through Code and Microsoft.Crm.Sdk.Messages.SetStateRequest
They all suggesting to use "SetStateRequest" and for using this i have to set the OptionSetValue like
request["State"] = new OptionSetValue(4);
But above line gives me error saying "OptionSetValue does not contain constructor which takes one argument"
BTW i am using SOAP end point of CRM 2011 service in silverlight application
Any ideas friends?
EDIT
Following is my code
var request = new OrganizationRequest { RequestName = "SetStateRequest" };
request["State"] = 3;
request["Status"] = 4;
request["EntityMoniker"] = new EntityReference() { Id = createdActivityId, LogicalName = "serviceappointment" };
crmService.BeginExecute(request,ChangeActivityStatusCallback,crmService);
And my callback function is
private void ChangeActivityStatusCallback(IAsyncResult result) {
OrganizationResponse response;
try
{
response = ((IOrganizationService)result.AsyncState).EndExecute(result);
}
catch (Exception ex)
{
_syncContext.Send(ShowError, ex);
return;
}
}
You must some how be referencing some other OptionSetValue class that is not the Microsoft.Xrm.Sdk one. Try appending the namespace to see if that resolves your issue:
request["State"] = new Microsoft.Xrm.Sdk.OptionSetValue(4);
Also, why are you using late bound on the SetStateRequest? Just use the SetStateRequest class:
public static Microsoft.Crm.Sdk.Messages.SetStateResponse SetState(this IOrganizationService service,
Entity entity, int state, int? status)
{
var setStateReq = new Microsoft.Crm.Sdk.Messages.SetStateRequest();
setStateReq.EntityMoniker = entity.ToEntityReference();
setStateReq.State = new OptionSetValue(state);
setStateReq.Status = new OptionSetValue(status ?? -1);
return (Microsoft.Crm.Sdk.Messages.SetStateResponse)service.Execute(setStateReq);
}
Thanks Daryl for you time and effort. I have solved my problem with the way u have suggested.
I am posting my code that worked for me.
var request = new OrganizationRequest { RequestName = "SetState" };
request["State"] = new OptionSetValue { Value = 3 };
request["Status"] = new OptionSetValue { Value = 4 };
request["EntityMoniker"] = new EntityReference() { Id = createdActivityId, LogicalName = "serviceappointment" };
crmService.BeginExecute(request,ChangeActivityStatusCallback,crmService);
private void ChangeActivityStatusCallback(IAsyncResult result) {
OrganizationResponse response;
try
{
response = ((IOrganizationService)result.AsyncState).EndExecute(result);
}
catch (Exception ex)
{
_syncContext.Send(ShowError, ex);
return;
}
}

Resources