Why Signalr does not stable all time? - asp.net-mvc

I am workign witha a signalr project using .Net framework 4.6. And I have a base controller:
public abstract class Base<THub> : ApiController where THub : IHub
{
private static readonly Func<IHubContext> ValueFactory = () => GlobalHost.ConnectionManager.GetHubContext<THub>();
private readonly Lazy<IHubContext> hub = new Lazy<IHubContext>(ValueFactory);
protected IHubContext Hub => hub.Value;
}
SO I am creating my Notification controller from Base.
public class NewsController : Base<NotificationHub>{
public async Task<IHttpActionResult> CreateNews(string name){
// connect database
// create news on database
....
Hub.Clients.All.send(name);
}
}
And I am connecting this hub from my desktop applicaiton. I am creating news using CreateNews(string name)action, this action sends notification at first few attempts.
And then it does not send a few attempts, and some times later again sends notification to client.
[HubName("notification")]
public class NotificationHub: Hub
{
private static readonly ConnectionMapping<string> Connections = new ConnectionMapping<string>();
public override Task OnConnected()
{
var name = Context.User.Identity.Name;
Connections.Add(name, Context.ConnectionId);
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
var name = Context.User.Identity.Name;
Connections.Remove(name, Context.ConnectionId);
return base.OnDisconnected(stopCalled);
}
public override Task OnReconnected()
{
var name = Context.User.Identity.Name;
if (!Connections.GetConnections(name).Contains(Context.ConnectionId))
{
Connections.Add(name, Context.ConnectionId);
}
return base.OnReconnected();
}
}
I set break points in my desktop client, there is no error or connection failures. It always works. But notifications does not send all time called CreateNews(string name)action.
What are the possible causes?

Whenever your desktop application start, you need to add that connectionid in your hub class object. so you need to implement your signalR object in desktop app as well.
so now when you create news from the desktop app, it will call hub class directly where you will get all active connections, where you want to send notification.
so you need to implement signalR Both side.

Related

Can't get EventAggregator working with AutoFac in ASP.NET

I have a need for a simple EventAggregator in my ASP.NET MVC application where I'm using AutoFac. I've had a look at https://github.com/NimaAra/Easy.MessageHub - I really like the simplicity and lightweight as I feel a complete service bus implementation might be overkill for my needs. But I'm all ears if someone has a better approach :)
However - I can't seem to get the setup to work with my web application. I have a very simple setup:
HomeController (just to initiate the call)
public class HomeController : Controller
{
private readonly IPublishStuffService _publishStuffService;
private readonly IMessageHub _hub;
public HomeController(IPublishStuffService publishStuffService, IMessageHub hub)
{
_publishStuffService = publishStuffService;
_hub = hub;
_hub.RegisterGlobalHandler((type, eventObject) => Debug.WriteLine($"Type: {type} - Event: {eventObject}"));
}
public ActionResult Index()
{
_publishStuffService.PublishStuff("Hello world");
return View();
}
}
The PublishStuffService
public class PublishStuffService : IPublishStuffService
{
private readonly IMessageHub _hub;
public PublishStuffService(IMessageHub hub)
{
_hub = hub;
}
public void PublishStuff(string message)
{
_hub.Publish(message);
}
}
SubscribeToStuffService
public class SubscribeToStuffService : ISubscribeToStuffService
{
private readonly IMessageHub _hub;
public SubscribeToStuffService(IMessageHub hub)
{
_hub = hub;
_hub.Subscribe<string>(HandleSubscription);
}
public void HandleSubscription(string message)
{
Debug.WriteLine("===================");
Debug.WriteLine(message);
Debug.WriteLine("===================");
}
}
My GlobalHandler prints out the message "Hello world" fine - but my subscribing service never gets called. I'm figuring it might be a problem with my AutoFac setup - but I'm unsure how to handle the situation.
My AutoFac configuration (using AutoFac.MVC5) looks like this:
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(HomeController).Assembly);
builder.RegisterModelBinders(typeof(HomeController).Assembly);
builder.RegisterModelBinderProvider();
builder.RegisterModule<AutofacWebTypesModule>();
builder.RegisterSource(new ViewRegistrationSource());
builder.RegisterFilterProvider();
// Register individual components
builder.RegisterType(typeof(SubscribeToStuffService)).As<ISubscribeToStuffService>().InstancePerLifetimeScope();
builder.RegisterType(typeof(PublishStuffService)).As<IPublishStuffService>().InstancePerLifetimeScope();
builder.RegisterType(typeof(MessageHub)).As<IMessageHub>().SingleInstance();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
Can anyone help me figure out how to ensure that the message hub is persisted across my entire web application so that I can have different classes subscribe to different events published to the message hub.
Basically I'm looking for the Notification part of Jimmy Bogards Mediatr library - which works perfect by the way - but I feel that the implementation of Mediatr might be a bit much if I only intend to use the Notification setup :)
UPDATE
I can actually get the subscriber events to fire if I add a dependency to ISubscribeToStuffService in the same place as I publish (here in my HomeController):
public class HomeController : Controller
{
private readonly IPublishStuffService _publishStuffService;
private readonly IMessageHub _hub;
private readonly ISubscribeToStuffService _subscribeToStuffService;
public HomeController(IPublishStuffService publishStuffService, IMessageHub hub, ISubscribeToStuffService subscribeToStuffService)
{
_publishStuffService = publishStuffService;
_hub = hub;
_subscribeToStuffService = subscribeToStuffService;
}
...
}
This apparently resolves the subscriber. But that's not really helpful as it defeats the purpose of have a loose coupling between my dependencies.
So the question becomes - how do I get AutoFac to resolve my subscribers without having to add them as dependencies everywhere I publish something to the message bus? Can this be done?
UPDATE 2
Found this nifty little pub/sub extension for AutoFac: https://github.com/jonstelly/AutofacEvents. It does everyting I need right out of the box in terms of getting an event aggregator up and running with AutoFac.

