WebApi controller - asp.net-web-api

I try to integrate autofac for webapi and I am having problem to make it work.
My controller constructor signature is:
public class AController: ApiController
{
public AController(IComponentContext componentContext)
{}
}
In my global.asax file i have called the following code in Application_Start
protected void Application_Start()
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers();
container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
}
When I try to run my application and to access my ressource "/api/A", the server returns an error 500 complaining about the fact the controller does not have a default constructor. I though that was the task of the AutofacWebApiDependencyResolver to inject the container in my case. How can I fix my issue ?
Thanks,

I have found my issue .
Update this line to
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
sort the issue out.

Related

Autofac not resolving constructor parameter for WebAPI2 controllers

I'm trying to use Autofac for DI container for an Asp.Net MVCApplication with WebApi2 and OWIN. My global.asax.cs has nothing in the Application_Start(). My startup.cs has the following Configuration:
public void Configuration(IAppBuilder app)
{
DependencyInjectionConfig.Configure(app);
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
And DependencyInjectionConfig.Configure is:
public static void Configure(IAppBuilder app)
{
var config = new HttpConfiguration(); //this means webapi controllers don't use DI container
//var config = GlobalConfiguration.Configuration; //this makes MVC view controllers fail to do anything
var builder = new ContainerBuilder();
var assm = Assembly.GetExecutingAssembly();
//MVC and WebAPI Controllers
builder.RegisterControllers(assm);
builder.RegisterApiControllers(assm);
WebApiConfig.Register(config);
//Model Binders
builder.RegisterModelBinders(assm);
builder.RegisterModelBinderProvider();
//Modules
builder.RegisterModule<AutofacWebTypesModule>();
//MVC Views
builder.RegisterSource(new ViewRegistrationSource());
//MVC and WebAPI Filters
builder.RegisterFilterProvider();
builder.RegisterWebApiFilterProvider(config);
//Finally, Any custom registrations
RegisterComponents(builder, assm);
/* My items show in the builder as expected at this point */
//build the container
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
//Special OWIN bits
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
app.UseAutofacWebApi(config);
app.UseWebApi(config);
}
My problem is that Autofac does not seem do any parameter resolution regardless of if I use var config = new HttpConfiguration(); or var config = GlobalConfiguration.Configuration;. bonus, if I use GlobalConfiguration.Configuration MVC controllers for views completely fails.
The ApiController is pretty straight-forward:
public class MessagesController : ApiController
{
private IMesageHandler MessageHandler {get; set;}
public MessagesController(IMessageHandler messageHandler)
{
this.MessageHandler = messageHandler;
}
[HttpGet]
public string Get()
{
return "Hello World";
}
}
The exception is that it can't find a parameterless constructor (because the Autofac container appears to be napping).

Web API Nunit Tests not injecting dependencies

When trying to unit test my web api project I am getting the error
{[Message, An error has occurred.]}
ExceptionMessage, An error occurred when trying to create a controller of type 'ExampleController'. Make sure that the controller has a parameterless public constructor.
{[ExceptionType, System.InvalidOperationException]}
{[StackTrace, 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.d__1.MoveNext()]}
{[InnerException, System.Web.Http.HttpError]}
Unit Test:
[TestFixtureSetUp]
public void TestsSetup()
{
_server = HttpRequestHelper.SetupHttpServerDefault();
}
[Test]
public void CanGetAllAddresses()
{
var client = new HttpClient(_server);
var request = HttpRequestHelper.CreateRequest("memory/address", HttpMethod.Get, ConfigurationManager.AppSettings["KeyUser"], string.Empty, ConfigurationManager.AppSettings["SecretUser"]);
using (HttpResponseMessage response = client.SendAsync(request).Result)
{
Assert.NotNull(response.Content);
}
}
I am registering my controllers within an nunit TestFixtureSetUp function that involves this logic:
public static HttpServer SetupHttpServerDefault()
{
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "memory/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var container = new Container();
container.Register<IAddressService, AddressService>();
var services = GlobalConfiguration.Configuration.Services;
var controllerTypes = services.GetHttpControllerTypeResolver().
GetControllerTypes(services.GetAssembliesResolver());
foreach (var controllerType in controllerTypes)
{
var registration = Lifestyle.Transient.
CreateRegistration(controllerType, container);
container.AddRegistration(controllerType, registration);
registration.SuppressDiagnosticWarning
(DiagnosticType.DisposableTransientComponent, "");
}
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver = new
SimpleInjectorWebApiDependencyResolver(container);
return new HttpServer(config);
}
My address controller starts out like this:
public class AddressController : BaseController
{
private readonly IAddressService _addressService;
public AddressController(IAddressService addressService)
{
_addressService = addressService;
}
}
When removing the controller parameters I am able to debug into the controller which tells me I am not injecting the dependencies into the controller correctly. I've looked over this post here that seems similar but I am unfamiliar with how I would explicitly declare my controllers. I tried using a similar method to my services but I did not work.
The solution for my particular problem was actually to register the dependency resolver on both the in memory HttpServer that I am creating in the tests and on the GlobalConfiguration as well. Above in the question you'll see the creation of the config variable and then this is the code that fixed my issues:
config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container);
Without the config.DependencyResolver I wasn't able to connect to my projects controllers via:
using (HttpResponseMessage response = client.SendAsync(request).Result)
And without GlobalConfiguration.Configuration.DependencyResolver I wasn't able to contact services locally in my test project. Hope this helps someone else!

