Asp.net web api with autofac and Hangfire - autofac

I recently upgraded to a new version of Hangfire and I am struggeling trying to setup my webapi with autofac and Hangfire. I'm using Autofac Hangfire integration version 1.1 and Hangfire 1.4.2. I'm using Owin to host. I keep getting following error:
The requested service 'IFoo' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
Here is my owin startup configuration. All my registrations are made in the AutofacStandardModule class
public class Startup
{
public void Configuration(IAppBuilder app)
{
//we will have the firewall block all CE endpoints from the outside instead
//ConfigureOAuthTokenConsumption(app);
var storage = new SqlServerStorage("connection string");
JobStorage.Current = storage;
app.UseHangfireServer(new BackgroundJobServerOptions(),storage);
app.UseHangfireDashboard("/Hangfire",new DashboardOptions(),storage);
var builder = new ContainerBuilder();
builder.RegisterModule(new AutofacStandardModule());
var container = builder.Build();
GlobalConfiguration.Configuration.UseAutofacActivator(container);
}
}
Also, here is my web api config class. I dont see how I should be configuring Hangfire here also though..
public static class WebApiConfig
{
public static void Register(HttpConfiguration config, Autofac.Module moduleToAppend)
{
config.MapHttpAttributeRoutes();
config.EnableCors();
config.EnableSystemDiagnosticsTracing();
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(
Assembly.GetExecutingAssembly())
.Where(t =>
!t.IsAbstract && typeof(ApiController).IsAssignableFrom(t))
.InstancePerLifetimeScope();
builder.RegisterModule(
new AutofacStandardModule());
if (moduleToAppend != null)
{
builder.RegisterModule(moduleToAppend);
}
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(
container);
//Hangfire.GlobalConfiguration.Configuration.UseAutofacActivator(container);
//JobActivator.Current = new AutofacJobActivator(container);
}
}

I solved the issue, it seemed I hadn't specified clearly enough which type my job was when enqueuing.
What is did was to change
_jobClient.Enqueue(
() => _foo.Bar(fooId, fooId2));
..into..
_jobClient.Enqueue<IFoo>(x => x.Bar(fooId, fooId2));

Related

autofac webapi owin integration problems with middleware exection order not correct