Can't call web api controller inside the signalr OnDisconnected method

I have an mvc web apllication with signalr and i want to update the table in the published web api.
calling web api controller to get users inside the Onconnected method works fine:
public override async Task OnConnected()
{
var users = await _client.GetAsync("chats/users");
Clients.All.userConnected();
}
But when i place the code inside the OnDisconnected method it gives me an error:
public override async Task OnDisconnected(bool stopCalled)
{
var users = await _client.GetAsync("chats/users");
}
Why is this happening? this is the whole Hub code:
private static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
private HttpClient _client;
public ChatHub()
{
AccessDelegatingHandler handler = new AccessDelegatingHandler();
_client = HttpClientFactory.Create(handler);
_client.BaseAddress = new Uri(ClsConfig.GetConfiguration().APIBaseAddress);
}
// Send new message to group chat.
public static void SendGroupMessage(MessageDetailModel messageDetail)
{
hubContext.Clients.All.newGroupMessageReceived(messageDetail);
}
public override async Task OnConnected()
{
var users = await _client.GetAsync("chats/users");
Clients.All.userConnected();
}
public override Task OnReconnected()
{
return base.OnReconnected();
}
public override async Task OnDisconnected(bool stopCalled)
{
var users = await _client.GetAsync("chats/users");
}
EDIT:
I found out that when i place var user = Context.User.Identity; inside the OnDisconnected method the user is IsAuthenticated = true but when i place a break point inside the AccessDelegatingHandler class the var identity = (ClaimsIdentity)HttpContext.Current.User.Identity; line gives an error and is IsAuthenticated = false
By the time the onDisconnected event fires, you are likely already disconnected, and there is no guarantee that your code will run, (its a known issue with Signalr) also are you monitoring the onDisconnected in the client or the server? It looks like you are trying to handle it from the server, and you should be handling it from the client.
This link should help to understand why this is the way it is.
https://learn.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/handling-connection-lifetime-events#clientdisconnect

Configure Unity container per-request in OWIN middleware

