Autofac MVC5 and WebAPI2.1 not working - autofac

Here is my Bootstrap in global.asax
public class Global : HttpApplication {
void Application_Start(object sender, EventArgs e) {
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
// initiate dependency injection resolver
DependencyInjectionResolver.RegisterDependencies(typeof(Global).Assembly);
}
}
Here is implementation
public class DependencyInjectionResolver {
private static IContainer _container;
public static TService Resolve<TService>() {
return DependencyResolver.Current.GetService<TService>();
}
public static void RegisterDependencies(Assembly assembly) {
var builder = new ContainerBuilder();
builder.RegisterFilterProvider();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterGeneric(typeof (Repository<>))
.As(typeof (IRepository<>))
.InstancePerHttpRequest()
.InstancePerLifetimeScope();
builder.RegisterType<LoggerService>()
.As<ILoggerService>()
.InstancePerApiRequest()
.InstancePerHttpRequest();
builder.Register(x =>
new MessageDataService(Resolve<ILoggerService>(), Resolve<IRepository<ApiRequestHistory>>()))
.As<IMessagesDataService>()
.InstancePerHttpRequest()
.InstancePerApiRequest();
#region setup
_container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(_container));
GlobalConfiguration.Configuration.DependencyResolver
= new AutofacWebApiDependencyResolver(_container);
#endregion
}
}
Here is my exception:
An error has occurred.An error occurred when trying to create a controller of type 'MessageReportController'. Make sure that the controller has a parameterless public constructor.System.InvalidOperationException at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()An error has occurred.Type 'WayToLead.Web.UI.api.MessageReportController' does not have a default constructorSystem.ArgumentException at System.Linq.Expressions.Expression.New(Type type)
at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
How to fix it to work with WebApi and Mvc controllers?

Check that you have registered all of your ApiControllers' dependencies and sub-dependencies. Somewhere deep inside the stack trace you might find exacly which dependency AutoFac wasn't able to resolve.
I'm guessing that since AutoFac couldn't satisfy all dependencies then the default dependency resolver takes over.

Related

Mvc5 Hangfire Autofac No parameterless constructor defined for this object

I have an MVC5 webapplication which uses Autofac for DI registrations.
Now im using Hangfire for background jobs. When i schedule a job, i got an error.
What am i missing in here? I followed the descriptions given bij Hangfire and Hangfire.Autofac documentation.
Exception i got:
System.MissingMethodException
No parameterless constructor defined for this object.
System.MissingMethodException: No parameterless constructor defined for this object.
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at System.Activator.CreateInstance(Type type)
at Hangfire.JobActivator.SimpleJobActivatorScope.Resolve(Type type)
at Hangfire.Server.CoreBackgroundJobPerformer.Perform(PerformContext context)
at Hangfire.Server.BackgroundJobPerformer.<>c__DisplayClass10_0.<PerformJobWithFilters>b__0()
at Hangfire.Server.BackgroundJobPerformer.InvokePerformFilter(IServerFilter filter, PerformingContext preContext, Func`1 continuation)
at Hangfire.Server.BackgroundJobPerformer.InvokePerformFilter(IServerFilter filter, PerformingContext preContext, Func`1 continuation)
at Hangfire.Server.BackgroundJobPerformer.PerformJobWithFilters(PerformContext context, IEnumerable`1 filters)
at Hangfire.Server.BackgroundJobPerformer.Perform(PerformContext context)
at Hangfire.Server.Worker.PerformJob(BackgroundProcessContext context, IStorageConnection connection, String jobId, BackgroundJob backgroundJob, IReadOnlyDictionary`2& customData)
MyJob class:
public interface IMyJob
{
void DoSomething();
}
public class MyJob : IMyJob
{
private readonly ILogger _logger;
public MyJob(ILogger logger)
{
_logger= logger;
}
public void DoSomething()
{
Console.WriteLine("Recurring!");
}
}
I am using the following versions:
Hangfire 1.7.28
Hangfire.Autofac 2.3.1
Autofac 5.2.0
I have the following Hangfire configurations:
// Startup.cs
public void Configuration(IAppBuilder app)
{
// Configure DI dependancies
Bootstrapper.SetAutofacContainer(app);
// Configure authentication
ConfigureAuth(app);
// Configure Hangfire
`Hangfire.GlobalConfiguration.Configuration.UseSqlServerStorage("DefaultConnection");
var options = new DashboardOptions { Authorization = new[] { new HangfireAuthorizationFilter() } };
app.UseHangfireDashboard("/jobs", options);
app.UseHangfireServer();`
RecurringJob.AddOrUpdate<MyJob>("MYJOB", (x) => x.DoSomething(), Cron.MinuteInterval(5));
}
// My Autofac bootstrapper class
public class Bootstrapper
{
public static void SetAutofacContainer(IAppBuilder app)
{
var builder = new ContainerBuilder();
// Register Web controllers.
builder.RegisterControllers(typeof(MvcApplication).Assembly);
// Register model binders that require DI.
builder.RegisterModelBinders(typeof(MvcApplication).Assembly);
builder.RegisterModelBinderProvider();
// Register web abstractions like HttpContextBase.
builder.RegisterModule<AutofacWebTypesModule>();
// Enable property injection in view pages.
builder.RegisterSource(new ViewRegistrationSource());
// Enable property injection into action filters.
builder.RegisterFilterProvider();
// Identity
builder.RegisterType<ApplicationUserStore>().As<IUserStore<Medewerker, Guid>>().InstancePerLifetimeScope();
builder.RegisterType<ApplicationUserManager>().AsSelf().InstancePerLifetimeScope();
builder.RegisterType<ApplicationSignInManager>().AsSelf().InstancePerLifetimeScope();
builder.Register<IAuthenticationManager>(c => HttpContext.Current.GetOwinContext().Authentication).InstancePerLifetimeScope();
builder.Register<IDataProtectionProvider>(c => app.GetDataProtectionProvider()).InstancePerLifetimeScope();
builder.RegisterType<Logger>().As<ILogger>().InstancePerLifetimeScope();
builder.RegisterType<MyJob>().AsSelf().InstancePerBackgroundJob();
// Build the container
var container = builder.Build();
Hangfire.GlobalConfiguration.Configuration.UseAutofacActivator(container);
JobActivator.Current = new AutofacJobActivator(container);
// Replace the MVC dependancy resolver with Autofac
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// Set the dependency resolver for MVC.
var mvcResolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(mvcResolver);
// Register the Autofac middleware FIRST, then the Autofac MVC middleware.
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
}
}

