I try to execute a method in an external library:
This is the interface of the external library:
public interface IExternal
{
string Name { get; }
Task DoAsync();
}
This is the class of the external library:
public class ExternalClass : IExternal
{
public string Name
{
get
{
return "Test external";
}
}
public async Task DoAsync()
{
Console.WriteLine("Do async");
await Task.Delay(3000);
Console.WriteLine("Done async");
}
}
This is the local class my ViewModel uses:
public class External
{
public string Name { get; set; }
public string Description { get; set; }
public RelayCommand Run { get; set; }
}
In my application i load the external library as an reference.
An try to bind DoAsync as RelayCommand:
foreach (var item in externals)
{
var t = new External();
t.Name = item.Name;
t.Description = "test";
t.Run = new RelayCommand(async () => await item.DoAsync());
}
The XAML binding of the button is as follows: Command="{Binding Run}"
Nothing happens, no command is executed.
Related
Working on a project thats Stores items to my sqlDb created it following this video by James Montemagno https://www.youtube.com/watch?v=XFP8Np-uRWc&ab_channel=JamesMontemagno my issue now comes when I'm trying to save a list to the sqlDb it shows that it was added however when i retrieve my data my List prop is null.
public class UserTask{
[PrimaryKey]
public string ID { get; set; }
public string Title { get; set; }
[TextBlob("TagBlobbed")]
public List<string> TagsList { get; set; }
public string TagBlobbed { get; set; }
public string Details { get; set; }
[Ignore]
public string Comment { get; set; }
public UserTask()
{
TagsList = new();
}
}
public static class PlannerDataService
{
static SQLiteAsyncConnection db;
static async Task Init()
{
if (db != null) return;
var databasePath = Path.Combine(FileSystem.AppDataDirectory, "DbTasks.db");
db = new SQLiteAsyncConnection(databasePath);
await db.CreateTableAsync<UserTask>();
}
public static async Task AddNewTask(UserTask t)
{
await Init();
var task = new UserTask()
{
ID = t.ID,
TagsList = t.TagsList,
Details = t.Details,
Title = t.Title
};
await db.InsertAsync(task);
}
public static async Task<List<UserTask>> GetUserTasks()
{
await Init();
var tasks = await db.Table<UserTask>().ToListAsync();
var t = tasks.OrderByDescending(a => a.ID).ToList();
return t;
}
public static async Task RemoveTask(string id)
{
await Init();
await db.DeleteAsync<UserTask>(id);
}
public static async Task UpdateTask(UserTask t)
{
await Init();
var task = new UserTask()
{
ID = t.ID,
TagsList = t.TagsList,
Details = t.Details,
Title = t.Title
};
await db.UpdateAsync(task);
}
}
I've seen + read questions similar to this and I've tried following their advice to no luck which is why I'm posting for a better solution without changing much of my code.
I'm working on Unit test. I create TestBuilder class, where I create method SetupTown method.
When I tried call this method in my main test class - i have error( Error CS0118'TestBuilder' is a namespace but is used like a type). I read about it and recommend to call a class with method. I tried do it, but It doesn't help.
public partial class TownServiceTests
public partial class TownServiceTests
{
private class TestBuilder
{
public Mock<ITownRepository> MockTownRepository { get; set; }
//public Mock<IClientViewModelBuilder> MockClientPropertyModelBuilder { get; set; }
public Mock<IMapper> MockMapper { get; set; }
public TestDataGenerator TestDataGenerator;
private readonly string _jsonDataPath = #"../../../TestData/Town/TownTestData.json";
private string _jsonDataKey;
private TownViewModel Towns { get; set; }
public TestBuilder(string jsonDataKey)
{
MockTownRepository = new Mock<ITownRepository>();
//MockClientPropertyModelBuilder = new Mock<IClientViewModelBuilder>();
MockMapper = new Mock<IMapper>();
TestDataGenerator = new TestDataGenerator(_jsonDataPath);
_jsonDataKey = jsonDataKey;
TestDataGenerator.LoadData(_jsonDataKey);
}
public ITownService Build()
{
return new TownService(MockTownRepository.Object,
MockMapper.Object);
}
public TestBuilder SetupTowns()
{
var towns = TestDataGenerator.GetTestData<Town>(_jsonDataKey, "Towns");
MockTownRepository.Setup(r => r.InsertTown(It.IsAny<string>()))
.ReturnsAsync(towns.FirstOrDefault().Id);
return this;
}
}
}
}
Please check method public TestBuilder SetupTowns
Here my TestClass
[TestClass]
public partial class TownServiceTests
{
[TestMethod]
public async Task ValidInsertTown()
{
var builder = new TestBuilder("Data").SetupTowns; //Problem
var service = builder.Build();
var expectedTowns = builder.TestDataGenerator.GetTestData<Town>("Data", "Towns");
var result = await service.InsertTown(expectedTowns);
Assert.IsNotNull(result);
Assert.IsNull(result);
}
}
Could toy tell me what I do wrong?
Example
public partial class ClientServiceTests
{
private class TestBuilder
{
public Mock<IClientRepository> MockClientRepository { get; set; }
public Mock<IClientViewModelBuilder> MockClientPropertyModelBuilder { get; set; }
public Mock<IMapper> MockMapper { get; set; }
public TestDataGenerator TestDataGenerator;
private readonly string _jsonDataPath = #"../../../TestData/Client/ClientTestData.json";
private string _jsonDataKey;
public TestBuilder(string jsonDataKey)
{
MockClientRepository = new Mock<IClientRepository>();
MockClientPropertyModelBuilder = new Mock<IClientViewModelBuilder>();
MockMapper = new Mock<IMapper>();
TestDataGenerator = new TestDataGenerator(_jsonDataPath);
_jsonDataKey = jsonDataKey;
TestDataGenerator.LoadData(_jsonDataKey);
}
public IClientService Build()
{
return new ClientService(MockClientRepository.Object
, MockClientPropertyModelBuilder.Object
, MockMapper.Object);
}
public TestBuilder SetupClients()
{
var clients = TestDataGenerator.GetTestData<ClientSummary>(_jsonDataKey, "Clients");
MockClientRepository.Setup(r => r.GetClientBySearchCriteria(It.IsAny<string>()))
.ReturnsAsync(clients);
var clientViewModels = TestDataGenerator.GetTestData<ClientViewModel>(_jsonDataKey, "ClientViewModel");
MockClientPropertyModelBuilder.Setup(r => r.GetClientViewModel(clients))
.Returns(clientViewModels);
return this;
}
public TestBuilder SetupInvalidInputClients()
{
MockClientRepository.Setup(r => r.GetClientBySearchCriteria(It.IsAny<string>()))
.ReturnsAsync(new List<ClientSummary>());
MockClientPropertyModelBuilder.Setup(r => r.GetClientViewModel(new List<ClientSummary>()))
.Returns(new List<ClientViewModel>());
return this;
}
}
}
TestClass (here works good)
[TestMethod]
public async Task GetClientBySearchCriteria_ValidInput_ReturnClients()
{
var searchParameter = "1";
var builder = new TestBuilder("Data").SetupClients();
var service = builder.Build();
var expectedClients = builder.TestDataGenerator.GetTestData<ClientSummary>("Data", "Clients");
var result = await service.GetClientBySearchCriteria(searchParameter);
Assert.IsNotNull(result);
Assert.AreEqual(2, result.Count);
Assert.AreEqual(expectedClients.FirstOrDefault().Name, result.FirstOrDefault().Name);
}
namespace of the file
I think, the issue is happened because you have Something.TestBuilder.Something namespace and compiler is trying to use it instead of class.
You have the TestBuilder folder and a few classes inside it. It may be that classes inside TestBuilder folder contains TestBuilder in their namespaces and compiler trying to access this namespace instead of class.
I am creating a simple logging system by using Nest and C#. I have a log producer for collecting logs inside of blockingcollection. Also I have a consumer. But I stumpled upon with an issue. How can I use my comsumer in startup or is there any way to create background servise which was listening queue of blockingcollection? What is best practice of it? I am confusing how to call AsyncConsumer or consumer when application startup.
public class SimpleLog
{
public string Header { get; set; }
public string LogDate { get; set; }
public string Sessionid { get; set; }
public string Userid { get; set; }
public string Correlationid { get; set; }
public int Status { get; set; }
public string UrlQueryString { get; set; }
public string UrlPath { get; set; }
public string UrlMethod { get; set; }
public string Environment { get; set; }
public string IndexName { get; set; }
public string IndexType { get; set; }
}
public class QuickLog
{
private static BlockingCollection<SimpleLog> data = new BlockingCollection<SimpleLog>();
public static void Producer(SimpleLog pageviewLog)
{
data.TryAdd(pageviewLog, TimeSpan.FromSeconds(10));
}
public static void Consumer()
{
var _client = ElasticConfig.GetClient();
var logs = new List<SimpleLog>();
foreach (var item in data.GetConsumingEnumerable())
{
logs.Add(item);
}
if (logs == null && logs.Count <= 0)
return;
var log = logs.FirstOrDefault();
var response = _client.IndexMany(logs, log.IndexName, log.IndexType);
if (!response.IsValid)
throw response.OriginalException;
}
public async Task AsyncConsumer()
{
var _client = ElasticConfig.GetClient();
var logs = new List<SimpleLog>();
foreach (var item in data.GetConsumingEnumerable())
{
logs.Add(item);
}
if (logs == null && logs.Count <= 0)
return;
var log = logs.FirstOrDefault();
var response = await _client.IndexManyAsync(logs, log.IndexName, log.IndexType).ConfigureAwait(false);
if (!response.IsValid)
throw response.OriginalException;
await Task.Delay(TimeSpan.FromSeconds(10)).ConfigureAwait(false);
}
}
public static class ElasticConfig
{
private static IElasticClient _client;
static ElasticConfig()
{
var esurl = LogSettings.Url;
string[] urls = esurl.Split(',');
var nodes = new Uri[2];
for (int i = 0; i < urls.Length; i++)
{
nodes.SetValue(new Uri(urls[i]), i);
}
var connectionPool = new SniffingConnectionPool(nodes);
var connectionSettings = new ConnectionSettings(connectionPool).RequestTimeout(
TimeSpan.FromSeconds(60))
.PingTimeout(TimeSpan.FromSeconds(60))
.MaxRetryTimeout(TimeSpan.FromSeconds(60))
.MaxDeadTimeout(TimeSpan.FromSeconds(60))
.DeadTimeout(TimeSpan.FromSeconds(60)).DisablePing()
.SniffOnConnectionFault(false)
.SniffOnStartup(false)
.SniffLifeSpan(TimeSpan.FromMinutes(1));
_client = new ElasticClient(connectionSettings);
}
public static IElasticClient GetClient()
{
return _client;
}
}
Not sure how many times and which method exactly you want to call. If you want to run some asynchronous background jobs you can use IHostedService. You will need to install Microsoft.Extensions.Hosting NuGet package or Microsoft.AspNetCore.App metapackage.
Usage:
Add this line to your Startup.cs
services.AddHostedService<LogBackgroundService>(); //service is instance of IServiceCollection
And this is the implementation of your background service:
public class LogBackgroundService : IHostedService
{
public async Task StartAsync(CancellationToken cancellationToken)
{
await QuickLog.AsyncConsumer(); // or whatever you want to call
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
Behavior:
It will run once(but IHostedService still will be running. If you want to reduce resource consumption just call StopAsync() when it's done). If you want to run something in a loop, you can implement this:
while (!cancellationToken.IsCancellationRequested)
{
await QuickLog.AsyncConsumer();
await Task.Delay(250, cancellationToken); // you can add this if you want to throttle
}
PS. If you need to run multiple IHostedServices in your application without blocking each other you will need to wrap your methods into Tasks:
public Task StartAsync(CancellationToken cancellationToken)
{
Task.Run(() => QuickLog.AsyncConsumer(), cancellationToken);
}
IHostedService is solution for you.
You can crate new class and inherit from this class https://gist.github.com/davidfowl/a7dd5064d9dcf35b6eae1a7953d615e3
Then your new class will be something like this
public class LogService : HostedService
{
private readonly IServiceScopeFactory _scopeFactory;
public LogBackgroundService (IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
await new QuickLog().AsyncConsumer(cancellationToken);
await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken);
}
}
}
Finally update your Startup.cs:
services.AddSingleton<IHostedService, LogService>();
I've been playing around with the bot framework and creating a chat bot for fun that lets you detail the members of your family/pets.
Is there a way to recur over the same set of questions until the user is satisfied? Example code below:
[Prompt("What is your family name?")]
public string familyName{ get; set; }
[Prompt("What is your postcode?")]
public string postcode { get; set; }
[Prompt("Would you like to add a family member? {||}")]
public bool AddPerson { get; set; }
[Prompt("What is their name?")]
public string PersonName { get; set; }
[Prompt("How old are they?")]
public string PersonAge{ get; set; }
[Prompt("How are they related to you?")]
public string PersonRelation{ get; set; }
[Prompt("Would you like to add another family member? {||}")]
public bool addAnotherPerson { get; set; }
public IForm<Family> BuildForm()
{
return new FormBuilder<GetQuoteDialog>()
.Field(nameof(familyName))
.Field(nameof(postcode))
//Choose to add a person to the family
.Field(nameof(AddPerson))
//Details of that person.
.Field(new FieldReflector<Family>(nameof(PersonName))
.SetActive((state) => state.AddPerson== true))
.Field(new FieldReflector<Family>(nameof({PersonAge))
.SetActive((state) => state.AddPerson== true))
.Field(new FieldReflector<Family>(nameof({PersonRelation))
.SetActive((state) => state.AddPerson== true))
//Prompts the user to add another if they wish
//Recurs to the PersonName field and lets them go through the
//process of adding another member
.Field(new FieldReflector<Family>(nameof({AddAnotherMember))
.SetActive((state) => state.AddPerson== true))
.Confirm("Is this your family? {*}")
.Build();
}
}
Does anyone have an idea on how to accomplish this?
I call the formflow like this:
public async Task confirmAdd(IDialogContext context, IAwaitable<bool> result)
{
if (await result)
{
// builds and calls the form from here
var myform = new FormDialog<BuildFamily>(new BuildFamily(), BuildForm, FormOptions.PromptInStart, null);
context.Call<BuildFamily>(myform, End);
}
}
private async Task End(IDialogContext context, IAwaitable<BuildFamily> result)
{
BuildFamily data = null;
try
{
data = await result;
await context.PostAsync("Nice family you got there :)");
}
catch (OperationCanceledException)
{
await context.PostAsync("You canceled the form!");
return;
}
}
I'm not sure how to "recur over the same set of questions until the user is satisfied" within a FormFlow dialog. However, you can ask the user the question "Would you like to add more family members?" in the calling dialog, and achieve the same type of conversation flow. Remove the PostalCode and FamilyName type questions, and put them in a separate dialog. Then, in the add family members dialog do something like this:
[Serializable]
public class AddFamilyMembersDialog : IDialog<object>
{
List<Family> _familyMembers = new List<Family>();
public Task StartAsync(IDialogContext context)
{
context.Wait(MessageReceivedAsync);
return Task.CompletedTask;
}
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
PromptAddMembers(context);
}
private void PromptAddMembers(IDialogContext context)
{
PromptDialog.Text(context, AfterPromptAdd, "Would you like to add more family members?", null, 1);
}
private async Task AfterPromptAdd(IDialogContext context, IAwaitable<string> result)
{
var yesno = await result;
if (yesno.ToLower() == "yes")
{
await context.Forward(FormDialog.FromForm(Family.BuildForm), AfterAdded, null, CancellationToken.None);
}
else
{
//_familyMembers contains everyone the user wanted to add
context.Done(true);
}
}
private async Task AfterAdded(IDialogContext context, IAwaitable<Family> result)
{
var member = await result;
if (member != null)
_familyMembers.Add(member);
PromptAddMembers(context);
}
[Serializable]
public class Family
{
[Prompt("What is their name?")]
public string PersonName { get; set; }
[Prompt("How old are they?")]
public string PersonAge { get; set; }
[Prompt("How are they related to you?")]
public string PersonRelation { get; set; }
public static IForm<Family> BuildForm()
{
return new FormBuilder<Family>()
.AddRemainingFields()
.Build();
}
}
}
I have the following task i would love to initialize once the app is running, and just populate a value in my App.xaml.cs
public partial class App : Application
{
public bool ProcessedTask = false;
public List<Item> Items = new List<Item>();
public App()
{
...
// Standard XAML initialization
InitializeComponent();
// NOW HERE I WOULD LIKE TO INVOKE MY TASK
}
public async Task<string> RequestDataTask()
{
HttpClient client = new HttpClient();
Task<string> getStringRequests = client.GetStringAsync("http://test.com/get/");
ItemsRootObject responseObject = Newtonsoft.Json.JsonConvert.DeserializeObject<ItemsRootObject>(getStringRequests);
foreach (Item item in responseObject.rows)
{
Items.Add(item);
}
ProcessedTask = true;
string Message = "Processed Task";
return Message;
}
}
public class ItemsRootObject
{
public List<Item> rows { get; set; }
public bool success { get; set; }
public int code { get; set; }
public string msg { get; set; }
}
public class Item
{
public string value { get; set; }
}
I already know the JSON return and objects are there correctly (works in a regular call), but i don't know (understand) how to invoke my task while keeping the phone app going (load MainPage.xaml).
Anyone can tell how i get my task started asynchronously?
You can use async and await where you need to call the task.
private async void yourFunction(object sender, RoutedEventArgs e)
{
string result = await RequestDataTask();
}
http://msdn.microsoft.com/it-it/library/hh191443.aspx
But if you want to call an async method inside a constructor use something like this:
public partial class App
{
private readonly Task _initializingTask;
public App()
{
_initializingTask = Init();
}
private async Task Init()
{
/*
Initialization that you need with await/async stuff allowed
*/
string result = await RequestDataTask();
}
}