I'm wanting to configure registrations in a Unity container being used by ASP.NET Web API 2 based on properties of a HTTP request. For example, a request to /api/database1/values should result in a Unity container configuration with an IDbContext configured for database1, while a request to /api/database4/values will get an IDbContext configured for database4.
I've gotten so far as using UnityHierarchicalDependencyResolver as the dependency resolver, so types registered with HierarchicalLifetimeManager last only for the lifetime of the request. This works well for getting types resolved per request. But how to get them registered per request using OWIN middleware is beyond me.
In my middleware, a call to System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IUnityContainer)) gets an instance of IUnityContainer, but it's the same container for all requests, including any registrations from previous requests.
By encapsulating UnityHierarchicalDependencyResolver with my own implementation of IDependencyResolver I can see that IDependencyResolver.BeginScope isn't called until much later in the process. So the problem would seem to be that the child container isn't created until Web API wakes up, long after my middleware calls Next(..).
Is there a way I can get the scope of my dependency resolver to start sooner? Is there some other strategy that I'm missing. In case it makes any difference, I'm hosting in IIS, but favouring the OWIN middleware approach.
Update
This isn't an answer, and it's too big for a comment, but after struggling to solve this with Unity I decided to switch to Autofac and it all just fell into place.
The Autofac OWIN packages (Autofac.Mvc5.Owin, Autofac.Owin, Autofac.WebApi2.Owin) make it dead easy to use Autofac within the OWIN pipeline and ensure appropriate lifetime management in ASP.NET MVC and Web API. This was the missing link.
I couldn't find a way to reconfigure the container per-request, but it did at least make it possible to configure a factory per-request (so yes, #Haukinger and #alltej, you were right to push in that direction.
So I register a factory like:
builder.RegisterType<DataDependencyFactory>().InstancePerRequest();
And register the create method of that factory like:
builder
.Register(c => c.Resolve<DataDependencyFactory>().CreateDataDependency())
.As<IDataDependency>()
.InstancePerRequest();
Registering the factory this way is particularly useful, because downstream dependents don't need to be aware of the factory. I like this because my dependents don't need a factory, they need an instance. The container bends to the needs of my dependents, not the other way around :)
Then, in a piece of OWIN middleware, I resolve the factory, and set a property on it according to the properties of the request. Subsequent resolution of IDataDependency in an MVC or Web API controller, or anything else later in the OWIN pipeline, will get an instance configured according to the property on the factory.
Based on your api URL ("/api/database4/values"), I suggest that you create a filter attribute(e.g. DbIdFilter) so that you can reuse the filter attribute to other controller methods that follow similar url path/segment like this below:
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/values")]
public IHttpActionResult GetValues()
{
return Ok();
}
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/products")]
public IHttpActionResult GetProducts()
{
return Ok();
}
First, create the filter attribute:
public class DbIdFilterAttribute : ActionFilterAttribute
{
private readonly string _routeDataId;
private const string defaultRouteName = "databaseId";
public DbIdFilterAttribute():this(defaultRouteName)
{}
public DbIdFilterAttribute(string routeDataId)
{
_routeDataId = routeDataId;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
var routeData = actionContext.Request.GetRouteData();
var dbId = routeData.Values[_routeDataId] as string;
//here we create the db instance at the filter level.
DbInstanceFactory.RegisterDbInstance(dbId);
}
}
Next, create an instance factory that will register/resolve the db instance during runtime:
public class DbInstanceFactory : IDbInstanceFactory
{
public static IDbInstance RegisterDbInstance(string databaseId)
{
var factory = UnityConfig.GetConfiguredContainer().Resolve<IDbInstanceFactory>();
return factory.CreateInstance(databaseId);
}
public IDbInstance CreateInstance(string databaseId)
{
var container = UnityConfig.GetConfiguredContainer();
//container.RegisterType<IDbInstance, DbInstance>();
container.RegisterType<IDbInstance, DbInstance>(new InjectionConstructor(databaseId));
var dbInstance = container.Resolve<IDbInstance>();
return dbInstance;
}
public IDbInstance GetInstance()
{
var container = UnityConfig.GetConfiguredContainer();
var dbInstance = container.Resolve<IDbInstance>();
return dbInstance;
}
}
public interface IDbInstanceFactory
{
IDbInstance CreateInstance(string databaseId);
IDbInstance GetInstance();
}
Register this factory class in UnityConfig.cs (or wherever you currently register the types):
container.RegisterType<IDbInstanceFactory, DbInstanceFactory>
(new ContainerControlledLifetimeManager());
It's registered ContainerControlledLifetimeManager since this factory does not have to be a per request.
So just a basic DbInstance class below(for clarity) that takes a parameter in the constructor (this parameter can be your connection string or a named connection):
public class DbInstance : IDbInstance
{
public string DbId { get; }
public DbInstance(string databaseId)
{
DbId = databaseId;
}
}
public interface IDbInstance
{
string DbId { get; }
}
In controller class, you can use it like this:
....
private IDbInstanceFactory _dbFactory;
public MyController(IDbInstanceFactory dbFactory)
{
_dbFactory = dbFactory;
}
// Alternate, if you want to use property injection instead of constructor injection
//[Dependency]
//public IDbInstanceFactory DbFactory { get; set; }
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/test")]
public IHttpActionResult Test()
{
var db = _dbFactory.GetInstance();
return Ok(db.DbId);
}
...

NHibernate session is closed when refreshing page

