I am trying to perform unit tests of a client that returns a task with a list of elements and iterates them, but what I have tried is not working for me.
IEnumerable<ExpenseNote> pendingExpenses = null;
try
{
pendingExpenses = await _expenseNoteService.GetPendingExpenseNotes().ConfigureAwait(false);
}
catch (Exception ex)
{
executionContext.Error($"Step 1-Final: Error when call \"getPendingExpenses()\". Detail: {ex.Message}", true);
throw;
}
if (!pendingExpenses.Any())
{
executionContext.Checkpoint("Step 1-Final: There are not pending expenses");
return;
}
int numApproveExpenses = 0;
executionContext.Checkpoint($"Step 2: Processing {pendingExpenses.Count()} pending expenses");
foreach (var expenseNote in pendingExpenses)
{
if (expenseNote.IsApprovable)
{
try
{
await _workflowsRRHHProxy.Approve(expenseNote.Id.ToString());
executionContext.Checkpoint($"Step 2.1: Expense with number {expenseNote.Number} has been approved ");
numApproveExpenses++;
}
catch (Exception ex)
{
executionContext.Error($"Step 2.1: Error when call \"Approve()\" with id: {expenseNote.Id} " +
$". Detail: {ex.Message}", false);
throw;
}
}
}
test example:
// ARRANGE
var mockExpenseNote = _mockFactory.CreateMock<DomainEntities.ExpenseNote>();
mockExpenseNote.Expects.One.Method(x => x.IsApprovable).WillReturn(true);
var expenseNote = mockExpenseNote.MockObject;
expenseNote.Id = Guid.NewGuid();
expenseNote.Number = "EX-APPROVE";
var expenseNotes = new List<DomainEntities.ExpenseNote>
{
expenseNote
};
Task<IEnumerable<DomainEntities.ExpenseNote>> task = Task.FromResult<IEnumerable<DomainEntities.ExpenseNote>>(expenseNotes);
var executionContext = _mockFactory.CreateMock<ITaskExecutionContext>();
executionContext.Expects.Between(1, 100).Method(method => method.Checkpoint("")).WithAnyArguments();
_expenseNoteService.Expects.One.Method(method => method.GetPendingExpenseNotes())
.WithAnyArguments()
.WillReturn(task);
var sut = GetServiceUnderTest();
// ACT
await sut.ProcessPendingExpenseNotes(executionContext.MockObject);
// ASSERT
_mockFactory.VerifyAllExpectationsHaveBeenMet();
but when i execute this test in " .WillReturn(task);" have this error:
System.InvalidCastException: Cannot cast object of type 'System.Linq.Expressions.PropertyExpression' to type 'System.Linq.Expressions.MethodCallExpression'..
Can Anyone Help me?
With mockExpenseNote.Expects.One.Method(x => x.IsApprovable).WillReturn(true); your lambda uses a property but you used the .Method() method so it expects you to use a method here (or call something else than .Method()).
Related
I'm trying to do BLE implementation in Xamarin forms. So I am able to connect and do write operation successfully but when I do read operation the app crashes. The read operation works in code behind that is xaml.cs but it crashes in viewmodel. This is exception I'm getting
Assertion at
/Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mono/mini/debugger-agent.c:4660,
condition is_ok (error)' not met, function:get_this_async_id, Could not execute the method because the containing type 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder1[TReturn_REF]',
is not fully instantiated. assembly: type: member:(null) [libc] Fatal signal 6 (SIGABRT), code -1
(SI_QUEUE) in tid 24845 (twell.touchless), pid 24845 (twell.touchless)
This is my code in viewmodel
private async Task<string> ProcessDeviceInformationService(IService deviceInfoService)
{
try
{
await adapter.ConnectToDeviceAsync(device);
var sb = new StringBuilder("Getting information from Device Information service: \n");
var characteristics = await deviceInfoService.GetCharacteristicsAsync();
var characteristic = await deviceInfoService.GetCharacteristicAsync(Guid.Parse("00002A39-0000-1000-8000-00805F9B34FB"));
// characteristic.CanWrite = true;
//foreach (var characteristic in characteristics)
//{
try
{
if (Device.RuntimePlatform==Device.iOS)
{
characteresticnativedata = DependencyService.Get<ICharacteristiciOS>();
characteresticnativedata.OpeniosBluetooth(device);
}
if (characteristic != null)
{
var sbnew = new StringBuilder("BLE Characteristics\n");
byte[] senddata = Encoding.UTF8.GetBytes(string.IsNullOrEmpty(SendMessageLabel.Text) ? "0ab" : SendMessageLabel.Text);
if (MainThread.IsMainThread)
{
var newbytes = await characteristic.WriteAsync(senddata);
}
var charvalue = Characteristic.Value;
var bytes = await characteristic.ReadAsync();
string str = Encoding.UTF8.GetString(charvalue);
sbnew.AppendLine($"Characteristics found on this device: {string.Join(", ", str.ToString())}");
CharactericsLabel.Text = sbnew.ToString();
}
}
catch (Exception ex)
{
return ex.Message;
}
return CharactericsLabel.Text;
}
catch (Exception ex)
{
return ex.ToString();
}
}
This same code var bytes = await characteristic.ReadAsync(); works in xaml.cs but it crashes in viewmodel. I even used GetAwaiter().GetResult() instead of await. But still it crashes.
var bytes = characteristic.ReadAsync.GetAwaiter().GetResult();
I have no clue how to fix this any suggestions?
I need to trigger some computation on an IotEdge module from an Administration-Backend Application.
On https://learn.microsoft.com/en-us/azure/iot-edge/module-development it says
Currently, a module cannot receive cloud-to-device messages
So it seems that calling direct methods seems to be the way to go. How can I implement a direct method and trigger it from within a .NET Core App?
In Main or Init Method of your IotEdge module you have to create a ModuleClient and connect it to a MethodHandler:
AmqpTransportSettings amqpSetting = new AmqpTransportSettings(TransportType.Amqp_Tcp_Only);
ITransportSettings[] settings = { amqpSetting };
ModuleClient ioTHubModuleClient = await ModuleClient.CreateFromEnvironmentAsync(settings);
await ioTHubModuleClient.OpenAsync();
await ioTHubModuleClient.SetMethodHandlerAsync("MyDirectMethodName", MyDirectMethodHandler, null);
Then you have to add the DirectMethodHandler to your IotEge module:
static async Task<MethodResponse> MyDirectMethodHandler(MethodRequest methodRequest, object userContext)
{
Console.WriteLine($"My direct method has been called!");
var payload = methodRequest.DataAsJson;
Console.WriteLine($"Payload: {payload}");
try
{
// perform your computation using the payload
}
catch (Exception e)
{
Console.WriteLine($"Computation failed! Error: {e.Message}");
return new MethodResponse(Encoding.UTF8.GetBytes("{\"errormessage\": \"" + e.Message + "\"}"), 500);
}
Console.WriteLine($"Computation successfull.");
return new MethodResponse(Encoding.UTF8.GetBytes("{\"status\": \"ok\"}"), 200);
}
From within your .Net core Application you can then trigger the direct method like this:
var iotHubConnectionString = "MyIotHubConnectionString";
var deviceId = "MyDeviceId";
var moduleId = "MyModuleId";
var methodName = "MyDirectMethodName";
var payload = "MyJsonPayloadString";
var cloudToDeviceMethod = new CloudToDeviceMethod(methodName, TimeSpan.FromSeconds(10));
cloudToDeviceMethod.SetPayloadJson(payload);
ServiceClient serviceClient = ServiceClient.CreateFromConnectionString(iotHubConnectionString);
try
{
var methodResult = await serviceClient.InvokeDeviceMethodAsync(deviceId, moduleId, cloudToDeviceMethod);
if(methodResult.Status == 200)
{
// Handle Success
}
else if (methodResult.Status == 500)
{
// Handle Failure
}
}
catch (Exception e)
{
// Device does not exist or is offline
Console.WriteLine(e.Message);
}
I am running this piece of code in my application.
public Task<BulkResponse<JObject>> GetRelatedObjectsAsync(IEnumerable<PrimaryObjectInfo> primaryObjectInfos)
{
var allSecondaries = new List<Tuple<int, List<JObject>>>();
var exceptionsDict = new ConcurrentDictionary<int, Exception>();
var relatedObjectsTasks = primaryObjectInfos.Select(async primaryObjectInfo =>
{
try
{
var secondaryObject = await objectManager.GetRelatedObjectsAsync(primaryObjectInfo);
allSecondaries.Add(Tuple.Create(primaryObjectInfo.Index, secondaryObject.ToList()));
}
catch (Exception ex)
{
exceptionsDict.TryAdd(primaryObjectInfo.Index, ex);
}
});
await Task.WhenAll(relatedObjectsTasks);
return ConvertToBulkResponse(allSecondaries, exceptionsDict);
}
When I run this code allSecondaries object sometimes returns valid list of results and sometimes the code ends up catching exceptions for the parallel threads I have for each primaryObjectInfo.
Async method objectManager.GetRelatedObjectsAsync() internally call 4-5 async functions and there are functions where parameters are passed by reference. (ref keyword)
Question:
Am I using the right data structure to consolidate the result from all parallel threads ?
If yes, what could be the reason I am getting different result every time?
You'd better split the execution from the results gathering:
public Task<BulkResponse<JObject>> GetRelatedObjectsAsync(
IEnumerable<PrimaryObjectInfo> primaryObjectInfos)
{
var relatedObjectsTasks = primaryObjectInfos
.Select(
async primaryObjectInfo =>
(primaryObjectInfo.Index,
await objectManager.GetRelatedObjectsAsync(primaryObjectInfo)))
.ToList();
try
{
await Task.WhenAll(relatedObjectsTasks);
}
catch
{
// observe each task's, exception
}
var allSecondaries = new List<(int index, List<JObject> related)>();
var exceptionsDict = new Dictionary<int, Exception>();
foreach (var relatedObjectsTask in relatedObjectsTasks)
{
try
{
allSecondaries.Add(relatedObjectsTask.Result);
}
catch (Exception ex)
{
exceptionsDict.Add(relatedObjectsTask.index, ex);
}
}
return ConvertToBulkResponse(allSecondaries, exceptionsDict);
}
You could look into each task's IsFaulted/Exception and IsCancelled properties instead of causing exceptions to be thrown:
foreach (var relatedObjectsTask in relatedObjectsTasks)
{
if (relatedObjectsTask.IsCancelled)
{
exceptionsDict.Add(
relatedObjectsTask.index,
new TaskCancelledException(relatedObjectsTask));
}
else if (relatedObjectsTask.IsFaulted)
{
exceptionsDict.TryAdd(relatedObjectsTask.index, ex);
}
else
{
allSecondaries.Add(relatedObjectsTask.Result);
}
}
I have a service that implements functionality to return data from sentiment analysis APIs. The client can request results from one or all engines and I want to collate all the data together. I want to process these async and wait for them all to complete before returning the result set. I'm new to async programming and I really cant figure out how to arrange the code and how to implement it syntactically. Here's an EXAMPLE of what I'm TRYING to achieve (I know this doesn't work, but you get the idea; hopefully :-) ):
private ISentimentResponse ProcessRequest(ISentimentRequest request, SentimentEngineServices selectedEngines)
{
SentimentResponse response = new SentimentResponse();
List<Task> taskList = new List<Task>();
foreach (SentimentEngineServices engineService in (SentimentEngineServices[])Enum.GetValues(typeof(SentimentEngineServices)))
{
if (((int)engineService & (int)selectedEngines) > 0)
{
ISentimentEngine engine = _engineFactory.GetSentimentEngine(engineService, null);
Task<ISentimentEngineResult> task = new Task<ISentimentEngineResult>(engine.AnalyseSentimentASync(request));
taskList.Add(task);
}
}
if (taskList.Count > 0)
{
ISentimentEngineResult[] results = Task<ISentimentEngineResult>.WaitAll(taskList);
foreach (result in results)
response.Add(results);
}
return response;
}
The engine has the following code implementation of engine.AnalyseSentimentASync:
public ISentimentEngineResult AnalyseSentiment(ISentimentRequest request)
{
try
{
MultiLanguageBatchInput sentimentList = SentimentRequestToMicrosoftBatchInput(request, Properties.Settings.Default.DefaultLanguage);
SentimentBatchResult sentiment = _client.Sentiment(sentimentList);
KeyPhraseBatchResult keyPhrases = _client.KeyPhrases(sentimentList);
return MicrosoftBatchResultsToSentimentEngineResult(sentiment, keyPhrases);
}
catch (Exception ex)
{
_logger.LogMessage(ex,$"{EngineName} threw an unknown exception: ", LoggingLevel.Error);
throw;
}
}
public async Task<ISentimentEngineResult> AnalyseSentimentAsync(ISentimentRequest request)
{
return AnalyseSentiment(request);
}
What do I need to do and is there any better way to achieve this?
I've looked everywhere for an example but I cant find one that addresses my implementation requirements, or the whole approach is completely wrong!
Thanks all,
Stu.
This is how you can convert it to async:
public async Task<ISentimentEngineResult> AnalyseSentimentAsync(ISentimentRequest request)
{
try
{
MultiLanguageBatchInput sentimentList = SentimentRequestToMicrosoftBatchInput(request, Properties.Settings.Default.DefaultLanguage);
SentimentBatchResult sentiment = await _client.SentimentAsync(sentimentList);
KeyPhraseBatchResult keyPhrases = await _client.KeyPhrasesAsync(sentimentList);
return MicrosoftBatchResultsToSentimentEngineResult(sentiment, keyPhrases);
}
catch (Exception ex)
{
_logger.LogMessage(ex,$"{EngineName} threw an unknown exception: ", LoggingLevel.Error);
throw;
}
}
private async Task<ISentimentResponse> ProcessRequestAsync(ISentimentRequest request, SentimentEngineServices selectedEngines)
{
SentimentResponse response = new SentimentResponse();
List<Task<ISentimentEngineResult>> taskList = new List<Task<ISentimentEngineResult>>();
foreach (SentimentEngineServices engineService in (SentimentEngineServices[])Enum.GetValues(typeof(SentimentEngineServices)))
{
if (((int)engineService & (int)selectedEngines) > 0)
{
ISentimentEngine engine = _engineFactory.GetSentimentEngine(engineService, null);
Task<ISentimentEngineResult> task = engine.AnalyseSentimentASync(request);
taskList.Add(task);
}
}
if (taskList.Count > 0)
{
ISentimentEngineResult[] results = await Task.WhenAll(taskList);
foreach (result in results)
response.Add(results);
}
return response;
}
Remember that you have to call it from some kind of event handler. I don't know what framework you are using (wpf, asp.net, windows service, webapi).
Ok, so here it is:
public ISentimentResponse AnalyseSentiment(ISentimentRequest request, SentimentEngineServices selectedEngines)
{
if (selectedEngines == SentimentEngineServices.None) throw new ArgumentException(nameof(selectedEngines));
ValidateRequest(request);
return ProcessRequestAsync(request, selectedEngines).Result;
}
private async Task<ISentimentResponse> ProcessRequestAsync(ISentimentRequest request, SentimentEngineServices selectedEngines)
{
SentimentResponse response = new SentimentResponse();
List<Task<ISentimentEngineResult>> taskList = new List<Task<ISentimentEngineResult>>();
foreach (SentimentEngineServices engineService in (SentimentEngineServices[])Enum.GetValues(typeof(SentimentEngineServices)))
{
if (((int)engineService & (int)selectedEngines) > 0)
{
ISentimentEngine engine = _engineFactory.GetSentimentEngine(engineService, null);
Task<ISentimentEngineResult> task = engine.AnalyseSentimentASync(request);
taskList.Add(task);
}
}
if (taskList.Count > 0)
{
ISentimentEngineResult[] results = await Task.WhenAll(taskList);
foreach (var result in results)
response.Add(result);
}
return response;
}
And the sentiment interface implementation:
public async Task<ISentimentEngineResult> AnalyseSentiment(ISentimentRequest request)
{
try
{
MultiLanguageBatchInput sentimentList = SentimentRequestToMicrosoftBatchInput(request, Properties.Settings.Default.DefaultLanguage);
SentimentBatchResult sentiment = await _client.SentimentAsync(sentimentList);
KeyPhraseBatchResult keyPhrases = await _client.KeyPhrasesAsync(sentimentList);
return MicrosoftBatchResultsToSentimentEngineResult(sentiment, keyPhrases);
}
catch (Exception ex)
{
_logger.LogMessage(ex,$"{EngineName} threw an unknown exception: ", LoggingLevel.Error);
throw;
}
}
Thanks FCin.
I want get data from Azure. This is my code:
private async void FindPromotion()
{
MobileServiceCollection<Promotions, Promotions> result;
MobileServiceInvalidOperationException exception = null;
string _place = textInputPlace.Text;
if (_place!= null)
{
try
{
//lista obiektów Category
result = await todoTable2.Where(todoItem => todoItem.Place==_place)
.Select(todoItem => todoItem.Products, todoItem => todoItem.Description)
.ToCollectionAsync();
}
catch (MobileServiceInvalidOperationException ex)
{
exception = ex;
}
if (exception != null)
{
await new MessageDialog(exception.Message, "Can't find items").ShowAsync();
}
else
{
ListItems.ItemsSource = result.Distinct();
}
}
}
I have error:
No overload for method 'Select' takes 2 arguments.
Anybody know? Is another way to get this data?
This is how you can select multiple columns:
result = await todoTable2.Select(todoItem => new { todoItem.Products , todoItem.Description}).ToCollectionAsync();