I'm using Autofac for DI with the builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).InstancePerRequest(); but sometimes it gives an error on all my controllers (System.InvalidOperationException: An error occurred when trying to create a controller of type 'UserController'. Make sure that the controller has a parameterless public constructor. ---> Autofac.Core.DependencyResolutionException)
and when I give a rebuild of WEB API and it starts working fine.
Here is my code in startup.cs
private void ConfigureAutofac(HttpConfiguration config, IAppBuilder app)
{
var builder = new ContainerBuilder();
//Register HttpRequestMessage
builder.RegisterType<CurrentRequest>().InstancePerRequest();
builder.Register(c => new UrlHelper(c.Resolve<CurrentRequest>().Value));
//Register Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).InstancePerRequest();
//Register the Autofac filter provider.
builder.RegisterWebApiFilterProvider(config);
//Register the Autofac model binder provider.
builder.RegisterWebApiModelBinderProvider();
#region Register managers
var businessasm = BuildManager.GetReferencedAssemblies()
.Cast<Assembly>()
.Where(n => n.FullName.Contains("Business"))
.FirstOrDefault();
builder.RegisterAssemblyTypes(businessasm)
.Where(t => t.Name.EndsWith("Manager") && t.Name != "DocumentManager")
.AsImplementedInterfaces()
.InstancePerRequest();
builder.RegisterGeneric(typeof(DocumentManager<>))
.As(typeof(IDocumentManager<>))
.InstancePerRequest();
#endregion
//Set the dependency resolver to be Autofac.
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
config.MessageHandlers.Insert(0, new ApiDelegatingHandler());
config.MessageHandlers.Insert(1, new ActivityLogHandler());
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
}
The error indicates that UserController (which you didn't show above) takes a parameter that isn't registered with Autofac.
Since it works sometimes and not others, my guess is that the problem is this line:
var businessasm = BuildManager.GetReferencedAssemblies()
.Cast<Assembly>()
.Where(n => n.FullName.Contains("Business"))
.FirstOrDefault();
FirstOrDefault will return null if no assembly is found; and later on when you register all the things that end with Manager it means nothing will get registered.
My guess is that the UserController needs one of these managers, Autofac doesn't have it registered, and instantiation fails. If you have a breakpoint on the next line, you can see if businessasm is null; or, alternatively, switch to .First() instead of .FirstOrDefault() if you always expect the registrations to work.
Oh, and if you happen to have two assemblies with Business in them, you might want to make sure you're getting the right one. Assembly load order isn't guaranteed to be consistent.
That said I see the exception message you posted seems to indicate there are some nested exceptions in the stack. Don't stop reading at the first exception. Unfortunately with DI and other layers in the stack, you get exceptions that have inner exceptions that may, themselves, have inner exceptions... and the full set of messages may actually have more information that can help you troubleshoot.
Autofac has a really good troubleshooting page and Autofac v6 has some pretty detailed diagnostics that might help figure out where the missing things are if you can't figure it out from the exceptions.
Related
I would like to integrate Bot composer with Custom actions. The custom actions in turn calls different API to perform some business logic. I would like to inject interfaces and service provider to custom action. I am having trouble in doing this as it is failing and getting in to null pointer exceptions, eventhough I have added everything properly in the startup.cs. Could you please explain how can i achieve this?.
[JsonConstructor]
public MultiplyDialog(IServiceProvider serviceProvider, [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
: base()
{
serviceProvider.GetService<ApiService>() // serviceprovider always null
this.RegisterSourceLocation(sourceFilePath, sourceLineNumber);
}
You have to keep in mind that when using Adaptive Dialogs (that is, the core of Composer) Dialogs are singletons and, when using Composer, they're not instantiated from dependency injection (DI).
Also, since dialogs are singletons, you can't (well, you could but you shouldn't) use services like constructor injected DbContexts and similar (when working with the SDK, that is, coding).
The easiest way to solve this is by using HTTP requests using the HttpRequest action. This is the way that's built into the whole adaptive dialogs ecosystem to achieve this kind of functionality.
If you really insist on doing it with DI into the dialogs, you'd have to solve DI from the TurnContext and you'd have to set it up in the adapter. However, that's a bit convoluted an requires you to use a custom runtime.
UPDATE Added the way to implement DI with adaptive dialogs.
1 - Register the service class in the turn state in the adapter
public class AdapterWithErrorHandler : BotFrameworkHttpAdapter
{
public AdapterWithErrorHandler(
IConfiguration configuration,
ILogger<BotFrameworkHttpAdapter> logger,
//...
QnAClient qnaClient)
: base(configuration, logger)
{
// Add QnAClient to TurnState so we can use it while in the turn
Use(new RegisterClassMiddleware<QnAClient>(qnaClient));
//...
}
}
In the code above QnAClient is an typed HttpClient created with IHttpClientFactory so it's a safe to use singleton.
2 - Get the service from the TurnState wherever you need it
public async Task SetPropertiesAsync(DialogContext context, ...)
{
var qnaClient = context.Context.TurnState.Get<QnAClient>();
//...
}
BTW, this is a nice way to get an HttpClient properly managed by IHttpClientFactory when you register it like this in ConfigureServices:
services.AddHttpClient<QnAClient>()
.AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(new[] { 1, 2, 3, 5, 8, 13 }.Select(t => TimeSpan.FromSeconds(t))))
.AddTransientHttpErrorPolicy(p => p.CircuitBreakerAsync(6, TimeSpan.FromSeconds(30)));
In this case with retry policies from Polly.
The other answer isn't super clear - so I will add some clear snippets. Say you want to inject your service MyService
First, some extra configuration:
services.AddSingleton<IMiddleware, RegisterClassMiddleware<MyService>>(sp => new RegisterClassMiddleware<MyService>(sp.GetRequiredService<MyService>()));
Then in your Dialog:
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{
var myService = dc.Services.Get<MyService>();
}
Done!
I have a C# solution that includes multiple WebAPI projects. One of these projects, let's call it Project A, already uses SimpleInjector successfully. I'm trying to add SimpleInjector to another of these WebAPI projects, Project B, but I'm facing a problem.
I'm trying to create a second container at Project B as I did in Project A, but when I do this and try to build the solution, there is and exception in Project A, which is built after Project B, at the container.Verify() method. It tells me that a interface that is located at Project B (IUserService) is not properly registered at Project A, but Project A doesn't use this interface.
In Project B at Global.asax.cs I have this configuration:
/* Dependency Injection */
var container = new Container();
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
container.Register<IUserService>(() => { return new UserService(); }, Lifestyle.Scoped);
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
In Project A, I have this configuration:
/* Dependency Injection */
var container = new Container();
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
container.Register<ILog>(() => { return LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); }, Lifestyle.Scoped);
container.Register<IFundRepository>(() => { return new IporangaFundRepository(dbConnectorMiddle); }, Lifestyle.Scoped);
container.Register<ITradeRepository>(() => { return new IporangaTradeRepository(dbConnectorMiddle, middleReadClient); }, Lifestyle.Scoped);
container.Register<ITradeManager, TradeManager>(Lifestyle.Scoped);
container.Register<ITradeService>(() => new TradeService(container.GetInstance<ITradeManager>()),Lifestyle.Scoped);
container.Register<ISimulationService>(() => new SimulationService(container.GetInstance<ITradeService>()), Lifestyle.Scoped);
container.Register<IBookerService>(() => new BookerService(container.GetInstance<ITradeService>(), container.GetInstance<ISimulationService>()), Lifestyle.Scoped);
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
The error message:
System.InvalidOperationException: 'The configuration is invalid.
Creating the instance for type UserController failed. The constructor
of type UserController contains the parameter with name 'userService'
and type IUserService that is not registered. Please ensure
IUserService is registered, or change the constructor of
UserController.'
The following is not an answer to your question, but rather a suggestion how to improve and simplify the registrations for Project A.
Instead of using the posted code, I'd suggest using the following code to wire up the Container instance of Project A:
var container = new Container();
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
// For Log4NetAdapter<T>, please see: https://stackoverflow.com/a/25113659
container.RegisterConditional(typeof(ILog),
c => typeof(Log4NetAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
c => true);
container.RegisterInstance(dbConnectorMiddle);
container.RegisterInstance(middleReadClient);
container.Register<IFundRepository, IporangaFundRepository>(Lifestyle.Scoped);
container.Register<ITradeRepository, IporangaTradeRepository(Lifestyle.Scoped);
container.Register<ITradeManager, TradeManager>(Lifestyle.Scoped);
container.Register<ITradeService, TradeService>(Lifestyle.Scoped);
container.Register<ISimulationService, SimulationService>(Lifestyle.Scoped);
container.Register<IBookerService, BookerService(Lifestyle.Scoped);
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container);
This is better because:
Registrations are simplified because they only specify the mapping between the abstraction (e.g. ITradeService) and the implementation (e.g. TradeService), while letting Simple Injector Auto-Wire the types by inspecting the constructors' dependencies.
Not only are the registrations simplified, but now Simple Injector is aware of the structure of the complete dependency graph and can therefore effectively do verification on your behalf. This will, for instance, allow Simple Injector to find any Lifestyle Mismatches.
A conditional registration is used for the ILog abstraction. This allows Simple Injector to inject an ILog implementation specific to the consuming type. This allows your logging library to log information about the originating class. This is something that didn't work in your registration, where it would always inject a logger with a type that contains your registrations.
RegisterWebApiControllers uses reflection under the covers to search for implementations of ApiController.
I guess, based upon the error you get, project B is referenced by project A and the call to container.RegisterWebApiControllers in project A finds and registers the controllers of project B also.
Now when .Verify() is called it will scan the constructors of the ApiControllers in project B, finds a dependency on IUserService and breaks because this registration is actually missing in project A.
The integration package contains another overload for RegisterWebApiControllers which takes an array of assemblies that must be scanned for ApiControllers instead of scanning through all referenced assemblies.
Assuming the assembly of project A contains all ApiControllers that need to be registered this overload can be used in project A like:
container.RegisterWebApiControllers(GlobalConfiguration.Configuration,
new[] {typeof(MyApiControllerInProjectA).Assembly});
I have a code in Web Api Delegating Handler that extract data from request header.
However, I can't register instance in Autofac container because Autofac container require SingleInstance only.
public class ExtractUserNameMessageHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
var userNameFromFrontEnd = request.GetDependencyScope().GetService(typeof (IUserNameFromFrontEnd));
if (userNameFromFrontEnd == null)
{
var updatedContainerBuilder = new ContainerBuilder();
userNameFromFrontEnd = ExtractUserName(request);
if (userNameFromFrontEnd == null)
{
throw new Exception("We've got a request without UserName header");
}
updatedContainerBuilder.RegisterInstance(userNameFromFrontEnd)
.As<IUserNameFromFrontEnd>()
.InstancePerRequest();
var autofacDependencyResolver = GlobalConfiguration.Configuration.DependencyResolver as AutofacWebApiDependencyResolver;
if (autofacDependencyResolver == null)
{
throw new Exception("We can work with Autofac DI container");
}
updatedContainerBuilder.Update(autofacDependencyResolver.Container as IContainer);
}
When I try to update container I get an exception with message - registration can support singleinstance() sharing only.
What does it mean? I can't understand why we have this limitation. But in any cases my first goal - update container with new dependency.
Does anybody have ideas?
(Note: This question was cross-posted to the Autofac forums as well.)
When you register a specific instance, it's effectively a singleton - it's one instance, the instance you provided.
When you try to assign it InstancePerRequest or, really, any other lifetime scope besides SingleInstance, it doesn't make logical sense because you're not going to get a different instance per request (or whatever). You're going to get the exact same instance you registered, which is a singleton.
The exception message is trying to tell you how to avoid incorrect expectations: that it can't provide you a different instance per request even though you told it to because you didn't tell it how to create a new instance, you instead provided a specific instance.
If you need a different instance of an object per lifetime scope/request/whatever, you need to register a type, a delegate, or something else that tells Autofac how to create that new instance.
What that means is that if you want a different IUserNameFromFrontEnd per request, you need to move that logic out of a DelegatingHandler and into an Autofac registration delegate.
// Make sure to register the HttpRequestMessage in the container
// so you can resolve it...
builder.RegisterHttpRequestMessage(httpConfiguration);
// Then, whilst building your root container...
builder
.Register(ctx =>
{
var request = ctx.Resolve<HttpRequestMessage>();
return ExtractUserName(request);
})
.As<IUserNameFromFrontEnd>()
.InstancePerRequest();
Now it will probably do what you're looking to do - because you told Autofac how to create the instance that belongs in each request. It also means you don't need that DelegatingHandler anymore because Autofac will just do the right thing.
More advanced (and probably not useful here, but for completeness):
If, for whatever reason, you still feel like you need to modify the registration directly in the lifetime scope, instead of updating the container you should add the registration when the request lifetime scope is created.
Again, do not update the root container for per-lifetime-scope or per-request dependencies. It's not going to work how you think.
When a new lifetime scope is created, you can add registrations on the fly.
using(var scope = container.BeginLifetimeScope(
builder => builder.RegisterInstance(myfoo).As<IFoo>()))
{
// This will use the registrations in the container
// and the scope. f == myfoo
var f = scope.Resolve<IFoo>();
}
The AutofacDependencyResolver is the thing that creates the request lifetime scope and hands it off to Web API. You can see the full source here. The key method is BeginScope:
public IDependencyScope BeginScope()
{
var lifetimeScope = _container.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
return new AutofacWebApiDependencyScope(lifetimeScope);
}
If you create your own AutofacDependencyResolver you can modify how the scope is created:
public IDependencyScope BeginScope()
{
var lifetimeScope = _container.BeginLifetimeScope(
MatchingScopeLifetimeTags.RequestLifetimeScopeTag,
builder => builder.RegisterInstance(myfoo).As<IFoo>());
return new AutofacWebApiDependencyScope(lifetimeScope);
}
This isn't an explicitly supported extension point in the Autofac Web API integration right now - that's why you'd have to create your own resolver.
However, this seems like overkill to solve the thing it appears you're trying to solve. I strongly recommend just registering the delegate with Autofac rather than trying to update existing containers or scopes. You will have far more luck using the path of least resistance.
We're looking at using an AOP framework for handling things like logging, tracing, and exception handling. I've built a prototype using PostSharp and now I'm trying to build the same functionality using AspectMap.
In a nutshell, I have an ASP.NET MVC 3 application and I want an aspect that I can easily attach to my controller methods that shows the entry, exit, execution time, and argument values. My PoC is the basic MVC 3 Internet Application template (File > New > Project > Web > ASP.NET MVC 3 Web Application > Internet). What I've done so far...
Created an AspectsRegistry
public class PoCRegistry : AspectsRegistry
{
public PoCRegistry()
{
ForAspect<ProfileAttribute>().HandleWith<ProfileHandler>();
}
}
Created a StructureMapControllerFactory
public class StuctureMapControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance( RequestContext requestContext, Type controllerType )
{
if( controllerType == null ) return null;
try
{
return ObjectFactory.GetInstance( controllerType ) as Controller;
}
catch( StructureMapException )
{
Debug.WriteLine( ObjectFactory.WhatDoIHave() );
throw;
}
}
}
Registered everything in Application_Start
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters( GlobalFilters.Filters );
RegisterRoutes( RouteTable.Routes );
ObjectFactory.Initialize( ie => ie.AddRegistry( new PoCRegistry() ) );
ControllerBuilder.Current.SetControllerFactory( new StuctureMapControllerFactory() );
}
At this point the application works, and I can see it's using my StructureMapControllerFactory to build the controller (debugger steps into that code). The problem is that I can't figure out where or how to "enrich" the controller that is generated. In the tutorial it says I need to use something like the following:
For<ICaseController>()
.Use<CaseController>()
.EnrichWith( AddAspectsTo<CaseController> );
But in the tutorial that goes in the AspectRegistry, which doesn't seem like the right place in this situation because the registry isn't responsible for resolving the controller request, the controller factory is. Unfortunately the GetInstance() method in the controller factory returns an object and the EnrichWith() method needs a SmartInstance.
At this point I'm stuck. Any hints, pointers, or assistance would be appreciated.
This is a use case I hadn't thought about to be honest. I'll setup a test project today and see what I can come up with. Bear with me!
Update
I've been playing around with the backend code (you can get a complete copy of the code from http://aspectmap.codeplex.com) and the relevant part is this:
public T AddAspectsTo<T>(T concreteObject)
{
ProxyGenerator dynamicProxy = new ProxyGenerator();
return (T)dynamicProxy.CreateInterfaceProxyWithTargetInterface(typeof(T), concreteObject,
new[] { (IInterceptor)new AspectInterceptor(attributeMap) });
}
This is using the castle dynamic proxy stuff. Unfortunately the CreateInterfaceProxy... methods require that an interface is passed in (rather than a base class like I'd hoped). Now I've found this question:
C# Dynamic Proxy 2 generate proxy from class with code in constructor ? How to?
That seems to show that it could be possible to use CreateClassProxy. I've not had chance to try this out yet and I'm going away for a week away from the computer. If you want to try and wire it up though you're welcome to get the source from codeplex and give it a try though. If not I'll put something together when I return.
Action filters can be used to provide such AOP functionality.
http://www.asp.net/mvc/tutorials/older-versions/controllers-and-routing/understanding-action-filters-cs
http://msdn.microsoft.com/en-us/library/dd410056%28v=vs.90%29.aspx
I upgraded from the ASP.NET Web API release on nuget.org (the version before the RC on Friday) to the nightly builds on myget.org. As expected there were many breaking changes, and one of them I can't seem to get around: We have a scenario where we want our action to return an object and set the status code to 201 Created. This was quite easily done before (might not compile - conceptual code from the top of my head):
Session session = GetSessionInfo(requestMessage);
var response = new HttpResonseMessage(HttpStatusCode.Created);
response.Content = response.CreateContent(session);
return response;
CreateContent was actually an extension method located in System.Net.Http.HttpResponseMessageExtensions calling an internal constructor in ObjectContent. With the new release HttpResponseMessageExtensions seems to be gone in the new release and so does the internal constructors of ObjectContent. Now it seems I must call an ObjectContent constructor, and the following seems to be the most appropriate for our needs:
public class ObjectContent<T> : ObjectContent
{
public ObjectContent(T value, MediaTypeFormatter formatter)
{
}
}
However it seems I have to pass a MediaTypeFormatter into it, mixing content negotiation into the logic of the action. In our setup content negotiation is generic and completely decoupled from the controllers.
Does anyone have a suggestion for solving the scenario to return an object, set the response status code, but not have to deal with MediaTypeFormatter, media type or any other content negotiation related stuff?
We redesigned how ObjectContent<T> creation works. Starting with the RC, you should be calling the CreateResponse() set of extension methods (they're off HttpRequestMessage). This will actually produce an instance of HttpResponseMessage with an instance of a content-negotiated ObjectContent<T> inside. So, something like:
Session session = GetSessionInfo(requestMessage);
var response = Request.CreateResponse(HttpStatusCode.Created, session);
return response;