I have an issue with RegisterHttpRequestMessage not working for me and cannot figure out what I'm doing wrong. This is specifically when I try to manually resolve a service that accepts the HttpMessageRequest as a parameter.
I'm using modules to register components in my builder, and currently my module in the main web project looks like this:
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterHttpRequestMessage(GlobalConfiguration.Configuration);
builder.RegisterType<SourceSystemViewModel>().AsImplementedInterfaces().InstancePerRequest();
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.Where(t => t.Name.EndsWith("ViewModelValidator"))
.AsImplementedInterfaces()
.PropertiesAutowired();
// Etc etc etc
SourceSystemViewModel is currently quite simple and looks like this:
public interface ISourceSystemViewModel
{
SourceSystem Value { get; }
}
public class SourceSystemViewModel : ISourceSystemViewModel
{
public SourceSystemViewModel(HttpRequestMessage request)
{
Value = request.Headers.GetSourceSystem();
}
public SourceSystem Value { get; }
}
GetSourceSystem is just an extension method that pulls out the header value. I have tried both registering SourceSystemViewModel with and without InstancePerRequest but it doesn't make a difference. The moment autofac tries to resolve ISourceSystemViewModal (and ultimately HttpRequestMessage) it throws this:
An exception of type
'Autofac.Core.Registration.ComponentNotRegisteredException' occurred
in Autofac.dll but was not handled in user code
Additional information: The requested service 'System.Net.Http.HttpRequestMessage' 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.
Using autofac 3.5 (webapi dll is quoted as autofac.webapi2 3.4).
Any ideas much appreciated!
Notes
I'll add any findings as I come across them...
Update 1
I took a look at how RegisterHttpRequestMessage works and it does indeed add a message handler called CurrentRequestHandler to HttpConfiguration. When my request comes in I can see that this message handler still exists. So the method seems to do what it's supposed to, it's just not resolving the request message for me...
Update 2
I have noticed that while in the context of a controller and therefore have access to the HttpRequestMessage I can resolve both objects. Like this:
ILifetimeScope requestLifetimeScope = Request.GetDependencyScope().GetRequestLifetimeScope();
var h = requestLifetimeScope.Resolve<HttpRequestMessage>();
var sourceSystemViewModel = requestLifetimeScope.Resolve<ISourceSystemViewModel>();
Update 3
It's important to note that I am manually trying to resolve a service that is expecting the HttpMessageRequest as an injected parameter. For example, this fails for me:
using (var httpRequestScope = IocProxy.Container.Context.BeginLifetimeScope("AutofacWebRequest"))
{
var sourceSystemViewModel = httpRequestScope.Resolve<ISourceSystemViewModel>();
}
I had the same problem and based on SO I was able to get it working with
public class NLoggerTraceWriterModule : Module
{
private HttpConfiguration _config;
public NLoggerTraceWriterModule(HttpConfiguration config)
{
this._config = config;
}
protected override void Load(ContainerBuilder builder)
{
builder.RegisterInstance(this._config).As<HttpConfiguration>();
builder.Register(c =>
c.Resolve<HttpConfiguration>()
.Services
.GetService(typeof(ITraceWriter)) as ITraceWriter)
.As<ITraceWriter>();
}
}
registering this module as
// Call RegisterHttpRequestMessage to add the feature.
builder.RegisterHttpRequestMessage(config);
builder.RegisterModule(new Helper.Logging.NLoggerTraceWriterModule(config));
Even though this wasn't the issue for OP, here's another solution since this is currently the only Google result for "The requested service System.Net.Http.HttpRequestMessage' has not been registered."
If you've created an HttpConfiguration instance, make sure that's what you're passing to the registration function.
In my case, this was resolved by changing this:
builder.RegisterHttpRequestMessage(GlobalConfiguration.Configuration);
To this:
builder.RegisterHttpRequestMessage(Startup.HttpConfiguration);
Related
Currently I have a autofac module which receives a string as parameter, and that string is coming from another dependency.
Im trying to pass it using below code, my question is: Is this the right approach or there is a better/improved way to do it?
builder.RegisterBuildCallback(c =>
{
var configService = c.Resolve<IConfigurationService>();
var module = new LoggingModule(configService.GetConfigurationValue("LoggerName"));
module.Configure(c.ComponentRegistry);
});
Generally try to avoid build callbacks and trying to configure the container based on configuring the container. To be honest, I'm surprised this even works since the container and registry are effectively immutable.
It would be better to use a lambda registration to resolve things. Since we don't know what your logging module is doing, let's say right now it's this:
public class LoggingModule
{
private readonly string _name;
public LoggingModule(string name)
{
this._name = name;
}
protected override void Load(ContainerBuilder builder)
{
builder.RegisterInstance(new MyLogger(this._name));
}
}
Even if it's not exactly this, it's pretty easy to adapt something similar - the parameter is coming into the module and being used by a registration.
You could move that into the registration itself and remove the module entirely.
builder.Register(ctx =>
{
var configService = ctx.Resolve<IConfigurationService>();
var name = configService.GetConfigurationValue("LoggerName");
return new MyLogger(name);
}).SingleInstance();
This avoids having to "know the parameter up front" and also avoids trying to reconfigure the container. You still get to register the config in DI and resolve it like you want.
I have a service and a model to get the parameter for its constructor and then the controller uses that service. I also use dependency injection and i can't quite point as to how declare the service, because it requires a parameter.
I have already looked into another similar questions, but none of the answers seem to work for me. The error i get is: "Unable to resolve service for type 'System.String' while attempting to activate 'authentication.Services.RDStationServices.RDStationService'.
The code connected to this matter:
public class RDStationService : IRDStationService
{
public RDStationService(string server)
{
_endPoint = server;
_client = new RestClient
{
BaseUrl = new Uri(_endPoint)
};
}
}
Model:
public class RDStationOptions
{
public string Url { get; set; }
}
Enviroment variable:
"RDStationOptions": {
"Url": "https://www.rdstation.com.br/api/1.3/"}
Startup:
public void ConfigureServices(IServiceCollection services)
{
var configOptionsRDStation = Configuration.GetSection(nameof(RDStationOptions));
var _rdStationInstance = new RDStationService(configOptionsRDStation[nameof(RDStationOptions.Url)]);
services.AddSingleton(_rdStationInstance);
}
This configuration inside the ConfigureServices is my latest attempt of informing the string to the constructer, but i keep getting the same error.
Any suggestions, please?
Since you use ASP.NET Core I assume your Configuration instance is type of IConfiguration. This should work for you:
public void ConfigureServices(IServiceCollection services)
{
var configOptionsRDStation = Configuration.GetSection("RDStationOptions : Url");
var _rdStationInstance = new RDStationService(configOptionsRDStation.Value);
services.AddSingleton(_rdStationInstance);
}
If you want to use IOptions:
services.Configure<RDStationOptions>(Configuration.GetSection("RDStationOptions"));
services.AddOptions()
The code you posted works as intended. I feel that your error is being caused by other code. Maybe post the rest of your configuration.
An example of somewhere I would expect this to happen:
services.AddSingleton(_rdStationInstance);
// Will NOT work, will created a scoped RDStationService and try to resolve string
services.AddScoped<IRDStationService, RDStationService>();
Try to use Options.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-2.2
I think it will be better idea
I have been playing around with IdentityServer3 with the hopes to replace our current authentication process.
Currently we use a custom identity framework process using code first entity framework.
I managed to install IdentityServer3 and get the "in memory" stuff working. Now I want to hook it up to our already customised UserProvider (UserManager if you like).
We already use Autofac and have our UserProvider registered like this:
builder.RegisterType<UserProvider>().As<IUserProvider>().InstancePerDependency();
I found some documentation that states that IdentityServer uses Autofac itself.
They recommend creating a factory and then using IdentityServerOptions to register the user service like this:
options.Factory.UserService = new Registration<IUserService>(UserServiceFactory.Create())
The problem I have with that, is the factory looks something like this:
public class UserServiceFactory
{
public static AspNetIdentityUserService<User, string> Create()
{
var context = new IdentityDbContext();
var userStore = new UserStore<User>(context);
var userManager = new UserManager<User>(userStore);
return new AspNetIdentityUserService<User, string>(userManager);
}
}
Which is using the normal UserManager rather than our customised version and it isn't using DI because you create it all in the static method.
Surely it would be better to use Autofac as we already have our UserProvider registered.
So, I didn't use their IdentityServerOptions to invoke the static method. So I changed my factory to this:
public class IdentityServerUserService : UserServiceBase
{
private readonly IUserProvider _userProvider;
public IdentityServerUserService(IUserProvider userProvider)
{
_userProvider = userProvider;
}
public override async Task AuthenticateLocalAsync(LocalAuthenticationContext context)
{
var user = await _userProvider.FindAsync(context.UserName, context.Password);
if (user != null && !user.Disabled)
{
// Get the UserClaims
// Add the user to our context
context.AuthenticateResult = new AuthenticateResult(user.Id, user.UserName, new List<Claim>());
}
}
}
Which I registered in autofac like this:
builder.RegisterType<IdentityServerUserService>()
.As<IdentityServer3.Core.Services.IUserService>()
.InstancePerDependency();
And then I assigned to the IdentityServerOptions.Factory.UserService like this:
private static void SetupServices(IdentityServerOptions options, ILifetimeScope scope)
{
options.Factory.UserService = new Registration<IUserService>(scope.Resolve<IdentityServerUserService>());
}
And the scope I get like this:
var config = new HttpConfiguration();
var scope = config.DependencyResolver.GetRootLifetimeScope();
I believe this should work, but I get an error when I try to use postman to authenticate:
Autofac.Core.Registration.ComponentNotRegisteredException: The requested service 'Business.IdentityServerUserService' 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.
I tried to change from InstancePerDependency to InstancePerLifetimeScope but still got the same error.
So, I have a couple of questions:
Is this the right way to assign the UserService?
Will this allow my existing users to authenticate?
Has anyone done this before? If so, did they get it to work?
If anyone can help me with these questions, I would be eternally grateful.
You resolve IdentityServerUserService but you register IdentityServerUserService as IUserService. Autofac doesn't automatically register the type as itself.
To fix the error you can register the type as itself
builder.RegisterType<IdentityServerUserService>()
.As<IdentityServer3.Core.Services.IUserService>()
.InstancePerDependency();
or resolve IUserService
options.Factory.UserService = new Registration<IUserService>(scope.Resolve<IUserService>())
Attempting to inject data into a FluentValidation validator:
public class MyFormValidator : AbstractValidator<MyForm>
{
private readonly IQueryable<Models.User> _users;
public MyFormValidator(IQueryable<Models.User> users)
{
_users = users;
...
}
}
My validator factory:
public class DependencyResolverValidatorFactory : ValidatorFactoryBase
{
private readonly IContainer container;
public DependencyResolverValidatorFactory(IContainer container)
{
this.container = container;
}
public override IValidator CreateInstance(Type validatorType)
{
return container.ResolveOptionalKeyed<IValidator>(validatorType);
}
}
My Autofac configurator:
public class AutofacConfigurator
{
public static void Configure()
{
var builder = new ContainerBuilder();
...
builder.RegisterType<MyFormValidator>()
.Keyed<IValidator>(typeof(IValidator<MyForm>))
.As<IValidator>()
// 2nd parameter returns IQueryable<User>
.WithParameter("users", new SqlRepository<User>(dataContext))
.InstancePerRequest();
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// Register the validator factory with FluentValidation, and register
// FluentValidation as the model validator provider for the MVC framework.
// see http://www.jerriepelser.com/blog/using-fluent-validation-with-asp-net-mvc-part-3-adding-dependency-injection
var fluentValidationModelValidatorProvider =
new FluentValidationModelValidatorProvider(
new DependencyResolverValidatorFactory(container));
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
fluentValidationModelValidatorProvider.AddImplicitRequiredValidator = false;
ModelValidatorProviders.Providers.Add(fluentValidationModelValidatorProvider);
}
}
Getting the following exception:
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
I have other validators, most of which will not need data injected into them.
This is largely new ground for me (in both Autofac and FluentValidation) and am still trying to understand what I am doing here. I suspect I'm simply registering my type incorrectly. How do I fix this and properly register my type?
(My apologies if this is too similar to other questions that were already asked.)
I have zero experience with FluentValidation, but I doubt it's the cause of your issues anyway, so I'll plow forward regardless.
The exception you're getting means that Autofac can't resolve your service as 'instance per request'. There's a lot of documentation as to what this means on the Autofac documentation page. To summarize, it means that Autofac will attempt to resolve the service from a lifetime scope that is automatically created for each request sent to the webserver. When you register something as .InstancePerRequestScope() but then attempt to resolve that service outside of that scope, you'll get the DependencyResolutionException you see.
So we've established that your MyFormValidator isn't being resolved from a 'Request' scope. Why?
The custom DependencyResolverValidatorFactory you've written takes the actual IContainer that was built by Autofac, and resolves from that. This is a special type of ILifetimeScope, the 'root scope'. There's no request lifetime scope directly associated with this, so you get your exception. You need to to resolve from an ILifetimeScope that is began from the 'request' scope, or a sub-scope that is contained within the request scope.
The Autofac/MVC integration already automatically hosts a request scope (within the AutofacDependencyResolver, see the source), but your custom DependencyResolverValidatorFactory doesn't resolve from it. If you want to do that, I suppose you could modify your DependencyResolverValidatorFactory to accept the AutofacDependencyResolver instance instead, and use that to resolve.
It would look something like this:
public class DependencyResolverValidatorFactory : ValidatorFactoryBase
{
private readonly AutofacDependencyResolver resolver;
public DependencyResolverValidatorFactory(AutofacDependencyResolver resolver)
{
this.resolver = resolver;
}
public override IValidator CreateInstance(Type validatorType)
{
return resolver.RequestLiftimeScope.ResolveOptionalKeyed<IValidator>(validatorType);
}
}
Note the RequestLifetimeScope stuck in there.
Then you create this in your .Configure() method using
var resolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(resolver);
var fluentValidationModelValidatorProvider =
new FluentValidationModelValidatorProvider(
new DependencyResolverValidatorFactory(resolver));
That should get rid of the exception, assuming that this factory does indeed have a request to work from when creating instances of IValidators. If not, You might need to register using the default behavior (.InstancePerDependency(), where it creates a new instance every time it's requested) or a singleton (.SingleInstance()), depending on how/if validators can or should be shared.
Good luck.
I am trying to create a "A(UserManager) needs to create instances of B(UserClient)" relationship (http://code.google.com/p/autofac/wiki/RelationshipTypes) where B(UserClient) needs a HttpSessionStateBase..
UserClient
public class UserClient : IUserClient
{
public UserClient(HttpSessionStateBase session)
{
//...
}
//...
}
UserManager
public class UserManager : IUserManager
{
private readonly Func<IUserClient> userClientPerRequest;
private IUserClient UserClient
{
get
{
return userClientPerRequest();
}
}
public UserManager(Func<IUserClient> userClientPerRequest)
{
this.userClientPerRequest = userClientPerRequest;
}
public void DoStuff()
{
UserClient.DoStuff();
}
This is where is register autofac stuff
public class MyModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder.RegisterType<UserManager>().As<IUserManager>().SingleInstance();
builder.RegisterType<UserClient>().As<IUserClient>().InstancePerHttpRequest();
builder.RegisterModule(new AutofacWebTypesModule());
//If i try this, i get Error 1 (printing errors after this code-block)
builder.Register<Func<IUserClient>>(c => c.Resolve<IUserClient>);
//If i try this, i get Error 2
builder.Register<Func<IUserClient>>(c => {
var ctx = c.Resolve<IComponentContext>();
return ctx.Resolve<IUserClient>;
});
//If i try this, well i always get null from GetService..
builder.Register<Func<IUserClient>>(c =>
DependencyResolver.Current.GetService<IUserClient>);
}
Looking at Autofac: Reference from a SingleInstance'd type to a HttpRequestScoped , they use some RequestContainer but i can find no such thing. :)
Error 1
This resolve operation has already ended. When registering components using lambdas, the IComponentContext 'c' parameter to the lambda cannot be stored. Instead, either resolve IComponentContext again from 'c', or resolve a Func<> based factory to create subsequent components from.
Error 2
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being reqested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
I have tried switching .InstancePerHttpRequest() to .InstancePerLifetimeScope() and a whole other different stuff.. Anyone have any ideas?
Thanks
When adding Autofac registrations manually in Orchard, use InstancePerMatchingLifetimeScope("shell"), if you need a singleton or InstancePerMatchingLifetimeScope("work"), if you need per-request instance.
I'm not sure if HttpSessionStateBase ctor argument can actually be resolved from the container. You could put IHttpContextAccessor there instead and use it to access the session state object inside IUserClient implementation.
And as Jim Bolla suggested - Func<IUserClient> (factory) is already available out of the box.
I don't think you need to do either of those registrations. Because of Relationship Types, Func<IUserClient> should already be available to you.