SignalR Hub ResolutionFailedException with Unity - asp.net-mvc

I am getting a really annoying ResolutionFailedException error when trying to resolve a SignalR hub using Unity in an MVC web application. My code is displayed below.
My Bootstrapper Class
public static class Bootstrapper
{
public static IUnityContainer Initialise()
{
var container = BuildUnityContainer();
var unityDependencyResolver = new UnityDependencyResolver(container);
//Used for MVC
DependencyResolver.SetResolver(unityDependencyResolver);
//Used for SignalR
GlobalHost.DependencyResolver = new SignalRUnityDependencyResolver(container);
return container;
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
RegisterTypes(container);
return container;
}
public static void RegisterTypes(IUnityContainer container)
{
//Repositories
container.RegisterType<ChatMessageRepository>();
//Services
container.RegisterType<CapturePoolService>();
container.RegisterType<HistoricalDataService>();
//Context
container.RegisterType<ICustomPrincipal, CustomPrincipal>(new PerRequestLifetimeManager());
container.RegisterType<IDatabaseFactory, DatabaseFactory>(new PerRequestLifetimeManager());
container.RegisterType<UnitOfWork>(new PerRequestLifetimeManager());
//Hubs
container.RegisterType<ChatHub>(new InjectionFactory(CreateChatHub));
}
private static object CreateChatHub(IUnityContainer container)
{
return new ChatHub(container.Resolve<ChatMessageRepository>(), container.Resolve<UnitOfWork>());
}
}
My Chat Hub
public class ChatHub : Hub
{
private readonly ChatMessageRepository _chatMessageRepository;
private readonly UnitOfWork _unitOfWork;
public ChatHub(
ChatMessageRepository chatMessageRepository,
UnitOfWork unitOfWork)
{
_chatMessageRepository = chatMessageRepository;
_unitOfWork = unitOfWork;
}
}
Now, I have a few different views which each use an instance of the Chat Hub (e.g. think of it as separate chat rooms which all utilized the same logic written in my hub). When I go into one of these "rooms" my logic works as expected. However, the problem arises when I leave that page and go to any other page in my application. Here's the error:
Resolution of the dependency failed, type = "Core.Repositories.ChatMessageRepository", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - Operation is not valid due to the current state of the object.
At the time of the exception, the container was:
Resolving Repositories.ChatMessageRepository,(none)
Resolving parameter "dbFactory" of constructor Repositories.ChatMessageRepository(Library.IDatabaseFactory dbFactory)
Resolving Context.DatabaseFactory,(none) (mapped from Library.IDatabaseFactory, (none))
Which fires from my SignalRUnityDependencyResolver
public override Object GetService(Type serviceType)
{
return _container.IsRegistered(serviceType) ? _container.Resolve(serviceType): base.GetService(serviceType);
}
Specifically the "_container.Resolve(serviceType)" call.
Can someone please help?
Thanks.

I fixed this by registering my hub with the HierarchicalLifetimeManager.

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.

Unity Error: Cannot register a module after the application has been initialized