I'm confused with Autofac Examples : WebApiExample.OwinSelfHost, the startup class is following:
public class Startup
{
public void Configuration(IAppBuilder app)
{
// In OWIN you create your own HttpConfiguration rather than
// re-using the GlobalConfiguration.
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(
"DefaultApi",
"api/{controller}/{id}",
new { id = RouteParameter.Optional });
var builder = new ContainerBuilder();
// Register Web API controller in executing assembly.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// OPTIONAL - Register the filter provider if you have custom filters that need DI.
// Also hook the filters up to controllers.
builder.RegisterWebApiFilterProvider(config);
builder.RegisterType<CustomActionFilter>()
.AsWebApiActionFilterFor<TestController>()
.InstancePerRequest();
// Register a logger service to be used by the controller and middleware.
builder.Register(c => new Logger()).As<ILogger>().InstancePerRequest();
// Autofac will add middleware to IAppBuilder in the order registered.
// The middleware will execute in the order added to IAppBuilder.
builder.RegisterType<FirstMiddleware>().InstancePerRequest();
builder.RegisterType<SecondMiddleware>().InstancePerRequest();
// Create and assign a dependency resolver for Web API to use.
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// The Autofac middleware should be the first middleware added to the IAppBuilder.
// If you "UseAutofacMiddleware" then all of the middleware in the container
// will be injected into the pipeline right after the Autofac lifetime scope
// is created/injected.
//
// Alternatively, you can control when container-based
// middleware is used by using "UseAutofacLifetimeScopeInjector" along with
// "UseMiddlewareFromContainer". As long as the lifetime scope injector
// comes first, everything is good.
app.UseAutofacMiddleware(container);
// Again, the alternative to "UseAutofacMiddleware" is something like this:
// app.UseAutofacLifetimeScopeInjector(container);
// app.UseMiddlewareFromContainer<FirstMiddleware>();
// app.UseMiddlewareFromContainer<SecondMiddleware>();
// Make sure the Autofac lifetime scope is passed to Web API.
app.UseAutofacWebApi(config);
app.UseWebApi(config);
}
}
The FirstMiddleware and SecondMiddleware code was as following:
public class FirstMiddleware : OwinMiddleware
{
private readonly ILogger _logger;
public FirstMiddleware(OwinMiddleware next, ILogger logger) : base(next)
{
this._logger = logger;
}
public override async Task Invoke(IOwinContext context)
{
this._logger.Write("Inside the 'Invoke' method of the '{0}' middleware.", GetType().Name);
await Next.Invoke(context);
}
}
public class SecondMiddleware : OwinMiddleware
{
private readonly ILogger _logger;
public SecondMiddleware(OwinMiddleware next, ILogger logger) : base(next)
{
this._logger = logger;
}
public override async Task Invoke(IOwinContext context)
{
this._logger.Write("Inside the 'Invoke' method of the '{0}' middleware.", GetType().Name);
await Next.Invoke(context);
}
}
According to the comments, the middleware registration order matters. FirstMiddleware first, then SecondMiddleware. but the output was second middleware was invoked first.
the program logs output here
What's wrong with the order?
This is the autofac official example.WebApiExample.OwinSelfHost
Looks like you've found a bug! I've filed an issue about it on your behalf. You can read more technical details about it there, but the short version is that over the years we've changed some Autofac internals to support .NET Core and this looks like something we've missed.
The workaround until this is fixed will be to register the middleware in reverse order, which isn't awesome because once the fix is applied you'll have to reverse them back. :(

How do I get a list of registered services in Autofac

In the Microsoft.Extensions.DependencyInjection,I can:
public static IServiceCollection BuildAopProxy(this IServiceCollection service)
{
foreach (ServiceDescriptor item in service)
{}
}
How do I get which registered components in Autofac?
The set of all registrations can be found in the ComponentRegistry, available in the container and any nested scopes:
var builder = new ContainerBuilder();
builder.RegisterType<MyType>();
var container = builder.Build();
// Here is the list you want.
container.ComponentRegistry.Registrations;
If you actually want to resolve all providers of a specific service, you can just resolve an IEnumerable<TService>:
var builder = new ContainerBuilder();
// Two implementations of the same service.
builder.RegisterType<MyTypeA>().As<IService1>();
builder.RegisterType<MyTypeB>().As<IService1>();
var container = builder.Build();
// This will return a set with 2 items.
container.Resolve<IEnumerable<IService1>>();

Large number of SQL Active Sessions when injecting DBContext using Autofac in WebApi

I'm using Autofac for injecting dependencies in Web Api.
I set InstancePerRequest scope for EF DBContext.
Autofac Wiring up configuration:
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
var config = new HttpConfiguration();
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).InstancePerRequest();
var asmb = typeof (TrafficDataService).Assembly;
builder.RegisterAssemblyTypes(asmb).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerRequest();
builder.RegisterType<TrafficServiceGlobalContext>().As<IUnitOfWork>().InstancePerRequest();
builder.RegisterType<EMSEntities>().As<IEmsDataModel>().InstancePerRequest();
builder.RegisterType<ViolationTrafficEntities>().As<IViolationDataModel>().InstancePerRequest();
builder.RegisterType<TrafficController>().As<IHttpController>().InstancePerRequest();
builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).InstancePerRequest();
builder.Register(c => app.GetDataProtectionProvider()).InstancePerRequest();
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
WebApiConfig.Register(config);
}
After Service gets huge number of request, and when checking Active Sessions for my DB i see 500 Active Sessions over db.
Is really this a problem?
How to implement Connection Pooling?
Any idea?
Update:
All relevant classes depends on interfaces.
As Yacoub Massad asked in comments area, here is some of relevant classes signature and constructors:
public partial class ViolationTrafficEntities : DbContext, IViolationDataModel
{
.
.
.
}
public class TrafficDataService : ITrafficDataService
{
private readonly IViolationDataModel _violationDataModel;
public TrafficDataService(IViolationDataModel violationDataModel)
{
_violationDataModel = violationDataModel;
}
}

ASP.NET 5 beta8 Custom File Provider with Autofac

We have a default ASP.NET Web Application in which we want to use a custom file provider.
public class CustomFileProvider : IFileProvider
{
public IDirectoryContents GetDirectoryContents(string subpath)
{
...
}
public IFileInfo GetFileInfo(string subpath)
{
...
}
public IChangeToken Watch(string filter)
{
...
}
}
When we configure the provider using the following code it works fine and the custom file provider gets called by the framework.
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container.
services.AddMvc();
services.Configure<RazorViewEngineOptions>(options =>
{
// replace the fileprovider with the custom file provider
options.FileProvider = new CustomFileProvider();
});
}
When we extend the configuration with a custom di container like Autofac the custom file provider isn't called anymore. This used to work fine in beta5.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container.
services.AddMvc();
services.Configure<RazorViewEngineOptions>(options =>
{
// replace the fileprovider with the custom file provider
options.FileProvider = new CustomFileProvider();
});
// Create the Autofac container builder.
var builder = new ContainerBuilder();
// Populate the services.
builder.Populate(services);
// Build the container.
var container = builder.Build();
// Resolve and return the service provider.
return container.Resolve<IServiceProvider>();
}
Did something change on how to use a custom file provider?
There is an existing issue with the Autofac integration that is being worked through that addresses this exact thing.

