I have these functions
public async Task<List<Machine>> GetMachines()
{
await Initialize();
await SyncMachines();
return await machineTable.ToListAsync();
}
public async Task InsertMachines(List<Machine> machines)
{
await Initialize();
await Task.WhenAll(machines.Select(m => machineTable.InsertAsync(m)));
await SyncMachines();
}
I am writing a parent class to put these functions in, such that the functions getMachines() and InsertMachines() become getObject and InsertObject where the List<Machine> can be a list of any objects, so they can return and accept any type of list
How do I declare functions like this?
According to your description, I created my azure sync table class as follows, you could refer to it:
public class AzureCloudSyncTable<TModel> where TModel : class
{
public static MobileServiceClient MobileService = new MobileServiceClient(
"https://{your-mobile-app-name}.azurewebsites.net"
);
private IMobileServiceSyncTable<TModel> syncTable = MobileService.GetSyncTable<TModel>();
#region Offline sync
private async Task InitLocalStoreAsync()
{
if (!MobileService.SyncContext.IsInitialized)
{
var store = new MobileServiceSQLiteStore("localstore.db");
store.DefineTable<TModel>();
await MobileService.SyncContext.InitializeAsync(store);
}
await SyncAsync();
}
private async Task SyncAsync()
{
await PushAsync();
await syncTable.PullAsync(typeof(TModel).Name, syncTable.CreateQuery());
}
private async Task PushAsync()
{
try
{
await MobileService.SyncContext.PushAsync();
}
catch (MobileServicePushFailedException ex)
{
if (ex.PushResult != null)
{
foreach (var error in ex.PushResult.Errors)
{
await ResolveConflictAsync(error);
}
}
}
}
private async Task ResolveConflictAsync(MobileServiceTableOperationError error)
{
//var serverItem = error.Result.ToObject<TModel>();
//var localItem = error.Item.ToObject<TModel>();
//// Note that you need to implement the public override Equals(TModel item)
//// method in the Model for this to work
//if (serverItem.Equals(localItem))
//{
// // Items are the same, so ignore the conflict
// await error.CancelAndDiscardItemAsync();
// return;
//}
//// Client Always Wins
//localItem.Version = serverItem.Version;
//await error.UpdateOperationAsync(JObject.FromObject(localItem));
// Server Always Wins
//await error.CancelAndDiscardItemAsync();
}
#endregion
#region public methods
public async Task<List<TModel>> GetAll()
{
await InitLocalStoreAsync();
await SyncAsync();
return await syncTable.ToListAsync();
}
public async Task Insert(List<TModel> items)
{
await InitLocalStoreAsync();
await Task.WhenAll(items.Select(item => syncTable.InsertAsync(item)));
await PushAsync();
}
#endregion
}
Additionally, for more details about Handling Conflict Resolution, you could refer to adrian hall's book here.
Related
I have a method to make an order,
public async Task<bool> Order(Request request)
{
// Each step does different things.
await Step1(request);
await Step2(request);
await Step3(request);
await Step4(request);
...
await StepN(request);
}
public async Task<bool> Step1(Request request)
{
var amount1 = await changeSomething1(request);
await Pay1(amount1);
}
public async Task<bool> Step2(Request request)
{
var amount2 = await changeSomething2(request);
await Pay2(amount2);
}
public async Task<bool> StepX(Request request)
{
var amountX = await changeSomethingX(request);
await PayX(amountX);
}
Now I need to preview the Order without any PayX(amount) is called. I don't want to add a boolen parameter to skip it, like the following code, which looks pretty ugly.
public async Task<bool> Order(Request request, bool preview = false)
{
await Step1(request, preview);
await Step2(request, preview);
await Step3(request, preview);
await Step4(request, preview);
....
await StepN(request, preview);
}
public async Task<bool> StepX(Request request, bool preview = false)
{
var amountX = await changeSomethingX(request);
if(!preview) await PayX(amountX);
}
What pattern can be applied here? Thanks a lot.
It seems to me that you need some middleware-like pattern (Just like middlewares in Asp.Net for example). That's my proposal:
First create An OrderMiddleware class that encapsulates your 2 methods, Step and Pay. In this case we pass step and pay as delegates to the constructor to achieve maximum flexibility
public delegate Task<int> StepDelegate(Request request);
public delegate Task PayDelegate(int amount);
public class OrderMiddleware
{
// Private fields
private readonly StepDelegate _step;
private readonly PayDelegate _pay;
// Initialization
public OrderMiddleware(StepDelegate step, PayDelegate pay)
{
_step = step;
_pay = pay;
}
// Public
public async Task Order(Request request, bool preview)
{
var amount = await _step.Invoke(request);
if (!preview)
await _pay.Invoke(amount);
}
}
Then you need a class to handle a list of OrderMiddlewares that represent your complete pipeline.
public class OrderPipeline
{
// Private fields
private readonly List<OrderMiddleware> _orderMiddlewares;
// Initialization
public OrderPipeline()
{
_orderMiddlewares = new()
{
new(Step1, Pay1),
new(Step2, Pay2)
};
}
// Order Handling
public async Task Order(Request request, bool preview = false)
{
foreach(var middleware in _orderMiddlewares)
await middleware.Order(request, preview);
}
// Middlewares
public async Task Step1(Request request)
{
var amount1 = await changeSomething1(request);
await Pay1(amount1);
}
public async Task Step2(Request request)
{
var amount2 = await changeSomething2(request);
await Pay2(amount2);
}
}
In this way you order method can work with a list of middlwares.
Just few notes:
If you need to pass other parameters to every middleware, in addiction to the preview bool, consider to create a OrderConfiguration class that encapsulates all these data, and pass it instead. In that way the signature remains clean and you do not need to do any refactoring
Maybe you want to separate you middleware registration logic from your OrderPipeline class in order to not violate the open-closed principle:
public class OrderPipeline
{
// Private fields
private readonly List<OrderMiddleware> _orderMiddlewares = new();
// Order Handling
public async Task Order(Request request, bool preview = false)
{
foreach(var middleware in _orderMiddlewares)
await middleware.Order(request, preview);
}
public void AddMiddleware(OrderMiddleware orderMiddleware)
{
_orderMiddlewares.Add(orderMiddleware);
}
}
I have the following SignalR Hub with in-memory connection management.
[Authorize]
public class ChatHub : Hub
{
private static readonly ConnectionMapping<string> _connections =
new ConnectionMapping<string>();
private readonly IMessageRepository _messagesRepository;
public ChatHub(IMessageRepository messageRepository)
{
_messagesRepository = messagesRepository;
}
public override async Task OnConnectedAsync()
{
var name = Context.User.Identity.Name;
_connections.Add(name, Context.ConnectionId);
//await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception exception)
{
var name = Context.User.Identity.Name;
_connections.Remove(name, Context.ConnectionId);
//await Groups.RemoveFromGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnDisconnectedAsync(exception);
}
public async void SendMessage(ChatMessage chatMessage)
{
var name = Context.User.Identity.Name;
var chatHistoryMessage = await _messagesRepository.SaveMessageAsync(chatMessage);
var availableConnections = _connections.GetConnections(name);
if (availableConnections.Any())
{
foreach (var connectionId in availableConnections)
{
Clients.Client(connectionId).SendAsync("ReceiveMessage", chatHistoryMessage);
}
}
else
{
}
}
}
However, when executing the code the following line
Clients.Client(connectionId).SendAsync("ReceiveMessage", 1);
raises an object disposed error on Clients.
This issue started happening when I added the repository line:
var chatHistoryMessage = await _messagesRepository.SaveMessageAsync(chatMessage);
SaveMessageAsync method:
public async Task<ChatHistory> SaveMessageAsync (ChatMessage chatMessage)
{
using (var conn = new SqlConnection(ConnProvider.ConnectionString))
{
await conn.OpenAsync();
return (await conn.QueryAsync<ChatHistory>("[mob].[spSaveChatMessage]",
new
{
..
},
commandType: CommandType.StoredProcedure)).FirstOrDefault();
}
}
Why would my Clients object be disposed? If I wait with the debugger that issue never happens.
It looks like the SendMessage method should be an async Task rather than an async void.
The issue could be caused by the way the SignalR framework runs async voids.
See this article for a good overview.
Async methods returning void don’t provide an easy way to notify the
calling code that they’ve completed.
I try to wait for the class to be finished with instantiate.
My architecture is the following. Cook is inheriade from CookChief.
And if I instantiate cook, CookChief is creating himself, but CookChief is calling 1 other class named Cookhelper the cookhelper is waiting for a input and for this input method i want to wait in Cook.
The thing is iam creating this in MVVM Galasoft and my entry point is the CookViewmodel, with a relaycommand.
In the code below you can see my architecture. To say it short I want to wait until this bool processed = await Task.Run(() => ValidateForDeviceId()); is finished.
My first step was to outsource the constructer of each class. And create a init method.
This is my code:
public CookViewModel()
{
startCookButtonCommand = new RelayCommand(Cook);
}
private async Task Cook()
{
cook.Init();
}
public class Cook : CookChief
{
public Cook()
{
}
public async Task Init()
{
await this.CookChiefInit();
//here I want to wait until CookChiefInit is finished
Cooking();
}
public void Cooking()
{
MessageBox.Show("Input received");
}
}
Now the Cookchief:
public Cookchief()
{
}
protected async Task CookchiefInit()
{
this.Cookhelper = new Cookhelper();
Cookhelper.CookHelperInit();
}
And in the CookHelper we do this:
public CookHelper()
{
}
public void CookHelperInit()
{
this.driverWindow = new DriverWindow();
startProc();
}
private async void startProc()
{
ShowOrCloseDriverWindow(true);
//this is the task what we wait for before we can repeat
bool processed = await Task.Run(() => ValidateForDeviceId());
if(processed)
{
ShowOrCloseDriverWindow(false);
}
else
{
MessageBox.Show("DriverError");
}
}
private bool ValidateForDeviceId()
{
for (; ; )
{
this.deviceId = Input.deviceId;
if (deviceId > 0)
{
break;
}
}
return true;
}
Per the discussion in the comments, the problem here was that the initialization routine mixed synchronous and asynchronous methods and calls. Additionally, some async methods were called without the await keyword. The solution was to make all calls asynchronous and await them.
cook.Init() needs an await:
private async Task Cook()
{
await cook.Init();
}
In CookchiefInit(), the CookHelperInit() call needs to be awaited:
protected async Task CookchiefInit()
{
this.Cookhelper = new Cookhelper();
Cookhelper.CookHelperInit();
}
In order to await CookHelperInit(), it needs to be made asynchronous. The startProc() call is to an async method, so it must also be awaited:
public async Task CookHelperInit()
{
this.driverWindow = new DriverWindow();
await startProc();
}
I have a simple Web API method that looks like this:
public async Task<HttpResponseMessage> RunTask(TaskType taskType)
{
var taskId = await TaskManager.CreateTask(taskType);
TaskManager.Run(taskId);
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content =
new StringContent($"Task {taskType.GetDescription()} was started.")
};
}
TaskManager.Run is decalared like this:
public async Task Run(int id)
I was expecting it to return "Task was started" message immediately after TaskManager.Run(taskId) But the request continues to run synchronously.
But if to replace the call TaskManager.Run(taskId) with:
Task.Run(() => Thread.Sleep(TimeSpan.FromSeconds(100)));
Then it runs asynchronously.
So I believe this is something to do with the resources shared by TaskManager and main thread. Can a shared resource lock the execution?
I'm using Castle Windsor. One WindsorContainer container is declared in Web API project.
TaskManager utilizes BaseTaskRunner class inside of it. One more WindsorContainer is declared in BaseTaskRunner.
Web API's container uses LifeStyle.PerWebRequest for all components. BaseTaskRunner's container uses LifeStyle.Singleton (not sure if it's correct LifeStyle). Could the call be locked for example by DdContext or other classes declared in both of the containers?
UPD:
I don't want to wait the TaskManager.Run to complete. But what happens is that return statement still waits for the TaskManager.Run to complete (even without await statement on TaskManager.Run).
In other words it does not matter how I call the TaskManager.Run:
TaskManager.Run(taskId);
or
await TaskManager.Run(taskId);
It waits for TaskManager.Run to complete in both cases.
Here is the code of TaskManager:
public class TaskManager : ITaskManager
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
public async Task<int> CreateTask(TaskType type, byte[] data = null, object config = null)
{
var task = new BackgroundTask
{
Type = type,
Status = BackgroundTaskStatus.New,
Config = config?.SerializeToXml(),
Created = DateTime.Now,
Data = data
};
TaskRepository.Add(task);
TaskRepository.SaveChanges();
return task.Id;
}
public async Task Run(int id, bool removeOnComplete = true)
{
var task = TaskRepository.GetById(id);
Run(task, removeOnComplete);
}
public async Task Run(TaskType type, bool removeOnComplete = true)
{
var tasksToRun = TaskRepository.Get(t => t.Type == type);
tasksToRun.ForEachAsync(t => Run(t, removeOnComplete));
}
public async Task Run(BackgroundTask task, bool removeOnComplete = true)
{
switch (task.Type)
{
case TaskType.SpreadsheetImport:
new SpreadsheetImportTaskRunner().Run(task);
break;
}
}
}
And some other classes:
public class SpreadsheetImportTaskRunner : BaseTaskRunner
{
public IForecastSpreadsheetManager SpreadsheetManager { get; set; }
protected override void Execute()
{
SpreadsheetManager.ImportActuals(Task.Data);
}
protected override void Initialize()
{
base.Initialize();
SpreadsheetManager = _container.Resolve<IForecastSpreadsheetManager>();
}
}
BaseTaskRunner:
public class BaseTaskRunner
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
protected IWindsorContainer _container = new WindsorContainer();
protected BackgroundTask Task { get; set; }
public async Task Run(BackgroundTask task)
{
Initialize();
Task = task;
try
{
Execute();
}
catch (Exception ex)
{
SetError(ex.ToString());
}
}
protected virtual void Execute()
{
}
protected virtual void Initialize()
{
_container.Install(new TaskRunnerComponentsInstaller());
TaskRepository = _container.Resolve<IRepository<BackgroundTask>>();
}
}
I still believe this is something to do with the WindsorContainer and common classes which are resolved in several different threads.
The issue is that you're not using await on the Task being returned from the invocation of the TaskManager.Run function. Consider the below:
public async Task<HttpResponseMessage> RunTask(TaskType taskType)
{
var taskId = await TaskManager.CreateTask(taskType);
await TaskManager.Run(taskId);
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content =
new StringContent($"Task {taskType.GetDescription()} was started.")
};
}
Now it will work asynchronously as you'd expect. The await sets a continuation marker in the async state-machine, instructing it to return to this portion of the method upon completion of the asynchronous operation defined in the TaskManager.Run.
UPDATE
You are missing lots of await statements, and there are times where you need to not mark methods as async. It appears as though there are some mis-understandings as it pertains to these keywords. Here is what your TaskManager class should look like.
public class TaskManager : ITaskManager
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
public async Task<int> CreateTask(TaskType type,
byte[] data = null,
object config = null)
{
var task = new BackgroundTask
{
Type = type,
Status = BackgroundTaskStatus.New,
Config = config?.SerializeToXml(),
Created = DateTime.Now,
Data = data
};
TaskRepository.Add(task);
TaskRepository.SaveChanges();
return task.Id;
}
public ask Run(int id, bool removeOnComplete = true)
{
var task = TaskRepository.GetById(id);
return Run(task, removeOnComplete);
}
public Task Run(TaskType type, bool removeOnComplete = true)
{
var tasksToRun = TaskRepository.Get(t => t.Type == type);
return tasksToRun.ForEachAsync(t => Run(t, removeOnComplete));
}
public Task Run(BackgroundTask task, bool removeOnComplete = true)
{
switch (task.Type)
{
case TaskType.SpreadsheetImport:
return new SpreadsheetImportTaskRunner().Run(task);
break;
}
}
}
}
Ideally, if the method is marked as a return type of Task and the method doesn't need to unwind any tasks within its execution it can simply return the Task functionality for its implementation. For example, notice how dramatically my TaskManager class differs from yours -- I'm only marking methods as async that need to actually await. These two keywords should be married, if a method uses async there should be an await. But only use await if the method needs to unwind and use the asynchronous operation.
This is a followup question to the following question:
Volatile IEnlistmentNotification and TransactionScope.AsyncFlowEnabled = true
The approach accepted in the question above works as long as you don't await multiple statements. Let me show an example:
public class SendResourceManager : IEnlistmentNotification
{
private readonly Action onCommit;
public SendResourceManager(Action onCommit)
{
this.onCommit = onCommit;
}
public void Prepare(PreparingEnlistment preparingEnlistment)
{
preparingEnlistment.Prepared();
}
public void Commit(Enlistment enlistment)
{
Debug.WriteLine("Committing");
this.onCommit();
Debug.WriteLine("Committed");
enlistment.Done();
}
public void Rollback(Enlistment enlistment)
{
enlistment.Done();
}
public void InDoubt(Enlistment enlistment)
{
enlistment.Done();
}
}
public class AsyncTransactionalMessageSender : ISendMessagesAsync
{
private readonly List<Message> sentMessages = new List<Message>();
public IReadOnlyCollection<Message> SentMessages
{
get { return new ReadOnlyCollection<Message>(this.sentMessages); }
}
public async Task SendAsync(Message message)
{
if (Transaction.Current != null)
{
await Transaction.Current.EnlistVolatileAsync(
new SendResourceManager(async () => await this.SendInternal(message)),
EnlistmentOptions.None);
}
else
{
await this.SendInternal(message);
}
}
private async Task SendInternal(Message message)
{
Debug.WriteLine("Sending");
await Task.Delay(1000);
this.sentMessages.Add(message);
Debug.WriteLine("Sent");
}
}
[Test]
public async Task ScopeRollbackAsync_DoesntSend()
{
var sender = new AsyncTransactionalMessageSender();
using (var tx = new System.Transactions.TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
await sender.SendAsync(new Message("First"));
await sender.SendAsync(new Message("Second"));
await sender.SendAsync(new Message("Last"));
// We do not commit the scope
}
sender.SentMessages.Should().BeEmpty();
}
[Test]
public async Task ScopeCompleteAsync_Sends()
{
var sender = new AsyncTransactionalMessageSender();
using (var tx = new System.Transactions.TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
await sender.SendAsync(new Message("First"));
await sender.SendAsync(new Message("Second"));
await sender.SendAsync(new Message("Last"));
tx.Complete();
}
sender.SentMessages.Should().HaveCount(3)
.And.Contain(m => m.Value == "First")
.And.Contain(m => m.Value == "Second")
.And.Contain(m => m.Value == "Last");
}
As soon as you introduce a Task.Delay like shown in the example above the generated asynchronous statemachine will never come back and invoke the this.sentMessages.Add(message) and Debug.WriteLine("Sent")
The problem is I currently see now way to properly enlist asynchronous code inside the enlistment notification. Any ideas how to tackle this challenge?