This is another strange problem I've encountered this days!!! I've created and MVC 4 app using nhibernate. and added a filter attribute named [LoggingNHibernateSessionAttribute] on my HomeController which manages session for each action. I've followed 'ASP.NET MVC4 and the Web API published by Apress'.
public class LoggingNHibernateSessionAttribute : ActionFilterAttribute
{
private readonly IActionLogHelper _actionLogHelper;
private readonly IActionExceptionHandler _actionExceptionHandler;
private readonly IActionTransactionHelper _actionTransactionHelper;
public LoggingNHibernateSessionAttribute()
: this(WebContainerManager.Get<IActionLogHelper>(),
WebContainerManager.Get<IActionExceptionHandler>(),
WebContainerManager.Get<IActionTransactionHelper>())
{
}
public LoggingNHibernateSessionAttribute(
IActionLogHelper actionLogHelper,
IActionExceptionHandler actionExceptionHandler,
IActionTransactionHelper actionTransactionHelper)
{
_actionLogHelper = actionLogHelper;
_actionExceptionHandler = actionExceptionHandler;
_actionTransactionHelper = actionTransactionHelper;
}
public override void OnActionExecuting(ActionExecutingContext actionExectingContext)
{
_actionLogHelper.LogEntry(actionExectingContext.ActionDescriptor);
_actionTransactionHelper.BeginTransaction();
}
public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
{
_actionTransactionHelper.EndTransaction(actionExecutedContext);
_actionTransactionHelper.CloseSession();
_actionExceptionHandler.HandleException(actionExecutedContext);
_actionLogHelper.LogExit(actionExecutedContext.ActionDescriptor);
}
}
ActionTransactionHelper
public class ActionTransactionHelper : IActionTransactionHelper
{
private readonly ISessionFactory _sessionFactory;
private readonly ICurrentSessionContextAdapter _currentSessionContextAdapter;
public ActionTransactionHelper(
ISessionFactory sessionFactory,
ICurrentSessionContextAdapter currentSessionContextAdapter)
{
_sessionFactory = sessionFactory;
_currentSessionContextAdapter = currentSessionContextAdapter;
}
public void BeginTransaction()
{
var session = _sessionFactory.GetCurrentSession();
if (session != null)
{
session.BeginTransaction();
}
}
public bool TransactionHandled { get; private set; }
public void EndTransaction(ActionExecutedContext filterContext)
{
var session = _sessionFactory.GetCurrentSession();
if (session == null) return;
if (!session.Transaction.IsActive) return;
if (filterContext.Exception == null)
{
session.Flush();
session.Transaction.Commit();
}
else
{
session.Transaction.Rollback();
}
TransactionHandled = true;
}
public bool SessionClosed { get; private set; }
public void CloseSession()
{
if (_currentSessionContextAdapter.HasBind(_sessionFactory))
{
var session = _sessionFactory.GetCurrentSession();
session.Close();
session.Dispose();
_currentSessionContextAdapter.Unbind(_sessionFactory);
SessionClosed = true;
}
}
}
when run the app, I can save an entity in the dataBase. but when I hit refresh button and exception thrown indication session is closed.
I don't know why this happens. (I searched and find this NHibernate throwing Session is closed but couldn't solve my problem).
in my NinjectConfigurator I added inRequestScope() to all of injections but no answer. I checked when I refresh the page session will be opened. but I donnow why it say session is closed?!
UPDATE:
when I first run the app. I can create a new member. but when I hit the refresh button, the session will be closed unexpectedly!!
first run:
everything works well
after hitting refresh button:
a new session bind to the current context.
the new session will be injected the repository (session is open)
the ActionTransactionHelper calls beginTransaction()
4- customMembership createUser (....) called
5- but when the _userRepositoy.save(user)called in the repository session is closed!!!!
note:but when still endTransaction and closeSession isn't called. but how session is closed?
if I comment closeSession() in onActionExecute(). session alway is open and everything woks well if refresh the page.
I checked a lot and tried different way I knew. it only happens when for the second time I want to do CRUD operations with my customMembership.
for other entities it works like a charm!
I have upoaded my sample code. for testing just create and empty database and change connection string. then go to localHost:*****/api/categories (user and pass doesn't required)
Download sample project:
Size: 47 MB
https://www.dropbox.com/s/o63wjng5f799fii/Hashem-MVC4ServicesBook.rar
size: 54 MB
Zip Format: https://www.dropbox.com/s/smrsbz4cbtznx1y/Hashem-MVC4ServicesBook2.zip
A very important thing here, could be the nature of the NHibernate. The NHibernate and its Session are in the ASP.NET MVC living longer, then could be expected. I mean not only inside of the
ActionExecuting (Controller Action starts)
ActionExecuted (the View or Redirect is called)
Session in fact must live also through the phase of rendering. Because, we could load some proxy in the "Action()" but its collection, could be lazily loaded only during the View rendering. So even in these phases Session must be opened (the same Session from the request begining)
ResultExecuting (the proxy could start to be loaded only here)
ResultExecuted (almost all is done, let's close the session)
Other words... keep the session opened throught the complete Request. From authorization untill the content is rendered.
NOTE: Anohter hint, just to be sure that all is ok, I am using this scenario (maybe you do as well):
Client FORM is about to send the data to server. The method is POST, the Action is Update()
Sent FORM is coming to server, Action Update() is triggerred - all the transactions stuff is in place (as described above)
Once NHibernate persists the data into DB, the Update() action ends, and is redirected to action
Detail() if all is ok or
Edit() if something goes wrong
The users Browser was redirected to action Detail or Edit. So if user does REFRESH, the Detail or Edit is refreshed. The Update() is not called at all (it is a POST method)
In fact, the step 1. was one of the Actions Detail or Edit. In this case, we would face this issue already...
You have this error since Asp.Net MVC does not create a new instance of LoggingNHibernateSessionAttribute every request. It creates a new instance when you request an action first time and then uses this instance in the future.
The behaviour is the following:
First invocation of Post -> new instance of 'LoggingNHibernateSession' is created
First invocation of Put -> another one instance of 'LoggingNHibernateSession' is created
Second invocation of Put -> instance of 'LoggingNHibernateSession' from previous step is used
First invocation of Delete -> another one instance of 'LoggingNHibernateSession' is created
[LoggingNHibernateSession]
public JsonResult Post(Dto data)
{
/* ... */
}
[LoggingNHibernateSession]
public JsonResult Put(int id, Dto data)
{
/* ... */
}
[LoggingNHibernateSession]
public JsonResult Delete(int id)
{
/* ... */
}
It can be solved using Func<IActionLogHelper> instead of IActionLogHelper in the constructor. An instance of IActionLogHelper can be initialised within OnActionExecuting method.
public class LoggingNHibernateSessionAttribute : ActionFilterAttribute
{
/* your code */
private readonly Func<IActionTransactionHelper> _getActionTransactionHelper;
private IActionTransactionHelper _actionTransactionHelper;
public LoggingNHibernateSessionAttribute()
: this(WebContainerManager.Get<IActionLogHelper>(),
WebContainerManager.Get<IActionExceptionHandler>(),
() => WebContainerManager.Get<IActionTransactionHelper>())
{
}
public LoggingNHibernateSessionAttribute(
IActionLogHelper actionLogHelper,
IActionExceptionHandler actionExceptionHandler,
Func<IActionTransactionHelper> getActionTransactionHelper)
{
_actionLogHelper = actionLogHelper;
_actionExceptionHandler = actionExceptionHandler;
_getActionTransactionHelper = getActionTransactionHelper;
_actionTransactionHelper = null;
}
public override void OnActionExecuting(ActionExecutingContext actionExectingContext)
{
_actionTransactionHelper = _getActionTransactionHelper();
_actionLogHelper.LogEntry(actionExectingContext.ActionDescriptor);
_actionTransactionHelper.BeginTransaction();
}
/* your code */
}

Timer events in ASP.NET MVC

Problem: user operates over some entity in a domain. The last one changes its status so that user recieves e-mail notifications (using smtp server) repeatedly until the given time.
So I need to fire an event somehow.
What are the alternative ways to do that? I know there're no events in ASP.NET MVC framework.
Thanks!
You can use my Inversion Of Control container which has built in support for in-process domain events:
Subscribing
Subscribing is easy. Simply let any class implement IHandlerOf:
[Component]
public class ReplyEmailNotification : IHandlerOf<ReplyPosted>
{
ISmtpClient _client;
IUserQueries _userQueries;
public ReplyEmailNotification(ISmtpClient client, IUserQueries userQueries)
{
_client = client;
_userQueries = userQueries;
}
public void Invoke(ReplyPosted e)
{
var user = _userQueries.Get(e.PosterId);
_client.Send(new MailMessage(user.Email, "bla bla"));
}
}
Dispatching
Domain events are dispatched using the DomainEvent class. The actual domain event can be any class, there are no restrictions. I do however recommend that you treat them as DTO's.
public class UserCreated
{
public UserCreated(string id, string displayName)
{
}
}
public class UserService
{
public void Create(string displayName)
{
//create user
// [...]
// fire the event.
DomainEvent.Publish(new UserCreated(user.Id, user.DisplayName));
}
}
The code is from my article: http://www.codeproject.com/Articles/440665/Having-fun-with-Griffin-Container
ASP.NET MVC3 installation:
Use package manager console: install-package griffin.container.mvc3
Follow these instructions: http://griffinframework.net/docs/container/mvc3/

Resources