How to raise Event in HostedService and consume it in a Blazor Component? - multithreading

i am building a BlazorServer-Side App und i try to Update one of my Components when a Event occurs in a HostedService.
The Problem is solved! Check the Comments for the Solution.
This is how i try to do it:
Configuration in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddSingleton<WeatherForecastService>();
services.AddHostedService<WeatherForecastService>();
}
WeatherForecastService:
public class WeatherForecastService : IHostedService
{
private System.Timers.Timer timer = new System.Timers.Timer(10000);
public delegate void EventHandler(object sender, EventArgs e);
public event EventHandler NewWeather;
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private void TimeOver(object sender, ElapsedEventArgs e)
{
NewWeather?.Invoke(this, null);
}
public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate)
{
var rng = new Random();
return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToArray());
}
public Task StartAsync(CancellationToken cancellationToken)
{
timer.Elapsed += TimeOver;
timer.AutoReset = true;
timer.Start();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
FetchData.razor:
#code {
private WeatherForecast[] forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
ForecastService.NewWeather += UpdateWeather;
}
private async void UpdateWeather(object sender, object args)
{
forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
StateHasChanged();
}
}
UpdateWeather() on the FetchData.razor never gets called.
I am guessing the FetchData Component does not notice the event is fired because of some threading issue. But I dont konw yet what to do about it...
Your Help is appreciated.
Best Regards

The Code above generates two Instances of the WeatherForecastService!
The Solution is to change the registration of the HostedService
from:
services.AddHostedService();
to:
services.AddHostedService(sp => sp.GetRequiredService());

Related

Android Studio Widget faster update

Is there any way to update it faster than 30 min? I am trying to get a String from a website (which my code already can) and show it on a widget as an image.Code:
final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.status_widget);
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(context);
String url ="http://stats.bytewerk.org/status.txt";
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
public void onResponse(String response) {
if (response.equals("open")) {
views.setImageViewResource(R.id.status_nointernet, R.id.status_online);
} else {
views.setImageViewResource(R.id.status_nointernet, R.id.status_offline);
}
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
views.setImageViewResource(R.id.status_nointernet, R.id.status_nointernet);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
});
queue.add(stringRequest);
Runnable runnable = new Runnable() {
#Override
public void run() {
Handler handler = new Handler();
statusUpdate(context, appWidgetManager, appWidgetId); //volley request
handler.postDelayed(this, 5000);
}
};
runnable.run();

RxJava subscribe onNext is not called when adding element asynchronously

I have a Observable like this
Observable<String> gitHubRepoModelObservable;
I have this code
repoNames = new ArrayList<String>();
gitHubRepoModelObservable = Observable.fromIterable(repoNames);
repoNames.add("Hello");
gitHubRepoModelObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(String s) {
System.out.println(s);
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
repoNames is just a list of string. When I am adding a string "hello" manually the onNext is getting called but when I am adding string from a API call like bellow
call.enqueue(new Callback<List<GitHubRepoModel>>() {
#Override
public void onResponse(Call<List<GitHubRepoModel>> call, Response<List<GitHubRepoModel>> response) {
for (GitHubRepoModel repo : response.body()) {
repoNames.add(repo.getName());
}
}
#Override
public void onFailure(Call<List<GitHubRepoModel>> call, Throwable t) {
}
});
I am adding strings from the API into the repoNames the "onNext" is not getting called.
I have seen
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
can be added while initializing retrofit but I want to better understand the rxjava so in this experiment it is not working.
Please help!
It can't not be work.
When you create you api request and try subscribe you list is emty, so Observable does not work.
You need to create Observable such, that your subcribe will run your request!
Observable<String> gitHubRepoModelObservable = Observable.create(
new Observable.OnSubscribe<String>() {
#Override
public void call(final Subscriber<? super String> sub) {
call.enqueue(new Callback<List<GitHubRepoModel>>() {
#Override
public void onResponse(Call<List<GitHubRepoModel>> call, Response<List<GitHubRepoModel>> response) {
for (GitHubRepoModel repo : response.body()) {
sub.onNext(repo.getName()); //send result to rx
}
sub.onCompleted();
}
#Override
public void onFailure(Call<List<GitHubRepoModel>> call, Throwable t) {
}
});
}
}
);
gitHubRepoModelObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
#Override
public void onNext(String s) {
System.out.println(s);
}
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
});
Why would onNext get called if you are just adding element to plain List?
In the first example you are seeing onNext being called because modified list is passed through the stream during subscribe.
Create Subject ex. PublishSubject and pass list to Subject.onNext in onResponse, subscribe to it and you will get what you want.
Second option is adding RxJava2CallAdapterFactory and return Observable<Response<List<GithubRepoModel>>>. This way you don't need to create stream yourself.