MVC5 dependency injection issue

I have created an application using MVC5 with the onion architecture approach. The solution contains 3 projects (core, infrastructure, and UI). The UI contains both Web API controllers and MVC controllers. The issue I’m running into is dependency injection. I have installed Unity.MVC5 & Unity.WebApi. My UnityConfig.cs under App_Start Looks like this:
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<IPricingService, PricingService>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
My global.asax looks like this:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
System.Web.Http.GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
UnityConfig.RegisterComponents();
}
To test out my controller, I defined my home controller like this:
private readonly IPricingService _pricingService;
public HomeController(IPricingService PricingService)
{
this._pricingService = PricingService;
}
When running home page I get
No parameterless constructor defined for this object.
Now, moving to another test scenario, I created a web api controller and looks like this:
private readonly IPricingService _pricingService;
public TestApiController(IPricingService PricingService)
{
this._pricingService = PricingService;
}
Testing the web api generates this error:
An error occurred when trying to create a controller of type 'TextApiController'. Make sure that the controller has a parameterless public constructor.","exceptionType":"System.InvalidOperationException"
Not sure what I'm missing. Please advise.
You are supposed to inject the Unity.WebApi.DependencyResolver into the WebApi configuration not in GlobalConfiguration.Configuration.DependencyResolver.
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
container.RegisterType<IProductRepository, ProductRepository>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);
// Other Web API configuration not shown.
}
You also need to implement a child container in the BeginScope method as shown in this MSDN article.

Structure Map parameterless constructor error

I am trying to set up structure map ver 3.0.5.0 with Web API 2.
I have followed this implementation: Configuring dependency injection with ASP.NET Web API 2.1
However, I am getting this error when doing a get against my ComplexesController:
An error occurred when trying to create a controller of type 'ComplexesController'. Make sure that the controller has a parameterless public constructor.
Can anyone see what is wrong with my structuremap config? The Create method never gets called.
This is my implementation:
public class StructureMapControllerActivator : IHttpControllerActivator
{
private readonly IContainer _container;
public StructureMapControllerActivator(IContainer container)
{
if (container == null) throw new ArgumentNullException("container");
_container = container;
}
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
try
{
var scopedContainer = _container.GetNestedContainer();
scopedContainer.Inject(typeof(HttpRequestMessage), request);
request.RegisterForDispose(scopedContainer);
return (IHttpController)scopedContainer.GetInstance(controllerType);
}
catch (Exception e)
{
// TODO : Logging
throw e;
}
}
}
This method is in my startup...
public void InitializeContainer()
{
// STRUCTURE MAP
Container container = new Container();
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new StructureMapControllerActivator(container));
container.Configure(x => x.For<IForumRepository>().Use<ForumRepository>());
container.Configure(x => x.For<IComplexRepository>().Use<ComplexRepository>());
}
.. and this is the controller:
public class ComplexesController : ApiController
{
private IComplexRepository _repo;
public ComplexesController(IComplexRepository repo)
{
_repo = repo;
}
// GET: api/Complexes
public IList<Complex> GetComplexes()
{
var complexes = _repo.GetList();
return complexes;
}
...
My full Startup class
[assembly: OwinStartup(typeof(AngularJSAuthentication.API.Startup))]
namespace AngularJSAuthentication.API
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);
}
}
}
The problem here is that you are registering your service activator with a GlobalConfiguration object and not your HttpConfiguration object. In this scenario The GlobalConfiguration object is never used as it is replaced by the HttpConfiguration object. In order to solve your issue you should replace your InitializeContainer() method with the following.
public void InitializeContainer(HttpConfiguration config)
    {
        // STRUCTURE MAP
        Container container = new Container();
        config.Services.Replace(typeof(IHttpControllerActivator), new StructureMapControllerActivator(container));
        container.Configure(x => x.For<IForumRepository>().Use<ForumRepository>());
        container.Configure(x => x.For<IComplexRepository>().Use<ComplexRepository>());        
    }