UnitOfWork and DbContext: thread safety with DI

I'm working on a .NET Core 2.2 Console Application that hosts an IHostedService:
public class MqttClientHostedService : IHostedService, IDisposable
{
[...]
public MqttClientHostedService(
ILogger<MqttClientHostedService> logger,
IOptions<MqttClientConfiguration> mqttConfiguration,
IPositionService positionService)
{
this.logger = logger;
this.config = mqttConfiguration;
this.positionService = positionService;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
mqttClient = new MqttFactory().CreateMqttClient();
mqttClient.Connected += async (s, e) => await MqttClient_Connected(s, e);
mqttClient.ApplicationMessageReceived +=
async (s, e) => await MqttClient_ApplicationMessageReceived(s, e);
await mqttClient.ConnectAsync(
new MqttClientOptionsBuilder()
.WithTcpServer(config.Value.Host, config.Value.Port).Build());
}
private async Task MqttClient_ApplicationMessageReceived(
object sender, MqttApplicationMessageReceivedEventArgs e)
{
string message = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
await positionService.HandleMessage(message);
}
[...]
}
This IPositionService is a manager that inspects the message and checks if it can be saved inside our database:
public class PositionService : IPositionService
{
[...]
public PositionService(
IUnitOfWork unitOfWork, ILogger<PositionService> logger)
{
this.unitOfWork = unitOfWork;
this.logger = logger;
}
public async Task HandleMessage(string message)
{
Entity entity = await unitOfWork.EntityRepository.GetByMessage(message);
[...]
await unitOfWork.EntityRepository.UpdateAsync(entity);
await unitOfWork.Save();
}
[...]
}
IUnitOfWork is a wrapper around Entity Framework Core DbContext (please don't judge me, I have reasons to do this):
public class UnitOfWork : IUnitOfWork
{
[...]
public UnitOfWork(MyContext myContext)
{
this.myContext = myContext;
EntityRepository = new EFRepository<Entity>(myContext);
}
public async Task Save()
{
await myContext.SaveChangesAsync();
}
}
EFRepository<T>, that implements IRepository<T> interface, is a wrapper around DbSet<T> (again, please don't judge me). No relevant code here.
Console Application's Program.cs is configured like that:
[...]
.ConfigureServices((hostContext, services) =>
{
services.AddDbContext<MyContext>(
c => c.UseSqlServer("[...]", options => options.UseNetTopologySuite()),
ServiceLifetime.Transient);
services.AddTransient<IPositionService, PositionService>();
services.AddTransient(typeof(IRepository<>), typeof(EFRepository<>));
services.AddTransient<IUnitOfWork, UnitOfWork>();
services.AddHostedService<MqttClientHostedService>();
[...]
});
Problem is that PositionService.HandleMessage is being called many times per second, and being that DbContext is not thread safe I get this error message:
A second operation started on this context before a previous operation
completed.
I solved this issue by removing IUnitOfWork from PositionService's dependencies, injecting instead an IServiceScopeFactory, and doing:
using (IServiceScope serviceScope = serviceScopeFactory.CreateScope())
{
IUnitOfWork unitOfWork = serviceScope.ServiceProvider.GetService<IUnitOfWork>();
[...]
}
This way works, but I don't like it. It seems like a trick, and I don't like the fact that my PositionService knows about Dependency Injection and has to deal with scopes.
My question is: there's a better way to solve this problem without touching my classes? Should I make the whole UnitOfWork thread safe? Or maybe create it by hand without using DI?
The source of the problem is that MyContext is held captive as a Captive Dependency in the following object graph:
MqttClientHostedService
-> PositionService
-> UnitOfWork
-> MyContext
All types in this graph are registered as Transient, but still, services that act as hosted service (e.g. your MqttClientHostedService) are resolved only once for the duration of the application and cached indefinately. This effectively makes them a singleton.
In other words, MyContext is accidentally kept alive by the single MqttClientHostedService and because multiple messages can come in in parallel, you have yourself a race condition.
The solution is to let each ApplicationMessageReceived event run in its own unique little bubble (a scope) and resolve a new IPositionService from within that bubble. For instance:
public class MqttClientHostedService : IHostedService, IDisposable
{
[...]
public MqttClientHostedService(
ILogger<MqttClientHostedService> logger,
IOptions<MqttClientConfiguration> mqttConfiguration,
IServiceProvider provider)
{
this.logger = logger;
this.config = mqttConfiguration;
this.provider = provider;
}
[...]
private async Task MqttClient_ApplicationMessageReceived(
object sender, MqttApplicationMessageReceivedEventArgs e)
{
using (var scope = provider.CreateScope())
{
positionService = scope.ServiceProvider
.GetRequiredService<IPositionService>();
string message = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
await positionService.HandleMessage(message);
}
}
[...]
}

Passing connection string to Entity framework at runt time for each call

My Entity framework context is as following
public partial class MyContext : DbContext, IMyContext
{
static MyContext()
{
System.Data.Entity.Database.SetInitializer<MyContext>(null);
}
public MyContext()
: base("Name=MyContext")
{
}
I am resolving it through autofac in the following way
builder.RegisterType(typeof(MainContext)).As(typeof(DbContext)).InstancePerLifetimeScope();
builder.RegisterType<MainContext>().As<IMainContext>().InstancePerRequest();
This db context gets called in repository layer
#region Fields
private readonly IMyContext _context;
#endregion
#region Constructors and Destructors
public EmployeeRepository(IMyContext context)
{
_context = context;
}
#endregion
public void Create(Employee emp)
{
this._context.Employee.Add(emp);
}
Now my issue is , I want to set the connection string dynamically per call. The connection string will be passed through a webapi which i want to pass on to this context. Can anyone help me how can i do that? I am confused about autofac here. Secondly how can i make sure each call sets connection string and does not cache it.
You can use a factory that will build the context and set the connectionstring for you.
public interface IContextFactory
{
IContext GetInstance();
}
public class MyContextFactory : IContextFactory
{
public IContext GetInstance()
{
String connectionString = this.GetConnectionString(HttpContext.Current);
return new MyContext(connectionString);
}
private String GetConnectionString(HttpContext context)
{
// do what you want
}
}
builder.RegisterType<MyContextFactory>()
.As<IContextFactory>()
.InstancePerRequest();
builder.Register(c => c.Resolve<IContextFactory>().GetInstance())
.As<IContext>()
.InstancePerRequest();
If you can't get connectionstring based on HttpContext, you can change contextFactory implementation to expect initialization by WebAPI before creating the instance. For example :
public interface IContextFactory
{
IContext GetInstance();
void Initialize(String connectionString);
}
public class MyContextFactory : IContextFactory
{
private String _connectionString;
public void Initialize(String connectionString)
{
this._connectionString = connectionString;
}
public IContext GetInstance()
{
if (this._connectionString == null)
{
throw new Exception("connectionString not initialized");
}
return new MyContext(this._connectionString);
}
}
At the beginning of your web API call (through attribute for example), you can call the Initialize method. Because the factory is InstancePerRequest you will have one instance for the duration of the request.
By the way, I'm not sure to understand this registration
builder.RegisterType(typeof(MainContext)).As(typeof(DbContext)).InstancePerLifetimeScope();
builder.RegisterType<MainContext>().As<IMainContext>().InstancePerRequest();
It looks buggy because you will have 2 different registration of the same type and not for the same scope, is it intended ? Furthermore, it doesn't sound a good idea to register a DbContext, do you need this registration ?
The following registration looks better :
builder.RegisterType<MainContext>()
.As<IMainContext>()
.As<DbContext>()
.InstancePerRequest();

"No parameterless constructor" error instantiating Controller registered w/Windsor Container

Using MVC and trying to use dependency injection for controllers, but when I try to call a method on a controller that takes a dependency, I get the "no parameterless constructor" error. Here's my setup:
ProductRepository : IProductRepository
ProductService : IProductService {
public ProductService(IProductRepository repository) {} }
ProductController {
public ProductController(IProductService service) {} }
In Global.asax:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
InitializeServiceLocator();
RegisterRoutes(RouteTable.Routes);
}
protected virtual void InitializeServiceLocator()
{
IWindsorContainer container = new WindsorContainer();
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container));
container.RegisterControllers(typeof(HomeController).Assembly);
ComponentRegistrar.AddComponentsTo(container);
foreach (var handler in container.Kernel.GetAssignableHandlers(typeof(object)))
{
System.Diagnostics.Debug.WriteLine(String.Format("{0} {1}",
handler.ComponentModel.Service,
handler.ComponentModel.Implementation));
}
ServiceLocator.SetLocatorProvider(() => new WindsorServiceLocator(container));
}
ComponentRegistrar:
public static void AddComponentsTo(IWindsorContainer container)
{
AddCustomRepositoriesTo(container);
AddApplicationServicesTo(container);
}
When InitializeServiceLocator completes, I can see that all Controllers, Services and Repositories are registered.
Any help greatly appreciated.
I'd still like to know the problem, but I've worked around it by creating my own WindsorControllerFactory per this post (with modification to avoid any web.config action): http://mvcsharp.wordpress.com/2010/01/09/setting-up-ioc-in-asp-net-mvc-using-castle-windsor/
The WindsorControllerFactory in the previous code was the MvcContrib.Castle.WindsorControllerFactory. Anyone using MvcContrib version successfully?
Thanks.