SignalR issues with SignalR.Ninject and overiding the IConnectionIdFactory

I have all the Nuget Bits for SignalR , I am trying to use my own clientIDs as well as the dependency Injection container that comes with SignalR for all my other repositories and such. Now the strange thing is this jQuery to connect to the hub fails on:
debugger;
// Proxy created on the fly
var chat = $.connection.chat;
Basically, the chat object becomes undefined as if SignalR cannot be resolved. This started happening once I tried to overide the default resolver for SignalR with the code below.
What am I missing here?
Another issue I am having is I am not sure if my UserClientIDfactory which implements IConnectionIdFactory
is working either.
Here is the MVC3 code in my Global.asax
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
RegisterServices(kernel);
return kernel;
}
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<UserIdClientIdFactory>()
.To<UserIdClientIdFactory>()
.InRequestScope();
//Rest of the other stuff to inject
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
//ninject calls to create the kernal etc
IKernel kernel = CreateKernel();
//TO DO using signal IR resolver
var resolver = new NinjectDependencyResolver(kernel);
SignalR.Hosting.AspNet.AspNetHost.SetResolver(resolver);
}
Finally, here is the code for my custom clientIDfactory
public class UserIdClientIdFactory : IConnectionIdFactory
{
#region IConnectionIdFactory Members
string IConnectionIdFactory.CreateConnectionId(SignalR.Hosting.IRequest request)
{
// get and return the UserId here, in my app it is stored
// in a custom IIdentity object, but you get the idea
return HttpContext.Current.User.Identity.Name != null ?
//TO DO change to get profileID from Appfabric or the database and log user infor
HttpContext.Current.User.Identity.Name.ToString() :
Guid.NewGuid().ToString();
}
#endregion
}
As I read your question you ask how to do proper dependency injection in ASP.NET MVC and SignalR using the same DI container (and hence only need to declare bindings in one place). If this is correct understood, I once wrote a blog post regarding this: http://lcdev.dk/2012/02/14/using-signalr-ninject-with-asp-net-mvc3-and-the-ninject-mvc3-nuget-package/
In the blog post I assume that you are using ASP.NET MVC3 as well as the Ninject.MVC3 and the SignalR.Ninject Nuget packages.
However, if this is not the case I do have a comment to your code. To me it seems like that the kernel used to make your bindings (in RegisterServices) is not the kernel you actually register with SignalR. And if this is the case, then of course SignalR won't know about your intended bindings and might throw an exception as result of your use of an un-instantiated object reference -> which then might explain why you no longer can connect to your SignalR hub.
ok thanks for the your post man, made me do some more digging , I read the rest of the post you linked about how to use Ninject with MVC3 which lead me to realize that I had ninject but not the Nuget Bits for Ninject Mvc3 , I added that and alos modifed my global.asax using the following post
http://www.planetgeek.ch/2010/11/13/official-ninject-mvc-extension-gets-support-for-mvc3/
here is the working code in gloabal.asax I also removed the bootstrapper that NinJect mvc3 added to the application start folder since that is how it works in the above post
public class MvcApplication : NinjectHttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//routes.IgnoreRoute("{*allaxd}", new { allaxd = #".*\.axd(/.*)?" }); //added for mango chat
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
public override void Init()
{
this.AuthenticateRequest += new EventHandler(MvcApplication_AuthenticateRequest);
this.PostAuthenticateRequest += new EventHandler(MvcApplication_PostAuthenticateRequest);
base.Init();
}
#region "Ninject stuff for dependancy Injection
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
// kernel.Load(Assembly.GetExecutingAssembly());
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<UserIdClientIdFactory>()
.To<UserIdClientIdFactory>()
.InRequestScope();
SignalR.Hosting.AspNet.AspNetHost.DependencyResolver.Register(typeof(IConnectionIdFactory), () => new UserIdClientIdFactory());
}
#endregion
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
//for project awesome
ModelMetadataProviders.Current = new AwesomeModelMetadataProvider();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}