you should then pass the HttpConfiguration object from your Startup class to the new InitializeContainer() method.
Hope this helps.
-B
I am trying to gain a solid understanding of the complete lifecycle. I think my setup may be slightly different to the above. Here is what worked for me.
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
var container = IocConfig.Setup();
// Allow a controller to be declared without a parameterless constructor
config.DependencyResolver = new DependencyResolver(container);
config.Services.Add( typeof(IExceptionLogger), new GlobalExceptionLogger( container.GetInstance<ILoggingService>()));
// Web API routes
config.MapHttpAttributeRoutes();
// Setup Authentication
ConfigureOAuth(app, container);
var corsOptions = CorsOptions.AllowAll;
app.UseCors(corsOptions);
// Add ASP.Net Web API to OWIN pipeline
app.UseWebApi(config);
}
}
It worked after I added this line:
// Allow a controller to be declared without a parameterless constructor
config.DependencyResolver = new DependencyResolver(container);
You have to get that my var container loads from a static class called IocConfig with a static Setup method. This is where the interfaces are mapped to their concrete implementations.
Also, you can probably ignore the GlobalExceptionLogger line if you want to use my complete example.

How do I use Universal Membership Provider, EF, and MiniProfiler together?

If I use the Universal Membership Provider and a seperate database, Entity Framework and enable Mini Profiler for EF 4.2. I get error {"There is already an object named 'Applications' in the database."} when I first hit a line checking user credentials in my home view.
If I turn remove MiniProfilerEF.Initialize(); then I stop getting the error.
Any ideas?
Can I stop profiling the defaultconnection?
I have been banging my head against this issue for awhile now. Did some more digging today and was able to get it working. Here is what I did. In MiniProfiler.cs I defined two methods as follows:
public static DbConnection GetConnection()
{
var connectionString = ConfigurationManager.ConnectionStrings["MyModelConnectionString"].ConnectionString;
var entityConnStr = new EntityConnectionStringBuilder(connectionString);
var realConnection = new SqlConnection(entityConnStr.ProviderConnectionString);
return realConnection;
}
public static IMyModelsInterface GetProfiledContext()
{
var connection = new MvcMiniProfiler.Data.EFProfiledDbConnection(GetConnection(), MiniProfiler.Current);
var context = connection.CreateObjectContext<MyModel>();
return context;
}
NOTE: These two methods probably shouldn't be defined in MinProfilerPackage, but this was my first past/hack to get it working.
Then call GetProfiledContext() and use the context returned whenever you want the queries profiled. I injected this profile context into my controller factory using Ninject. My call looks something like this:
public NinjectControllerFactory()
{
ninjectKernel = new StandardKernel();
AddBindings();
}
private void AddBindings()
{
var context = MiniProfilerPackage.GetProfiledContext();
IUnitOfWork uow = new UnitOfWork(context);
ninjectKernel.Bind<IRepository>().To<GenericRepository>().WithConstructorArgument("paramUnitOfWork", uow);
// ... rest of the method
}
NinjectControllerFactory is my controller factory that gets set in Application_Start.
protected void Application_Start()
{
// Add in DI for controller and repo associations
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
// ... rest of the method
}

Resources