I am using Microsoft SignalR in order to push notification to browsers. Those notifications are triggered by action from other browsers. I want to make a background task which send notification sometimes. For example, at 12:45:21 i want to fire a notification to all connected users, even if they are doing nothing. Is it possible to do that ?
SignalR doesn't give you the ability to run a background task, but if you run are running a background task, there is nothing to stop your task using your SignalR hub to invoke client methods and send any desired notification.
To launch and control your background task, Hangfire is a flexible library that should help.
Edit to add: Since you've clarified you want to do this in a windows service, another prominent library to assist with building and deploying services is TopShelf
Edit to add: Also, I gather from your comment that you're trying to understand how to access the hub object from your background task? There are many ways to do this, but to improve testability and maintainability of your program, I recommend using an IoC (Inversion of Control) container, and injecting the necessary references - this tutorial: Dependency Injection in SignalR has a walkthrough using the Ninject library. That walkthrough is oriented towards asp.net hosting, but the link you found should help with adapting to a windows service.
If you are using asp.net core 2.1, this is now possible using BackgroundService/IHostedService
https://github.com/davidfowl/UT3/blob/fb12e182d42d2a5a902c1979ea0e91b66fe60607/UTT/Scavenger.cs#L9-L40
(Contents below)
public class Scavenger : BackgroundService
{
private readonly IHubContext<UTTHub> _hubContext;
private readonly ILogger<Scavenger> _logger;
public Scavenger(IHubContext<UTTHub> hubContext, ILogger<Scavenger> logger)
{
_hubContext = hubContext;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
// Mark games that haven't played in a while as completed
var changed = Game.MarkExpiredGames();
// Mark completed games as removed
var removed = Game.RemoveCompletedGames();
if (removed > 0)
{
_logger.LogInformation("Removed {GameCount} games.", removed);
}
if (removed > 0 || changed)
{
await _hubContext.Clients.All.SendAsync("GameUpdated", Game.GetGames());
}
await Task.Delay(5000);
}
}
}
}
Also see this
https://github.com/aspnet/Docs/issues/8925
Related
We are working on service which collect data from AWS SQS then send batch to client. We are using mediator to publish notifications. The diagram of program looks like:
The problem is in first NotificationHandler from Mediatr.
private readonly EventCollectorHostedService _collector;
public CollectIncomingEventNotificationHandler(EventCollectorHostedService collector)
{
_collector = collector;
}
Class EventCollectorHostedService is register after Mediator so is not visible during registering this NotificationHandler and additionally it use Mediator to publish notification that batch is ready to send.
The error is that cannot construct CollectIncomingEventNotificationHandler because -> Unable to resolve service for type 'Api.Services.HostedServices.EventCollectorHostedService'.
services.AddMediatR(typeof(Startup).GetTypeInfo().Assembly);
services.AddHostedService<EventCollectorHostedService>();
The ugly solution is to declare some functionality in EventCollectorHostedService as static or instead of injecting EventCollectorHostedService, inject IServiceProvider.
But these solution don't look clean for me so do you have any other better solution ?
Thanks in advance.
Maybe someone encountered with similar problem so finally i have a brilliant solution.
Background services have to be treat like separate microservices based on event driven architecture so we have to make internal message broker mechanism.
The very simple solution which cover my case is:
public class NotificationChannel : INotificationChannel
{
public event EventHandler<IncomingEventNotificataionEventArgs> IncomingEventReceived;
public void Publish<T>(T notification)
{
if(notification is IncomingEventNotification incomingEventNotification)
{
OnIncomingEventReceived(incomingEventNotification);
}
}
protected virtual void OnIncomingEventReceived(IncomingEventNotification notification)
{
if(IncomingEventReceived != null)
{
var args = new IncomingEventNotificataionEventArgs(notification);
IncomingEventReceived(this, args);
}
}
}
This is a question about the project https://github.com/DiUS/pact-jvm.
Problem
When I am validating pacts I need to be able to use client side authentication, as the providers actually require client side authentication. I'll prefix what I am saying with a declaration that I am not very familiar with groovy: I mostly program in scala, java or javascript. Having looked at the code I think that client side authentication is not currently supported, so I'd like to make a pull request with that support in it.
What I've done so far
I have managed to get Https working with a truststore: I copied the HttpTarget and created a HttpsTarget, and in the HttpsTarget specified the truststore in the providerinfo. Unfortunately looking at the code there doesn't seem to be a way of specifying the client certificate, so I need to change the providerinfo class to be able to specify where it is (in the same way the the truststore is provided).
My problem is that I've got the code compiling using the advice in the 'for contributors', but when I publish locally, I am only publishing for scala version 2_12. Because of version issues and binary incompatibilities between scala versions, I need to publish to scala 2_11. My skills with gradle are even less than my skills with groovy. I've done a search for all the references to scalaVersion, and found that there is quite a lot of logic around it, but I've not managed to track down where it is specified.
Question
If I can use client side authentication with the current pact validator could you let me know. If not, could you tell me how to publish the project with support for scala 2_11?
Thanks
In the end I made my own Http Target. My need is to run from Junit, not the general case, and this is good enough:
public class HttpsTarget extends HttpTarget {
public HttpsTarget(final int port) {
super("https", "localhost", port, "/", false);
}
static class HttpsClientFactory implements IHttpClientFactory {
#NotNull
#Override
public CloseableHttpClient newClient(Object o) {
SSLContext sslContext = // put here code to make ssl context
CloseableHttpClient httpClient = HttpClients
.custom()
.setSSLContext(sslContext)
.build();
return httpClient;
}
}
#Override
public void testInteraction(final String consumerName, final Interaction interaction, PactSource source) {
ProviderInfo provider = getProviderInfo(source);
ConsumerInfo consumer = new ConsumerInfo(consumerName);
ProviderVerifier verifier = setupVerifier(interaction, provider, consumer);
Map<String, Object> failures = new HashMap<>();
ProviderClient client = new ProviderClient(provider, new HttpsClientFactory());
verifier.verifyResponseFromProvider(provider, interaction, interaction.getDescription(), failures, client);
reportTestResult(failures.isEmpty(), verifier);
try {
if (!failures.isEmpty()) {
verifier.displayFailures(failures);
throw getAssertionError(failures);
}
} finally {
verifier.finialiseReports();
}
}
}
How can I dispose and re-instantiate a singleton with Prism/DryIoC in Xamarin Forms?
I'm working with Azure Mobile Apps for offline data. Occasionally, I need to delete the local sqlite database and re-initialize it. Unfortunately the MobileServiceClient occasionally holds the db connection open and there's no method exposed to close it. The suggested solution (https://github.com/Azure/azure-mobile-apps-net-client/issues/379) is to dispose of MobileServiceClient. Only problem is that is registered with DryIoC as a singleton.
I'm not overly familiar with DryIoC, or Prism and Forms for that matter... But for the life of me, I can't see a way to do this.
I did cook up a pretty elaborate scheme that almost worked.
In my ViewModel method, when I needed the db freed up, I fired off an event -
_eventAggregator.GetEvent<RegisterDatabaseEvent>().Publish(false);
Then in App.xaml.cs, I wired up a listener and a handler like so -
_eventAggregator.GetEvent<RegisterDatabaseEvent>().Subscribe(OnRegisterDatabaseEventPublished);
private void OnRegisterDatabaseEventPublished()
{
Container.GetContainer().Unregister<IAppMobileClient>();
Container.GetContainer().Unregister<IMobileServiceClient>();
Container.GetContainer().Register<IMobileServiceClient, AppMobileClient>(new SingletonReuse());
Container.GetContainer().Register<IAppMobileClient, AppMobileClient>(new SingletonReuse());
_eventAggregator.GetEvent<RegisterDatabaseCompletedEvent>().Publish(register);
}
Lastly, back in the ViewModel constructor, I had a final listener that handled the event coming back from App.xaml and finished processing.
_eventAggregator.GetEvent<RegisterDatabaseCompletedEvent>().Subscribe(OnRegisterDatabaseCompletedEventPublished);
So the amazing thing is that this worked. The database was able to be deleted and all was good. But then I navigated to a different page and BOOM. DryIoC said it couldn't wire up the ViewModel for that page. I assume the unregister/register jacked up DryIoC for all injection... So how can I accomplish what needs to be done?
FINAL SOLUTION
Thanks so much to dadhi for taking the time to help. You are certainly a class act and I'm now considering using DryIoC elsewhere.
For anyone who stumbles on this, I'm posting the final solution below. I'll be as verbose as I can to avoid any confusion.
First, in my App.xaml.cs, I added a method for registering my database.
public void RegisterDatabase(IContainer container)
{
container.RegisterMany<AppMobileClient>(Reuse.Singleton,
setup: Setup.With(asResolutionCall: true),
ifAlreadyRegistered: IfAlreadyRegistered.Replace,
serviceTypeCondition: type =>
type == typeof(IMobileServiceClient) || type == typeof(IAppMobileClient));
}
I simply add a call to that method in RegisterTypes in place of registering the types in there directly.
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.GetContainer().Rules.WithoutEagerCachingSingletonForFasterAccess();
...
RegisterDatabase(containerRegistry.GetContainer());
...
}
Note also the added rule for eager caching, per dadhi.
Later on when I need to release the database in the ViewModel... I kick things off by resetting my local db variable and sending an event to App.xaml.cs
_client = null;
_eventAggregator.GetEvent<RegisterDatabaseEvent>().Publish(true);
In App.xaml.cs, I have subscribed to that event and tied it to the following method.
private void OnRegisterDatabaseEventPublished()
{
RegisterDatabase(Container.GetContainer());
_eventAggregator.GetEvent<RegisterDatabaseCompletedEvent>().Publish(register);
}
Here I just call RegisterMany again, exactly the same as I do when the app starts up. No need to unregister anything. With the setup and ifAlreadyRegistered arguments (thanks, dadhi!), DryIoC allows the object to be replaced. Then I raise an event back to the VM letting it know the database has been released.
Finally, back in the ViewModel, I'm listening for the completed event. The handler for that event updates the local copy of the object like so.
_client = ((PrismApplication)App.Current).Container.Resolve<IAppMobileClient>();
And then I can work with the new object, as needed. This is key. Without setting _client to null above and resolving it again here, I actually ended up with 2 copies of the object and calls to methods were being hit 2x.
Hope that helps someone else looking to release their Azure Mobile Apps database!
I am not sure how exactly XF handles these things.
But in DryIoc in order for service to be fully deleted or replaced it need to be registered with setup: Setup.With(asResolutionCall: true). Read here for more details: https://bitbucket.org/dadhi/dryioc/wiki/UnregisterAndResolutionCache#markdown-header-unregister-and-resolution-cache
Update
Here are two options and considerations that work in pure DryIoc and may not work XF. But it probably may help with solution.
public class Foo
{
public IBar Bar { get; private set; }
public Foo(IBar bar) { Bar = bar; }
}
public interface IBar {}
public class Bar : IBar {}
public class Bar2 : IBar { }
[Test]
public void Replace_singleton_dependency_with_asResolutionCall()
{
var c = new Container(rules => rules.WithoutEagerCachingSingletonForFasterAccess());
c.Register<Foo>();
//c.Register<Foo>(Reuse.Singleton); // !!! If the consumer of replaced dependency is singleton, it won't work
// cause the consumer singleton should be replaced too
c.Register<IBar, Bar>(Reuse.Singleton,
setup: Setup.With(asResolutionCall: true)); // required
var foo = c.Resolve<Foo>();
Assert.IsInstanceOf<Bar>(foo.Bar);
c.Register<IBar, Bar2>(Reuse.Singleton,
setup: Setup.With(asResolutionCall: true), // required
ifAlreadyRegistered: IfAlreadyRegistered.Replace); // required
var foo2 = c.Resolve<Foo>();
Assert.IsInstanceOf<Bar2>(foo2.Bar);
}
[Test]
public void Replace_singleton_dependency_with_UseInstance()
{
var c = new Container();
c.Register<Foo>();
//c.Register<Foo>(Reuse.Singleton); // !!! If the consumer of replaced dependency is singleton, it won't work
// cause the consumer singleton should be replaced too
c.UseInstance<IBar>(new Bar());
var foo = c.Resolve<Foo>();
Assert.IsInstanceOf<Bar>(foo.Bar);
c.UseInstance<IBar>(new Bar2());
var foo2 = c.Resolve<Foo>();
Assert.IsInstanceOf<Bar2>(foo2.Bar);
}
I have a requirement to start a process on the server that may run for several minutes, so I was thinking of exposing the following hub method:-
public async Task Start()
{
await Task.Run(() => _myService.Start());
}
There would also be a Stop() method that allows a client to stop the running process, probably via a cancellation token. I've also omitted code that prevents it from being started if already running, error handling, etc.
Additionally, the long-running process will be collecting data which it needs to periodically broadcast back to the client(s), so I was wondering about using an event - something like this:-
public async Task Start()
{
_myService.AfterDataCollected += AfterDataCollectedHandler;
await Task.Run(() => _myService.Start());
_myService.AfterDataCollected -= AfterDataCollectedHandler;
}
private void AfterDataCollectedHandler(object sender, MyDataEventArgs e)
{
Clients.All.SendData(e.Data);
}
Is this an acceptable solution or is there a "better" way?
You don't need to use SignalR to start the work, you can use the applications already existing framework / design / API for this and only use SignalR for the pub sub part.
I did this for my current customers project, a user starts a work and all tabs belonging to that user is updated using signalr, I used a out sun library called SignalR.EventAggregatorProxy to abstract the domain from SignalR. Disclaimer : I'm the author of said library
http://andersmalmgren.com/2014/05/27/client-server-event-aggregation-with-signalr/
edit: Using the .NET client your code would look something like this
public class MyViewModel : IHandle<WorkProgress>
{
public MyViewModel(IEventAggregator eventAggregator)
{
eventAggregator.Subscribe(this);
}
public void Handle(WorkProgress message)
{
//Act on work progress
}
}
Background
I've read all kinds of blogs and documentation about nhibernate session management. My issue, is I need it for both winforms and webforms. That's right, I'm using the same data layer in both a winforms (windows .exe) and webforms (asp.net web) application. I've read a little about the unit of work pattern and is a good choice for winforms. Storing the nhibernate session in HttpRequest.Current.Items seems like a good way to go for web apps. But what about a combo deal? I have web apps, windows apps, and WCF services that all need to use the same nhibernate data layer. So back to my question...
I plan on using this design: NhibernateBestPractices in my web app like so:
private ISession ThreadSession {
get {
if (IsInWebContext()) {
return (ISession)HttpContext.Current.Items[SESSION_KEY];
}
else {
return (ISession)CallContext.GetData(SESSION_KEY);
}
}
set {
if (IsInWebContext()) {
HttpContext.Current.Items[SESSION_KEY] = value;
}
else {
CallContext.SetData(SESSION_KEY, value); // PROBLEM LINE HERE!!!
}
}
}
The Problem
The problem I am having when using this code in my windows app, is with the line
CallContext.SetData(SESSION_KEY, value);
If I understand CallContext() right, this will keep the session open the entire lifetime of my windows app because it stores the nhibernate session as part of the main applications thread. And I've heard all kinds of bad things about keeping an nhibernate session open for too long and I know by design, it's not mean to stay open very long. If all my assumptions are correct, then the above line of code is a no,no.
Given all this, I'd like to replace the above line with something that will destroy the nhibernate session more frequently in a windows app. Something similar to the lifetime of the HttpRequest. I don't want to leave it up to the windows client to know about the nhibernate session (or transaction) and when to open and close it. I'd like this to be triggered automagically.
The Question
So, where can I store the nhibernate session in a windows app that will allow me (ie. something besides the client) to automatically begin and end a transaction on a per database request (that is, whenever a client makes a call to the DB)?
** Update **
Here are 2 more links on how to implement the unit of work pattern
http://msdn.microsoft.com/en-us/magazine/dd882510.aspx
http://www.codeinsanity.com/2008/09/unit-of-work-pattern.html
Each of your apps can provide a common implementation of an interface like IUnitOfWorkStorage
public interface IUnitOfWorkStorage
{
void StoreUnitOfWork(IUnitOfWork uow);
}
IUnitOfWork can be a wrapper around the ISession which can look like this
public interface IUnitOfWork
{
void Begin();
void End();
}
Begin might open the session and start a transaction, while End would commit the transaction and close the session. So you can have 2 implementations of IUnitOfWorkStorage, one for the WebApp and one for the Windows App. The web app can use HttpContext.Current or something and your windows app can provide just a simple object store that is disposed at the end of your action which would End the UnitOfWork.
I ended up using the following code. The only "burden" it put on my app was the unit tests, and I'd rather muck up that code with session specific info that the production code. I kept the same code as mentioned in my question and then added this class to my unit test project:
namespace MyUnitTests
{
/// <summary>
/// Simulates the IHttpModule class but for windows apps.
/// There's no need to call BeginSession() and EndSession()
/// if you wrap the object in a "using" statement.
/// </summary>
public class NhibernateSessionModule : IDisposable
{
public NhibernateSessionModule()
{
NHibernateSessionManager.Instance.BeginTransaction();
}
public void BeginSession()
{
NHibernateSessionManager.Instance.BeginTransaction();
}
public void EndSession()
{
NHibernateSessionManager.Instance.CommitTransaction();
NHibernateSessionManager.Instance.CloseSession();
}
public void RollBackSession()
{
NHibernateSessionManager.Instance.RollbackTransaction();
}
#region Implementation of IDisposable
public void Dispose()
{
// if an Exception was NOT thrown then commit the transaction
if (Marshal.GetExceptionCode() == 0)
{
NHibernateSessionManager.Instance.CommitTransaction();
}
else
{
NHibernateSessionManager.Instance.RollbackTransaction();
}
CloseSession();
}
#endregion
}
}
And to use the above class you'd do something like this:
[Test]
public void GetByIdTest()
{
// begins an nhibernate session and transaction
using (new NhibernateSessionModule())
{
IMyCustomer myCust = MyCustomerDao.GetById(123);
Assert.IsNotNull(myCust);
} // ends the nhibernate transaction AND the session
}
Note: If you're using this method make to sure to not wrap your sessions in "using" statements when executing queries from your Dao classes like in this post. Because you're managing sessions yourself and keeping them open a littler longer that a single session per query, then you need to get rid of all the places you are closing the session and let the NhibernateSessionModule do that for you (web apps or windows apps).