I have asp.net mvc application and im using Unity as IoC container. The UnityWebActivator class has PreApplicationStartMethod which registers all the types with Unity container.
I want to register a singleton instance of a class whose property values are coming from the database.
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Web.App_Start.UnityWebActivator), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(Web.App_Start.UnityWebActivator), "Shutdown")]
namespace Web.App_Start
{
public static class UnityWebActivator
{
public static void Start()
{
var container = UnityConfig.GetConfiguredContainer();
FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
// Web API
//GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
}
}
and UnityConfig.cs i register all the types
public class UnityConfig
{
#region Unity Container
private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
public static IUnityContainer GetConfiguredContainer()
{
return container.Value;
}
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<DbContext, MyEntities>(new PerRequestLifetimeManager(), new InjectionFactory(x => new MyEntities()));
//register singleton
container.RegisterInstance<ApplicationSettings>(LoadApplicationSettings(container), new ContainerControlledLifetimeManager());
}
private static ApplicationSettings LoadApplicationSettings(IUnityContainer container)
{
var appSettings = new ApplicationSettings();
using (var dbContext = new MyEntities())
{
var settings = dbContext.Settings.ToList();
// populate appsettings from settings
}
}
}
The LoadApplicationSettings method above needs to get the data from the database and create the instance of ApplicationSettings class.
However LoadApplicationSettings gets invoked as PreApplicationStartMethod which is before application_start method and since DbContext is not mapped yet i get error
InvalidOperationException: Unable to determine application context.
The ASP.NET application path could not be resolved.
and:
InvalidOperationException: This method cannot be called during the
application's pre-start initialization stage.
So as per the suggestion here i did two things:
1> Remove the line [assembly: WebActivator.PreApplicationStartMethod]
2> Add a call to the UnityWebActivator.Start() method in the Application_Start() event of the global asax.
However doing so causes another error when registering UnityPerRequestHttpModule
public static void Start()
{
// removed code for brevity
// get error at line below
Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
//removed code for brevity
}
"Cannot register a module after the application has been
initialized."}
You can register ApplicationSettings using an InjectionConstructor. This will defer creation (and the loading of the settings from the database) until the first time they are resolved from the container. Presumably this should be after the application has finished bootstrapping.
Here is the new registration:
//register singleton
container.RegisterType<ApplicationSettings>(
new ContainerControlledLifetimeManager(),
new InjectionFactory(c => LoadApplicationSettings(c)));

Inconsistent accessibility parameter type error while Injecting Service to Controller-Constructor

while Injecting Service to Controller shows error "Inconsistent accessibility:parametertype 'IProductRepository' is less accessible than method 'ProductController.ProductController(IProductRepository)'"
Tools/Framework used: visualstudio_2015,mvc 4.6,and unity_Container_4
i am very new to this "IoC" , i guess i am missing something
Error code
private IProductRepository _IobjProductRepository;
//error shown in this code part
Injecting Service to Controller shows error -->
public ProductController(IProductRepository Repository)
{ _IobjProductRepository = Repository;}
<--error shown in this code par
t
BootStrapcode
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
container.RegisterType<IProductRepository,ProductRepository>();
container.RegisterType<IController,ProductController>();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
// MvcUnityContainer.Container = container;
RegisterTypes(container);
return container;
}
public static void RegisterTypes(IUnityContainer container){}
Make your IProductRepository a public interface.
public interface IProductRepository
{
// your properties & methods
}

ASP.NET nHibernate+Quartz.NET+Unity

