My code declares a cancellation token here in a view model, creates it in the OnAppearing and Cancels in the OnDisappearing:
public partial class DeckTabViewModel : BaseViewModel
{
public CancellationTokenSource cts;
}
Then in OnAppearing:
public partial class DeckTabViewModel : BaseViewModel
{
public async Task OnAppearingAsync()
{
cts = new CancellationTokenSource();
await GetCards(cts.Token);
}
}
And on Disappearing:
public partial class DeckTabViewModel : BaseViewModel
{
public async Task OnDisappearingAsync()
{
cts.Cancel();
}
}
Could someone tell me if this is the correct way to use the Cancellation token and should I in the OnDisappearing, also set it to null?
As CancellationTokenSource implements IDisposable, you should dispose the instance of CancellationTokenSource (in your example, cts) when you have finished using it: you can do so directly by calling the Dispose method, or indirectly using the using construct.
In your case, you would call Dispose after calling Cancel on cts:
public partial class DeckTabViewModel : BaseViewModel
{
public async Task OnDisappearingAsync()
{
try
{
cts.Cancel();
}
finally
{
if(cts != null)
{
cts.Dispose();
}
}
}
}
Related
I have scenario to pass async function as callback to my own resource manager(which implements IEnlistmentNotification interface), and need to invoke asynchronously in prepare method, but it works when invoke as synchronous way, is there any way to make it without wait or asynchronous, the wait producing the AggregatorException rather than my custom exception?
Resource Manager
public class ResourceManager : IEnlistmentNotification
{
private Func<Task>? _doWorkCallback;
public async Task EnlistAsync(Func<Task> doWorkCallback)
{
_doWorkCallback = doWorkCallback;
var transaction = Transaction.Current;
if (transaction != null)
{
await transaction.EnlistVolatileAsync(this, EnlistmentOptions.None).ConfigureAwait(false);
}
}
public void Prepare(PreparingEnlistment preparingEnlistment)
{
try
{
_doWorkCallback?.Invoke().Wait();
preparingEnlistment.Prepared();
}
catch
{
preparingEnlistment.ForceRollback();
}
}
public void Commit(Enlistment enlistment)
{
enlistment.Done();
}
public void Rollback(Enlistment enlistment)
{
enlistment.Done();
}
public void InDoubt(Enlistment enlistment)
{
enlistment.Done();
}
}
public static class TranscationExtensions
{
public static Task EnlistVolatileAsync(this Transaction transaction,
IEnlistmentNotification
enlistmentNotification,
EnlistmentOptions enlistmentOptions)
{
return Task.FromResult(transaction.EnlistVolatile
(enlistmentNotification,
enlistmentOptions));
}
}
Usage Code
public class Test
{
private async Task DoWork()
{
Thread.Sleep(1000);// considerer here my custom exception
await Task.CompletedTask;
}
public async Task TestMethod()
{
ResourceManager rm = new ResourceManager();
await rm.EnlistAsync(async () => await DoWork().ConfigureAwait(false)).ConfigureAwait(false);
}
}
When I want to Insert A New Object into the db bellow Error Occured:
No database provider has been configured for this DbContext
Services:
private IConfiguration config;
public Startup(IConfiguration config) => this.config = config;
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFrameworkSqlServer().AddDbContext<DataContext>(options => options.UseSqlServer(config["ConnectionStrings:MainConnection"]));
services.AddMvc();
}
DataContext:
public class DataContext:DbContext
{
public DataContext() { }
public DataContext(DbContextOptions<DataContext> options) : base(options) { }
public DbSet<Request> Request { get; set; }
public DbSet<AdminAccept> AdminAccept { get; set; }
public DbSet<Payment> Payment { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
base.OnConfiguring(builder);
}
}
Insert command :
public async Task <int> SaveToStorageAsync()
{
using (DataContext context=new DataContext())
{
context.Request.Add(this);
return await context.SaveChangesAsync();
}
}
however migrations and database created succefully
I solved it finally.
everything is okay but use of using expression cause an error.(I wonder why)
to solving it first of all I removed a using and declare a DataContext as parameter:
public async Task<int> SaveToStorageAsync(DataContext context)
{
context.Request.Add(this);
return await context.SaveChangesAsync();
}
after it initiate constructor in the main controller :
DataContext context;
public HomeController(DataContext context)
{
this.context = context;
}
and finally call function by sending context as a parameter.
hopped you used in your scenarios and good luck
Since you register the DataContext with the constructor receiving a DbContextOptions<DataContext> option.You also need to pass that when you create a DataContext
var optionsBuilder = new DbContextOptionsBuilder<DataContext >();
optionsBuilder.UseSqlServer("Your connection string");
using (DataContext context = new DataContext (optionsBuilder.Options))
{
context.Request.Add(this);
return await context.SaveChangesAsync();
}
I suggest that you could use dbContext by DI in controller which is a more recommended way in asp.net core:
public class StudentsController : Controller
{
private readonly DataContext _context;
public StudentsController(DataContext context)
{
_context = context;
}
public async Task <int> SaveToStorageAsync()
{
_context.Request.Add(this);
return await context.SaveChangesAsync();
}
}
The two ways are included in below link:
https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext#configuring-dbcontextoptions
I have noticed that when i call Bus.Publish my SendObserver is beeing called along with my PublishObserver. In my original scenario i use the observers for some debug logging where i noticed that when i call Publish both the PublishObserver and the SendObserver is called with the same message. The example code below reproduces the scenario:
public class YourMessage { public string Text { get; set; } }
public class SendObserver : ISendObserver {
public Task PreSend<T>(SendContext<T> context) where T : class
{
return Task.CompletedTask;
}
public Task PostSend<T>(SendContext<T> context) where T : class
{
Console.Out.WriteLineAsync($"Message Sent, Id: {context.MessageId}");
return Task.CompletedTask;
}
public Task SendFault<T>(SendContext<T> context, Exception exception) where T : class
{
return Task.CompletedTask;
}
}
public class PublishObserver : IPublishObserver
{
public Task PrePublish<T>(PublishContext<T> context) where T : class
{
return Task.CompletedTask;
}
public Task PostPublish<T>(PublishContext<T> context) where T : class
{
Console.Out.WriteLineAsync($"Message Published, Id: {context.MessageId}");
return Task.CompletedTask;
}
public Task PublishFault<T>(PublishContext<T> context, Exception exception) where T : class
{
return Task.CompletedTask;
}
}
public class Program
{
public static void Main()
{
var bus = Bus.Factory.CreateUsingRabbitMq(sbc =>
{
var host = sbc.Host(new Uri("rabbitmq://rabbitmq/PublishSendTest"), h =>
{
h.Username("guest");
h.Password("guest");
});
sbc.ReceiveEndpoint(host, "test_queue", ep =>
{
ep.Handler<YourMessage>(context =>
{
return Console.Out.WriteLineAsync($"Received: {context.Message.Text}");
});
});
});
bus.ConnectSendObserver(new SendObserver());
bus.ConnectPublishObserver(new PublishObserver());
bus.Start();
bus.Publish(new YourMessage { Text = "Hi" });
Console.WriteLine("Press any key to exit");
Console.ReadKey();
bus.Stop();
}
}
Output:
Press any key to exit
Message Sent, Id: ac4f0000-3051-1065-bbe5-08d6335c9e05
Message Published, Id: ac4f0000-3051-1065-bbe5-08d6335c9e05
Received: Hi
Is this the expected behaviour? If so what can i do to determine if it acutally was a Publish call that created the message?
I used version 5.1.5
The inconsistent observer issue should be resolved in the develop builds, and a test has been created to verify the behavior on the supported transports. Once released, the send observer should only be called on an actual Send, and the publish observer should only be called on an actual Publish.
Thanks for bringing this up, I'm not sure how it got out of whack.
I have a strange issue of getting null exception. I created class that implements ICommand interface, I have two methods.
public void Execute(object parameter)
{
NavigateAsync();
}
private async void NavigateAsync()
{
await App.MainNavigation.PushAsync(new Pages.SettingsPage());
}
When NavigateAsync() is exectude my MainNavigation is always null, even that I can see that parameter inside Execute is set.
In my App.xaml.cs file I have created public static INavigation MainNavigation { get; set; }
public partial class App : Application
{
public static ViewModels.MainViewModel ViewModel { get; set; }
public static INavigation MainNavigation { get; set; }
public App ()
{
InitializeComponent();
MainPage = new NavigationPage(new Paperboy.MainPage());
}
protected override void OnStart ()
{
// Handle when your app starts
}
protected override void OnSleep ()
{
// Handle when your app sleeps
}
protected override void OnResume ()
{
// Handle when your app resumes
}
}
Se when clicking icon i can se that command is executed but App.MainNavigation inside NavigateAsync() in null. So command is not executing PushAsync to SettingsPage.
You never instantiate your static MainNavigation property...
If I can give you 2 remarks:
instead of using a static property declared into your App.xaml.cs, maybe a better implementation could be to embed a Navigation getter into a specific 'service' class or directly into your Command definition:
public class MyCommand : ICommand
{
...
// Navigation getter
// There are better places for this prop but it's better
// than in app.xaml.cs
private INavigation MainNavigation
{
get => Application.Current?.MainPage?.Navigation;
}
public void Execute(object parameter)
{
NavigateAsync();
}
private async void NavigateAsync()
{
try
{
await MainNavigation?.PushAsync(new Pages.SettingsPage());
}
catch(){ ... }
}
}
Another point I would like to note, is that your Command looks like asynchronous. Maybe you already know, but here is a good implementation of async commands to avoid app crashes: Asynchronous commands
I hope it can help you. Happy coding !
I have written a custom OnMethodBoundaryAspect called TraceAspect. This aspect checks within the OnEntry, OnExit, and OnException methods whether tracing is enabled or not. I have a central class for reading and writing settings. Both of the two methods Settings.GetLoggingEnabled() and Settings.GetLogLevel() are called from the TraceAspect. They are there, so I reuse them which results in a StackOverflowException.
[assembly: MyCompany.MyProduct.TraceAspect]
[Serializable]
public class TraceAspect : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
if (Settings.GetLogginEnabled() && Settings.GetLogLevel() == LogLevel.Trace)
{
// Log the message
}
}
}
Applying the [TraceAspect(AttributeExclude = true)] attribute to the TraceAspect class leads to the same behaviour.
I could write something like this. But this is code duplication.
[assembly: MyCompany.MyProduct.TraceAspect]
[Serializable]
public class TraceAspect : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
if (this.GetLogginEnabled() && this.GetLogLevel() == LogLevel.Trace)
{
// Log the message
}
}
private bool GetLoggingEnabled()
{
// copy code from Settings.GetLogginEnabled()
}
private bool GetLogLevel()
{
// copy code from Settings.GetLogLevel()
}
}
How can I tell that the Settings.GetLoggingEnabled() and Settings.GetLogTrace() methods should not be traced, when they are called by the aspect?
You can break the recursion during logging by introducing a thread static flag to indicate that you're currently inside the logging call.
[Serializable]
public class TraceAspect : OnMethodBoundaryAspect
{
[ThreadStatic]
private static bool isLogging;
public override void OnEntry(MethodExecutionArgs args)
{
if (isLogging) return;
isLogging = true;
try
{
if (Settings.GetLogginEnabled() && Settings.GetLogLevel() == LogLevel.Trace)
{
// Log the message
}
}
finally
{
isLogging = false;
}
}
}