My application is based on ASP.NET Core 2.1 and .NET Core 2.1 (downgraded from 2.2) generic host as Windows Service. So, IHostBuilder is launched first with other services and frameworks and then (if role permits) web service gets launched on top using IWebHostBuilder with all that WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().StartAsync(). Secondary WebHost is another story; it is initialized and works, but I haven't checked yet if IoC replacement has the same trouble as generic host.
For now, generic host initialization:
new HostBuilder().ConfigureServices((hostContext, services) =>
{
services.AddHostedService<LifetimeService>(); // Gets launched when host is up
var container = ContainerBuilder.BuildBaseContainer(services, new WorkingPath());
services.AddSingleton<IContainer>(container);
services.AddStructureMap(); // Has no effect
});
IContainer initialization:
public static Container BuildBaseContainer(IServiceCollection services, IWorkingPath workingPath)
{
var container = new Container();
container.Configure(config =>
{
config.Scan(scan =>
{
workingPath.OwnLoadedAssemblies.Where(asm => !asm.IsDynamic).ForEach(scan.Assembly);
scan.LookForRegistries();
scan.AddAllTypesOf<IPlatformService>();
});
config.For<IContainer>().Use(() => container);
config.Populate(services);
});
container.AssertConfigurationIsValid();
return container;
}
And the trouble is here, in the constructor of that registered hosted service (or anywhere else)
public LifetimeService(IEnumerable<IPlatformService> services,
IServiceProvider sp, IContainer c)
{
var inCollection = services.Any();
var inContainer = c.TryGetInstance<IPlatformService>() != default;
var inProvider = sp.GetRequiredService<IPlatformService>() != default;
}
ps: IServiceProvider and IContainer are for demonstration purposes only, I only need 'services'
When LifetimeService is initialized during container.AssertConfigurationIsValid() I get
inCollection is true
inContainer is true
inProvider is true
IServiceProvider is StructureMapServiceProvider
Actual LifetimeService execution shows that
inCollection is false
inContainer is true
inProvider is false
IServiceProvider is ServiceProviderEngineScope
I don't plan to pass IServiceProvider or IContainer into constructors, but it seems that dependencies are resolved using IServiceProvider, not IContainer, and I get nulls. Silly thing like sp.GetRequiredService<IContainer>().TryGetInstance<IPlatformService>() does work.
There been some happy-path examples using WebHost and Startup classes where injection ought to be working properly. Doesn't seem relevant for generic host ...which might replace WebHost one day, but is little known and not widely used. Well, could be due to .NET Core version downgrade too, but quite unlikely. I've also tried replacing IServiceProvider and IServiceScopeFactory from IContainer during ConfigureServices() without luck. My idea is to replace or forward internal container to StructureMap. I might be misunderstanding how that should work...
Has anyone successfully tried to 'marry' generic host and external IoC?
I've solved the puzzle! Finally, according to a too much simplified example (https://github.com/aspnet/Hosting/blob/master/samples/GenericHostSample/ProgramFullControl.cs), I had to change HostBuilder initialization to
new HostBuilder()
.UseServiceProviderFactory(new StructureMapContainerFactory(workingPath))
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<LifetimeService>();
});
and introduce provider factory itself
public class StructureMapContainerFactory : IServiceProviderFactory<IContainer>
{
private readonly IWorkingPath workingPath;
// pass any dependencies to your factory
public StructureMapContainerFactory(IWorkingPath workingPath)
{
this.workingPath = workingPath;
}
public IContainer CreateBuilder(IServiceCollection services)
{
services.AddStructureMap();
return ContainerBuilder.BuildBaseContainer(services, workingPath);
}
public IServiceProvider CreateServiceProvider(IContainer containerBuilder)
{
return containerBuilder.GetInstance<IServiceProvider>();
}
}
Now internal container is substituted with StructureMap and resolved IServiceProvider in LifetimeService is of type StructureMapServiceProvider.
Related
There are many extensions for the IServiceCollection - in my case I use AddHttpClient.
My scenario is that I register general stuff in the ConfigureServices method in the Startup.cs where IServiceCollection is used to register services. Everything that is needed only in specific projects is registered in an extension method in the respective project, but there the DryIoc IContainer is used due to how the DryIoc container must be integrated in an ASP .NET Core project.
Now I have a HttpClient that I only need in a specific project. Therefore I would like to put the registration for it in the respective project. Problem is I want to use AddHttpClient for it which I normally can only use with IServiceCollection.
My question: Is there any way to use it in my other project. Maybe by getting it from the DryIoc container or something else.
This is the general structure of the described files:
Startup.cs
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.RegisterSomeService();
// register other stuff
}
}
Program.cs
public class Startup
{
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseServiceProviderFactory(new DryIocServiceProviderFactory())
.ConfigureContainer<Container>(SomeProject.ContainerSetup.Initialize);
}
ContainerSetup.cs in SomeProject
public static class ContainerSetup
{
public static void Initialize(HostBuilderContext hostContext, IContainer container)
{
container.Register<SomeService>();
// register other stuff
// here I want to use AddHttpClient
}
}
I was able to solve the problem by using the IContainer extension Populate which is part of DryIoc.Microsoft.DependencyInjection.
With it I edited my ContainerSetup.cs as follows
public static class ContainerSetup
{
public static void Initialize(HostBuilderContext hostContext, IContainer container)
{
var services = new ServiceCollection();
services.AddHttpClient<MyTypedClient>()
.Configure[...];
container.Populate(services); // with this call all services registered above will be registered in the container
// register other stuff if necessary
container.Register<SomeService>();
}
}
I suggest to look inside the AddHttpClient https://source.dot.net/#Microsoft.Extensions.Http/DependencyInjection/HttpClientFactoryServiceCollectionExtensions.cs,72bc67c4aadb77fc
and maybe make the same registrations with IContainer instead of the service collection.
Update:
Another idea is to register IServiceCollection into itself (or maybe it is already automatically registered?), then resolve it from IContainer and AddHttpClient..
I'm trying to Convert an application I have working under a Basic Websharper Setup into an ASP.NET Core Application, Using Simple Injector for DI, but Cannot get the Configuration quite right. I think I'm missing a piece of abstraction Due to Websharper's Remoting Abstraction. How should I get the best of both worlds?
I'm using Websharper with the ASPNETCORE Nuget Package, SimpleInjector with the ASPNETCORE Nuget Package, and my own custom libraries.
I've gotten things to work as singletons with the code below, but I'd much rather be able to use proper scoping...
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddSitelet<OddJobSitelet>()
//.AddWebSharperRemoting<OddJobRemoting>() //This will not work, results in a torn lifestyle related error
.AddAuthentication("WebSharper")
.AddCookie("WebSharper", options => { });
IntegrateSimpleInjector(services);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
InitializeContainer(app);
if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); }
WebSharper.Core.Remoting.AddHandler(typeof(OddJobRemoting), container.GetService<OddJobRemoting>()); //This only takes an instance, which appears to preclude scoping.
app.UseAuthentication()
.UseStaticFiles()
.UseWebSharper()
.Run(context =>
{
context.Response.StatusCode = 404;
return context.Response.WriteAsync("Page not found");
});
}
public static void Main(string[] args)
{
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build()
.Run();
}
private Container container = new Container();
private void IntegrateSimpleInjector(IServiceCollection services)
{
/*services.Add(new ServiceDescriptor(typeof(OddJobRemoting), (aspnetCore) => container.GetService<OddJobRemoting>(), //Tried this, did not help since Websharper Remoting doesn't appear to use ServiceCollection this way*/
ServiceLifetime.Scoped));
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.EnableSimpleInjectorCrossWiring(container);
services.UseSimpleInjectorAspNetRequestScoping(container);
}
private void InitializeContainer(IApplicationBuilder app)
{
//If I use anything other than Lifestyle.Singleton for either the remoting Handler or my provider, It results in a torn lifestyle.
container.Register<IJobSearchProvider>(() =>
{
return new SQLiteJobQueueManager(new SQLiteJobQueueDataConnectionFactory(TempDevInfo.ConnString),
TempDevInfo.TableConfigurations["console"], new NullOnMissingTypeJobTypeResolver());
}, Lifestyle.Singleton);
container.Register<OddJobRemoting>(Lifestyle.Singleton);
// Allow Simple Injector to resolve services from ASP.NET Core.
container.AutoCrossWireAspNetComponents(app);
}
}
As Requested:
If I change the lifestyles from singleton, I will get the following Exception:
The OddJobRemoting is registered as 'Async Scoped' lifestyle, but the instance is requested outside the context of an active (Async Scoped) scope.
This happens on the line:
WebSharper.Core.Remoting.AddHandler(typeof(OddJobRemoting), container.GetService<OddJobRemoting>());
To note, I'm having to do this because Websharper's AddHandler method requires an instance and appears to treat such as singletons internally.
I have implemented an adapter that implement IServiceProvider and returned it from the ConfigureServices method in the Startup. class:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var kernel = new StandardKernel();
var container = new NinjectComponentContainer(kernel);
// ...
return ServiceProviderFactory.Create(container, services);
}
However, my implementation doesn't seem to be used everywhere. I even tried to override the IHttpContextAccessor to return a modified HttpContext:
public HttpContext HttpContext {
get
{
var result = _httpContextAccessor.HttpContext;
result.RequestServices = _serviceProvider;
return result;
}
set => _httpContextAccessor.HttpContext = value;
}
To test whether I could get to my implementation I used a filter in order to see what the HttpContext.RequestServices would return:
public class AuthorizationTestAttribute : ActionFilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var service = context.HttpContext.RequestServices.GetService(typeof(IAccessConfiguration));
}
}
The type returned by context.HttpContext.RequestServices is:
My main issue was trying to get registered components resolved in the constructor of a filter but it always seems to fail saying the component is not registered. However it does seem to work when using the TypeFilter attribute:
[TypeFilter(typeof(RequiresSessionAttribute))]
However, my attribute does inherit from TypeFilter:
public class RequiresSessionAttribute : TypeFilterAttribute
{
public RequiresSessionAttribute() : base(typeof(RequiresSession))
{
Arguments = new object[] { };
}
private class RequiresSession : IAuthorizationFilter
{
private readonly IAccessConfiguration _configuration;
private readonly IDatabaseContextFactory _databaseContextFactory;
private readonly ISessionQuery _sessionQuery;
public RequiresSession(IAccessConfiguration configuration,
IDatabaseContextFactory databaseContextFactory, ISessionQuery sessionQuery)
{
Guard.AgainstNull(configuration, nameof(configuration));
Guard.AgainstNull(databaseContextFactory, nameof(databaseContextFactory));
Guard.AgainstNull(sessionQuery, nameof(sessionQuery));
_configuration = configuration;
_databaseContextFactory = databaseContextFactory;
_sessionQuery = sessionQuery;
}
I did come across this question but there is no definitive answer.
Any ideas on how to correctly provider a custom implementation of the IServiceProvider interface that will be used throughout the solution?
Even though Microsoft states that it is possible to replace the built-in container it appears as though it is not quite this simple, or even possible.
As stated by Steven in his very first comment, if you choose to use your container of choice, you should run them side-by-side.
The guidance from Microsoft suggests changing the ConfigureServices in the Startup class from this:
public void ConfigureServices(IServiceCollection services)
{
// registrations into services
}
to the following:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var container = new YourContainer(); // Castle, Ninject, etc.
// registrations into container
return new YourContainerAdapter(container);
}
However, there are a number of issues with this since there are already framework registrations in services that we do not necessarily know how to re-register in our own container. Well, there is a descriptor so if our container supports all the various methods then it is actually possible to re-register all the components. The various DI containers have different mechanisms when it comes to registration and service resolution. Some of them have a very hard distinction between the two making it quite tricky at times to accommodate a "common" solution.
My initial idea was to provide an adapter that accepts both my own container as well as the services collection from which I would then get the built-in service provider by calling services.BuildServiceProvider(). In this way I could attempt to resolve from the built-in provider and then, if the resolving bit failed, attempt to resolve from my own container. However, it turns out that the .net core implementation does in fact not use the returned IServiceProvder instance.
The only way I could get this to work was to wire up my own container and use it to resolve my controllers. That could be done by providing an implementation of the IControllerActivator interface.
In this particular implementation I was fiddling with Ninject although I typically prefer Castle but the same applies to any DI container:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IKernel>(new StandardKernel());
services.AddSingleton<IControllerActivator, ControllerActivator>();
}
public class ControllerActivator : IControllerActivator
{
private readonly IKernel _kernel;
public ControllerActivator(IKernel kernel)
{
Guard.AgainstNull(kernel, nameof(kernel));
_kernel = kernel;
}
public object Create(ControllerContext context)
{
return _kernel.Get(context.ActionDescriptor.ControllerTypeInfo.AsType());
}
public void Release(ControllerContext context, object controller)
{
_kernel.Release(controller);
}
}
In order to register the controller types I did my DI wiring in the Configure method since I have access to the IApplicationBuilder which can be used to get to the controller types:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime applicationLifetime)
{
var kernel = app.ApplicationServices.GetService<IKernel>();
// kernel registrations
var applicationPartManager = app.ApplicationServices.GetRequiredService<ApplicationPartManager>();
var controllerFeature = new ControllerFeature();
applicationPartManager.PopulateFeature(controllerFeature);
foreach (var type in controllerFeature.Controllers.Select(t => t.AsType()))
{
kernel.Bind(type).ToSelf().InTransientScope();
}
applicationLifetime.ApplicationStopping.Register(OnShutdown);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(
options => options.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()
);
app.UseMvc();
}
This worked swimmingly for the controllers but resolving "filters" was still a problem given that they use the IFilterFactory on the filter itself to implement a factory method:
public IFilterMetadata CreateInstance (IServiceProvider serviceProvider);
Here we can see that the IServiceProvider implementation is provided in order to resolve any depedencies. This applies when using the TypeFilterAttribute or when defining new filters that inherit from TypeFilterAttribute as I have in my question.
This mechanism is actually a very good example of the difference between "Inversion of Control" and "Dependency Injection". The control lies with the framework (inversion) and we have to provide the relevant implementations. The only issue here is that we are not able to hook in properly since our provided IServiceProvider instance is not passed to the CreateInstance method which then results in a failure when attempting to create an instance of the filter. There are going to be a number of ways to fix this design but we'll leave that to Microsoft.
In order to get my filters working I decided to go the "cross-wiring" route as alluded to by Steven by simply registering the depedencies required by my filters in the services collection also:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IKernel>(new StandardKernel());
services.AddSingleton<IControllerActivator, ControllerActivator>();
services.AddSingleton<IDatabaseContextFactory, DatabaseContextFactory>();
services.AddSingleton<IDatabaseGateway, DatabaseGateway>();
services.AddSingleton<IDatabaseContextCache, ContextDatabaseContextCache>();
// and so on
}
Since I do not have many dependencies in my filter it works out OK. This does mean that we have "duplicate" registrations that we need to be careful of depending on how the instances are used.
I guess another option may be to forego your DI container of choice and use only the built-in container.
In my Startup class I use the ConfigureServices(IServiceCollection services) method to set up my service container, using the built-in DI container from Microsoft.Extensions.DependencyInjection.
I want to validate the dependency graph in an unit test to check that all of the services can be constructed, so that I can fix any services missing during unit testing instead of having the app crash at runtime. In previous projects I've used Simple Injector, which has a .Verify() method for the container. But I haven't been able to find anything similar for ASP.NET Core.
Is there any built-in (or at least recommended) way of verifying that the entire dependency graph can be constructed?
(The dumbest way I can think of is something like this, but it will still fail because of the open generics that are injected by the framework itself):
startup.ConfigureServices(serviceCollection);
var provider = serviceCollection.BuildServiceProvider();
foreach (var serviceDescriptor in serviceCollection)
{
provider.GetService(serviceDescriptor.ServiceType);
}
A built-in DI container validation was added in ASP.NET Core 3 and it is enabled only in the Development environment by default. If something is missing, the container throws a fatal exception on startup.
Keep in mind that controllers aren't created in the DI container by default, so a typical web app won't get much from this check until the controllers are registered in the DI:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers()
.AddControllersAsServices();
}
To disable/customize the validation, add a IHostBuilder.UseDefaultServiceProvider call:
public class Program
{
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
//...
.UseDefaultServiceProvider((context, options) =>
{
options.ValidateOnBuild = false;
});
This validation feature has several limitations, read more here: https://andrewlock.net/new-in-asp-net-core-3-service-provider-validation/
Actually, I just used the example from your question with a few modifications and it worked pretty well for me. The theory behind filtering by classes in my namespace is that those will end up asking for everything else I care about.
My test looked a lot like this:
[Test or Fact or Whatever]
public void AllDependenciesPresentAndAccountedFor()
{
// Arrange
var startup = new Startup();
// Act
startup.ConfigureServices(serviceCollection);
// Assert
var exceptions = new List<InvalidOperationException>();
var provider = serviceCollection.BuildServiceProvider();
foreach (var serviceDescriptor in services)
{
var serviceType = serviceDescriptor.ServiceType;
if (serviceType.Namespace.StartsWith("my.namespace.here"))
{
try
{
provider.GetService(serviceType);
}
catch (InvalidOperationException e)
{
exceptions.Add(e);
}
}
}
if (exceptions.Any())
{
throw new AggregateException("Some services are missing", exceptions);
}
}
I had same problem in one of my project. My resolve:
add methods like AddScopedService, AddTransientService and AddSingletonService, that add service to DI and then add it to some List. Use this methods instead of AddScoped, AddSingleton and AddTransient
on startup application frist time i iterate by this list and call GetRequiredService. If any service can't be resolved, application will not start
I had CI: auto build and deploy on commit to develop branch. So if someone merge changes that broke DI, application fail and we all know about it.
If u whant to do it faster, u can use TestServer in Dmitry Pavlov's answer with my solution together
Here is a unit test that you can add to your project:
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using [X/N]Unit;
namespace MyProject.UnitTests
{
public class DITests
{
[Fact or Test]
public void AllServicesShouldConstructSuccessfully()
{
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseDefaultServiceProvider((context, options) =>
{
options.VailidateOnBuild = true;
})
.UseStartup<Startup>();
}).Build();
})
}
}
I've installed and configured Hangfire in my .NET Core web application's Startup class as follows (with a lot of the non-Hangfire code removed):
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseHangfireServer();
//app.UseHangfireDashboard();
//RecurringJob.AddOrUpdate(() => DailyJob(), Cron.Daily);
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<AppSettings>(Configuration);
services.AddSingleton<IConfiguration>(Configuration);
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IPrincipal>((sp) => sp.GetService<IHttpContextAccessor>().HttpContext.User);
services.AddScoped<IScheduledTaskService, ScheduledTaskService>();
services.AddHangfire(x => x.UseSqlServerStorage(connectionString));
this.ApplicationContainer = getWebAppContainer(services);
return new AutofacServiceProvider(this.ApplicationContainer);
}
}
public interface IScheduledTaskService
{
void OverduePlasmidOrdersTask();
}
public class ScheduledTaskService : IScheduledTaskService
{
public void DailyJob()
{
var container = getJobContainer();
using (var scope = container.BeginLifetimeScope())
{
IScheduledTaskManager scheduledTaskManager = scope.Resolve<IScheduledTaskManager>();
scheduledTaskManager.ProcessDailyJob();
}
}
private IContainer getJobContainer()
{
var builder = new ContainerBuilder();
builder.RegisterModule(new BusinessBindingsModule());
builder.RegisterModule(new DataAccessBindingsModule());
return builder.Build();
}
}
As you can see, I'm using Autofac for DI. I've set things up to inject a new container each time the Hangfire job executes.
Currently, I have UseHangfireDashboard() as well as the call to add my recurring job commented out and I'm receiving the following error on the line referencing IPrincipal:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
I understand that Hangfire does not have an HttpContext. I'm not really sure why it's even firing that line of code for the Hangfire thread. I'm ultimately going to need to resolve a service account for my IPrincipal dependency.
How can I address my issue with Hangfire and HttpContext?
The main problem I'm having now is when I add UseHangfireServer, I
then need to resolve HttpContext too
Found here Using IoC containers
HttpContext is not available
Request information is not available during the instantiation of a
target type. If you register your dependencies in a request scope
(InstancePerHttpRequest in Autofac, InRequestScope in Ninject and so
on), an exception will be thrown during the job activation process.
So, the entire dependency graph should be available. Either register
additional services without using the request scope, or use separate
instance of container if your IoC container does not support
dependency registrations for multiple scopes.
resolving scoped dependencies in .net core would require a request which is not available during startup when registering and activating jobs. Therefore make sure that your service required for activation during startup are not registered using scoped lifetimes.
services.AddTransient<IScheduledTaskManager, ScheduledTaskManageImplementation>();
All that is left now is to configure the application to use that service with the recurring job,
public class Startup {
public IContainer ApplicationContainer { get; private set; }
public Startup(IHostingEnvironment env) {
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public void Configuration(IApplicationBuilder app) {
// app.AddLogger...
//add hangfire features
app.UseHangfireServer();
app.UseHangfireDashboard();
//Add the recurring job
RecurringJob.AddOrUpdate<IScheduledTaskManager>(task => task.ProcessDailyJob(), Cron.Daily);
//app.UseMvc...
//...other code
}
public IServiceProvider ConfigureServices(IServiceCollection services) {
// Adding custom services
services.AddTransient<IScheduledTaskManager, ScheduledTaskManageImplementation>();
//add other dependencies...
// add hangfire services
services.AddHangfire(x => x.UseSqlServerStorage("<connection string>"));
//configure Autofac
this.ApplicationContainer = getWebAppContainer(services);
//get service provider
return new AutofacServiceProvider(this.ApplicationContainer);
}
IContainer getWebAppContainer(IServiceCollection service) {
var builder = new ContainerBuilder();
builder.RegisterModule(new BusinessBindingsModule());
builder.RegisterModule(new DataAccessBindingsModule());
builder.Populate(services);
return builder.Build();
}
//...other code
}
References
Hangfire 1.6.0
Integrate HangFire With ASP.NET Core
Using IoC containers
Why is Hangfire trying to resolve the .NET Core Startup class?
Hangfire doesn't store lambda expressions in the database, it stores the type and method being called. Then when the scheduled task is due to run, it resolves the type from the container and calls the method.
In your case, the method is on Startup.
You can register Startup with Autofac if you want, but it's probably easiest to have a scheduled task service:
AddOrUpdate<IScheduledTaskService>(x => x.DailyTask(), Cron.Daily);
I'm not sure of the type for jobmanager off the top of my head, but you can resolve the dependency from the container using a scope. You'll want to resolve from the scope in a using statement to prevent memory leaks. See the Autofac Docs
// not sure what type "jobManager" is
TYPE jobManager;
using(var scope = ApplicationContainer.BeginLifetimeScope())
{
jobManager = scope.Resolve<TYPE>();
}
RecurringJob.AddOrUpdate( ... );