I am developing a web application to ASP.NET MVC. To interact with the data repository is used, based on nHibernate. Repositories are instantiated through Unity. To repository resolved ISession per request.
Now I need to add to the project crawlers performing periodic scheduled tasks in the background. To implement a crawler selected Quartz.NET. A project can have several different walkers, while interacting with the database through the repository, if matches the execution of their tasks.
The problem is that the crawler must create another session, because it is based on a request solution is not working (no web request). It was implemented a solution in which I register two different implementations of the ISession, but it does not work. The code samples below.
The following questions arise:
This is correct direction of solving the problem?
How to implement it correctly?
Will not this approach two crawler trying to write to the database, to cause mistake?
Code:
public class DatabaseRepositoriesRegistration : IUnityRegistration
{
public void Register(IUnityContainer container)
{
// web
var connectionString = WebConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
SessionManager.ConnectionString = connectionString;
container.RegisterType<ISession>(new HierarchicalLifetimeManager(),
new InjectionFactory(c => SessionManager.CurrentSession)
);
container.RegisterType<IUnitOfWork, NHibernateUnitOfWork>(new HierarchicalLifetimeManager());
container.RegisterType(typeof(IRepository<>), typeof(NHibernateRepository<>), new HierarchicalLifetimeManager());
// externals
container.RegisterType<ISession>("ext", new HierarchicalLifetimeManager(), new InjectionFactory(c =>
{
var config = Fluently.Configure().
Database(
MsSqlConfiguration
.MsSql2008
.ConnectionString(connectionString)
.UseReflectionOptimizer()
)
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<MappingBeacon>())
.BuildConfiguration();
var sessionFactory = config.BuildSessionFactory();
return sessionFactory.OpenSession();
}));
container.RegisterType(typeof(IRepository<>), typeof(NHibernateRepository<>), "ext", new HierarchicalLifetimeManager(), new InjectionConstructor(new ResolvedParameter<ISession>("ext")));
}
}
public class SchedulerTask : MvcStartupTaskBase
{
private readonly IUnityContainer container;
public SchedulerTask(IUnityContainer container)
{
this.container = container;
}
public override void Run()
{
var scheduler = container.Resolve<IScheduler>();
scheduler.JobFactory = new UnityJobFactory(container);
scheduler.Start();
var job = JobBuilder.Create<UploadConvertionTask>().Build();
var trigger = TriggerBuilder.Create()
.WithDailyTimeIntervalSchedule
(s =>
s.WithIntervalInMinutes(1)
.OnEveryDay()
.StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(0, 0))
)
.Build();
scheduler.ScheduleJob(job, trigger);
}
public class UnityJobFactory : IJobFactory
{
private readonly IUnityContainer container;
public UnityJobFactory(IUnityContainer container)
{
this.container = container;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
return (IJob)container.Resolve(bundle.JobDetail.JobType, "ext");
}
public void ReturnJob(IJob job)
{
}
}
}
public class UploadConvertionTask: IJob
{
public UploadConvertionTask(IRepository<Upload> uploadRepositiory) {
// for repository session is closed!
}
public void Execute(IJobExecutionContext context)
{
}
}
Your scheduler is set up as a local variable inside the run method. It needs to be a variable that lives around long enough for the scheduler to run the task. Without knowing the details of the whole project, you should set your scheduler to be a singleton that is created when the application starts. Then, reference this singleton instance when you're scheduling jobs.
Ideally, your scheduler should be run as a separate long-running service, such as a windows service.

Resolving Unity dependency outside of application start, in libraries

I'm building an ASP.NET MVC app, and implementing Dependency Injection for the first time using Unity. For one particular interface, I've multiple types registered, like so:
container.RegisterType<ICache, AppfabricCache>("AppfabricCache", new ContainerControlledLifetimeManager());
container.RegisterType<ICache, MemoryCache>("MemoryCache", new ContainerControlledLifetimeManager());
I now need to make a decision on which one to use based on a CacheType enum.
I can implement it as follows, as is done in the Sixeyed.Caching project, but it makes you register types in different places. Also you now have a static wrapper around the container, which doesn't feel clean.
public static class Cache
{
private static readonly IUnityContainer _container;
static Cache()
{
_container = new UnityContainer();
_container.RegisterType<ICache, MemoryCache>("MemoryCache", new ContainerControlledLifetimeManager());
}
public static ICache Get(CacheType cacheType)
{
ICache cache = new NullCache();
switch(cacheType)
{
case CacheType.Memory:
cache = _container.Resolve<ICache>("MemoryCache");
break;
...
...
}
}
}
How do I get hold of the container from other library projects in my application? Or rather, how do I do this kind of resolution from libraries? Or maybe I should not?
This blog post says it is not a good idea to have the container outside of the application entry point, which sounds correct. What is the correct way to do this?
As #ploeh suggests, the container shouldn't be known outside of the application root.
To get an implementation based on a runtime value, you should use a factory:
public class CacheFactory : ICacheFactory
{
private readonly IUnityContainer _container;
public CacheFactory(IUnityContainer container)
{
if (container == null)
throw new ArgumentNullException("container");
_container = container;
}
public ICache Get(CacheType cacheType)
{
// implementation as in your post
}
}
public class SomethingUsingTheCache
{
private readonly ICacheFactory _cacheFactory;
public SomethingUsingTheCache(ICacheFactory cacheFactory)
{
if (cacheFactory == null)
throw new ArgumentNullException("cacheFactory");
_cacheFactory = cacheFactory;
}
public void DoStuff()
{
// get from config or wherever
CacheType cacheType = CacheType.Memory;
ICache cache = _cacheFactory.Get(cacheType);
// do something with cache
}
}
The factory is placed in the application root and any other class uses the factory and has no notion of the container.

Resources