Using structuremap with log4net wrapper

I have the following interface:
public interface ILogger
{
void Debug(string message, params object[] values);
void Info(string message, params object[] values);
void Warn(string message, params object[] values);
void Error(string message, params object[] values);
void Fatal(string message, params object[] values);
}
and the following implementation:
public class Log4netLogger : ILogger
{
private ILog _log;
public Log4netLogger(Type type)
{
_log = LogManager.GetLogger(type);
}
public void Debug(string message, params object[] values)
{
_log.DebugFormat(message, values);
}
// other logging methods here...
}
My idea was to use structuremap to instantiate the Log4netLogger class with using the Type of the class that did the logging. However, I can't for the life of me figure out how to pass the type of the calling class to structuremap so that it can be passed to the constructor of the logging implementation. Any advice on how to do that (or a better way) would be most appreciated.
We use a similar ILogger wrapper around log4net and typically use constructor injection. We use an interceptor as a factory method responsible for creating the Logger. Here is our typical registry for logging setup.
public class CommonsRegistry : Registry
{
public CommonsRegistry()
{
For<ILogger>()
.AlwaysUnique()
.TheDefault.Is.ConstructedBy(s =>
{
if (s.ParentType == null)
return new Log4NetLogger(s.BuildStack.Current.ConcreteType);
return new Log4NetLogger(s.ParentType);
});
var applicationPath = Path.GetDirectoryName(Assembly.GetAssembly(GetType()).Location);
var configFile = new FileInfo(Path.Combine(applicationPath, "log4net.config"));
XmlConfigurator.ConfigureAndWatch(configFile);
}
}
The parent type null check is necessary when there are dependencies on concrete types.
The rest is optional log4net setup stuff.
One thing I do like about this setup is the ability to use a null loggers for unit testing.
If the type parameter is context-specific, I don't think this is going to work as shown. If you need to pass something context specific in the constructor, you are likely going to have to create a factory interface and implementation that returns an instance of the ILogger:
public interface ILoggerFactory
{
ILogger Create(Type type);
}
public class LoggerFactory : ILoggerFactory
{
public ILogger Create(Type type)
{
return new Log4netLogger(type);
}
}
It might be possible to bootstrap StructureMap to supply the instance you want based on the type, but that assumes a limited number of types that you know in advance.
I really need to get out of the habit of answering my own question, but for those who run across it, here's the answer.
return ObjectFactory.With(type).GetInstance<T>();
I actually have a wrapper to structuremap (to avoid exposing the structuremap dependency to my app) that looks like the following:
public static class ServiceManager
{
public static T Get<T>()
{
return ObjectFactory.GetInstance<T>();
}
public static T Get<T>(Type type)
{
return ObjectFactory.With(type).GetInstance<T>();
}
}
Any time in the code I need a logger, I call the following:
ServiceManager.Get<ILogger>(GetType()).Info("Logging page view...");