Mocking a method inside my test class

Android Studio 2.3
I have the following method I want to test inside my model class:
public class RecipeListModelImp implements RecipeListModelContract {
private Subscription subscription;
private RecipesAPI recipesAPI;
private RecipeSchedulers recipeSchedulers;
#Inject
public RecipeListModelImp(#NonNull RecipesAPI recipesAPI, #NonNull RecipeSchedulers recipeSchedulers) {
this.recipesAPI = Preconditions.checkNotNull(recipesAPI);
this.recipeSchedulers = Preconditions.checkNotNull(recipeSchedulers);
}
#Override
public void getRecipesFromAPI(final RecipeGetAllListener recipeGetAllListener) {
subscription = recipesAPI.getAllRecipes()
.subscribeOn(recipeSchedulers.getBackgroundScheduler())
.observeOn(recipeSchedulers.getUIScheduler())
.subscribe(new Subscriber<List<Recipe>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
recipeGetAllListener.onRecipeGetAllFailure(e.getMessage());
}
#Override
public void onNext(List<Recipe> recipe) {
recipeGetAllListener.onRecipeGetAllSuccess(recipe);
}
});
}
#Override
public void shutdown() {
if(subscription != null && !subscription.isUnsubscribed()) {
subscription.unsubscribe();
}
}
}
Inside my test class I am testing like this:
public class RecipeListModelImpTest {
#Mock Subscription subscription;
#Mock RecipesAPI recipesAPI;
#Mock RecipeListModelContract.RecipeGetAllListener recipeGetAllListener;
#Mock List<Recipe> recipes;
#Inject RecipeSchedulers recipeSchedulers;
private RecipeListModelContract recipeListModel;
#Before
public void setup() {
TestBusbyComponent testBusbyComponent = DaggerTestBusbyComponent.builder()
.mockRecipeSchedulersModule(new MockRecipeSchedulersModule())
.build();
testBusbyComponent.inject(RecipeListModelImpTest.this);
MockitoAnnotations.initMocks(RecipeListModelImpTest.this);
recipeListModel = new RecipeListModelImp(recipesAPI, recipeSchedulers);
}
#Test(expected = NullPointerException.class)
public void testShouldThrowExceptionOnNullParameter() {
recipeListModel = new RecipeListModelImp(null, null);
}
#Test
public void testRecipeListModelShouldNotBeNull() {
assertNotNull(recipeListModel);
}
#Test
public void testShouldGetRecipesFromAPI() {
when(recipesAPI.getAllRecipes()).thenReturn(Observable.just(recipes));
recipeListModel.getRecipesFromAPI(recipeGetAllListener);
verify(recipesAPI, times(1)).getAllRecipes();
verify(recipeGetAllListener, times(1)).onRecipeGetAllSuccess(recipes);
verify(recipeGetAllListener, never()).onRecipeGetAllFailure(anyString());
}
#Test
public void testShouldFailToGetRecipesFromAPI() {
when(recipesAPI.getAllRecipes())
.thenReturn(Observable.<List<Recipe>>error(
new Throwable(new RuntimeException("Failed to get recipes"))));
recipeListModel.getRecipesFromAPI(recipeGetAllListener);
verify(recipesAPI, times(1)).getAllRecipes();
verify(recipeGetAllListener, times(1)).onRecipeGetAllFailure(anyString());
verify(recipeGetAllListener, never()).onRecipeGetAllSuccess(recipes);
}
#Test
public void testShouldShutdown() {
when(subscription.isUnsubscribed()).thenReturn(false);
final Field subscriptionField;
try {
subscriptionField = recipeListModel.getClass().getDeclaredField("subscription");
subscriptionField.setAccessible(true);
subscriptionField.set(recipeListModel, subscription);
} catch(NoSuchFieldException e) {
e.printStackTrace();
}
catch(IllegalAccessException e) {
e.printStackTrace();
}
recipeListModel.shutdown();
verify(subscription, times(1)).unsubscribe();
}
}
However, the problem is the Subscription in my model class is always null so will never enter the if blook. Is there any way to test this with using Mockito or spys?
Many thanks for any suggestions,
You should for testing recipeListModel class, where you have shutdown() method , set mock into this class.
If you don't have set method for subscription in recipeListModel , or constructor param.... ),you can set mock object with reflection like :
#Test
public void testShouldShutdown() {
Subscription subscription = mock(Subscription.class);
when(subscription.isUnsubscribed()).thenReturn(false);
Field subscriptionField = recipeListModel.getClass().getDeclaredField("subscription");
subscriptionField.setAccessible(true);
subscriptionField.set(recipeListModel, subscriptionMock);
recipeListModel.shutdown();
verify(subscription, times(1)).unsubscribe();
}
after your update :
if you can't change way of creation , you should mock it like (full way of creation) , i don't know your api , so it's just idea:
Subscription subscription = mock(Subscription.class);
when(subscription.isUnsubscribed()).thenReturn(false);
// preparation mock for create Subscription
//for recipesAPI.getAllRecipes()
Object mockFor_getAllRecipes = mock(....);
when(recipesAPI.getAllRecipes()).thenReturn(mockFor_getAllRecipes );
//for subscribeOn(recipeSchedulers.getBackgroundScheduler())
Object mockFor_subscribeOn = mock();
when(mockFor_getAllRecipes.subscribeOn(any())).thenReturn(mockFor_subscribeOn);
//for .observeOn(recipeSchedulers.getUIScheduler())
Object mockFor_observeOn = mock();
when(mockFor_subscribeOn .observeOn(any())).thenReturn(observeOn);
// for .subscribe
when(observeOn.subscribe(any()).thenReturn(subscription);

Botframework how log history

Do You have any idea how to log all outgoing/incoming messages? I am not sure how to capture outgoing messages.
I use Chains and Forms.
For example
await Conversation.SendAsync(activity, rootDialog.BuildChain);
AND
activity.CreateReply(.....);
I found better solution
public class BotToUserLogger : IBotToUser
{
private readonly IMessageActivity _toBot;
private readonly IConnectorClient _client;
public BotToUserLogger(IMessageActivity toBot, IConnectorClient client)
{
SetField.NotNull(out _toBot, nameof(toBot), toBot);
SetField.NotNull(out _client, nameof(client), client);
}
public IMessageActivity MakeMessage()
{
var toBotActivity = (Activity)_toBot;
return toBotActivity.CreateReply();
}
public async Task PostAsync(IMessageActivity message, CancellationToken cancellationToken = default(CancellationToken))
{
await _client.Conversations.ReplyToActivityAsync((Activity)message, cancellationToken);
}
}
public class BotToUserDatabaseWriter : IBotToUser
{
private readonly IBotToUser _inner;
public BotToUserDatabaseWriter(IBotToUser inner)
{
SetField.NotNull(out _inner, nameof(inner), inner);
}
public IMessageActivity MakeMessage()
{
return _inner.MakeMessage();
}
public async Task PostAsync(IMessageActivity message, CancellationToken cancellationToken = default(CancellationToken))
{
// loging outgoing message
Debug.WriteLine(message.Text);
//TODO log message for example into DB
await _inner.PostAsync(message, cancellationToken);
}
In controller use
public MessagesController()
{
var builder = new ContainerBuilder();
builder.RegisterType<BotToUserLogger>()
.AsSelf()
.InstancePerLifetimeScope();
builder.Register(c => new BotToUserTextWriter(c.Resolve<BotToUserLogger>()))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
builder.Update(Microsoft.Bot.Builder.Dialogs.Conversation.Container);
}
Its look like I cant log outgoing message.
I changed SDK source code.
Add event in Conversations.cs
For example like this.
public delegate void MessageSendedEventHandler(object sender, Activity activity, string conversationId);
public static event MessageSendedEventHandler MessageSended;
And add in every Send....HttpMessagesAsync method
this MessageSended?.Invoke(this, activity, conversationId);
its not great solution. But its working

How to extend ServiceStack IDbConnectionFactory and MiniProfiler

Given the following code for my connection factory:
public interface IDbFrontEndConnectionFactory : IDbConnectionFactory
{
}
public class FrontEndDbFactory : IDbFrontEndConnectionFactory
{
private readonly IAppSettings _settings;
private readonly IDbConnectionFactory _dbFactory;
public Func<IDbConnection, IDbConnection> ConnectionFilter { get; set; }
public FrontEndDbFactory(IDbConnectionFactory dbFactory, IAppSettings settings)
{
_dbFactory = dbFactory;
_settings = settings;
ConnectionFilter = (Func<IDbConnection, IDbConnection>)(x => x);
}
public IDbConnection OpenDbConnection()
{
var tenantId = Tenant.GetTenant();
return OpenTenant(tenantId);
}
public IDbConnection OpenTenant(string tenantId = null)
{
return tenantId != null
? new OrmLiteConnectionFactory(_settings.GetString("TenantId{0}:{1}".Fmt(tenantId, "Frontend"))).OpenDbConnection()
: _dbFactory.OpenDbConnection();
}
public IDbConnection CreateDbConnection()
{
return _dbFactory.CreateDbConnection();
}
}
IoC registration
IDbFrontEndConnectionFactory feFactory = new FrontEndDbFactory(masterDbFactory, fileSettings)
{
ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current)
};
container.Register(feFactory);
Global.asax
protected void Application_Start(object sender, EventArgs e)
{
LogManager.LogFactory = new NLogFactory();
new AppHost().Init();
}
protected void Application_BeginRequest(object src, EventArgs e)
{
if (Request.IsLocal)
Profiler.Start();
}
protected void Application_EndRequest(object src, EventArgs e)
{
Profiler.Stop();
}
The Repository:
public partial class CampaignRepository : ICampaignRepository
{
readonly ILog _log = LogManager.GetLogger(typeof(CampaignRepository));
private readonly IDbFrontEndConnectionFactory _connectionFactory;
public CampaignRepository(IDbFrontEndConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}
}
The IoC registration of my repository
container.Register<ICampaignRepository>(c => new CampaignRepository(c.Resolve<IDbFrontEndConnectionFactory>()));
The Service method when I'm inspecting the profiler
public CampaignViewModel Get(GetCampaign request)
{
if (request == null) throw new ArgumentNullException("request");
var profiler = Profiler.Current;
using (profiler.Step("Campaign Service Get"))
{
try
{
var vm = CampaignRepository.GetCampaignInfo(request.Id).ToViewModel();
if (vm.Campaign != null) return vm;
Response.StatusCode = (int)HttpStatusCode.NotFound;
return null;
}
catch (Exception exception)
{
_log.Error(request.ToJson(), exception);
throw;
}
}
}
I was expecting the profiler to show the sql timings, but that's not the case, the connection is not being profiled.
Is there something else that needs to be enabled or corrected for this to work?
Thank you, Stephen
To enable SQL Profiling in MiniProfiler you need to register the OrmLiteConnectionFactory to use MiniProfilers ProfiledDbConnection, e.g:
Container.Register<IDbConnectionFactory>(c =>
new OrmLiteConnectionFactory(connectionString, SqlServerDialect.Provider) {
ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current)
});

Resources