I try to configer the SimpleInjector container to use it with the SDammann WebAPI Versioning
I have this in my WebAPI config..
public static class WebApiConfig
{
public sealed class AcceptHeaderRequestVersionDetector : SDammann.WebApi.Versioning.Request.AcceptHeaderRequestVersionDetector
{
protected override ApiVersion GetVersionFromSingleHeader(MediaTypeWithQualityHeaderValue headerValue)
{
string rawVersion = headerValue.Parameters.First(x => x.Name == "version").Value;
int version = Convert.ToInt32(rawVersion);
return new SemVerApiVersion(
new Version(version, 0)
);
}
}
public static void Register(HttpConfiguration config)
{
Container container = new Container();
container.Register<DefaultControllerIdentificationDetector>();
container.Register<DefaultRequestControllerIdentificationDetector>();
container.Register<HttpConfiguration>(() => config);
config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
container.Verify();
config.Services.Replace(typeof(IHttpControllerSelector), new VersionedApiControllerSelector(config));
ApiVersioning.Configure()
.ConfigureRequestVersionDetector<AcceptHeaderRequestVersionDetector>();
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
My controllers are available in the following folders....
When i just test the test controller everything works fine --> http:localhost/VDB.Service.WebAPI/Api/Test
Code below
public class TestController : ApiController
{
[HttpGet]
public string Version()
{
return "Version 1";
}
}
When i try it with some other stuff like below then i get an error.... See picture below this code
public class OilTypesController : ApiController
{
private readonly IRequestHandler<FindOilTypesQuery,FindOilTypesQueryResult> _findOilTypesQueryHandler;
private readonly IRequestHandler<CreateOilTypeCommand, CreateOilTypeCommandResult> _createOilTypeCommandHandler;
public OilTypesController(FindOilTypesQueryHandler findOilTypesQueryHandler, CreateOilTypeCommandHandler createOilTypeCommandHandler)
{
_findOilTypesQueryHandler = findOilTypesQueryHandler;
_createOilTypeCommandHandler = createOilTypeCommandHandler;
}
[HttpPost]
public CreateOilTypeCommandResult CreateOilType(CreateOilTypeCommand command)
{
var result = _createOilTypeCommandHandler.Execute(command);
return result;
}
[HttpGet]
public IQueryable<OilTypeSummaryModel> GetOilTypes(ODataQueryOptions<OilType> oDataQuery)
{
var query = new FindOilTypesQuery(oDataQuery);
return _findOilTypesQueryHandler.Execute(query).OilTypes.ToOilTypeSummaryModel();
}
}
BTW my Global.asax looks like this...
public class WebApiApplication : HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
Container container = new Container();
container.RegisterManyForOpenGeneric(typeof(IRequestHandler<,>), Assembly.GetExecutingAssembly());
container.Register<IVdbCommandContext, VdbCommandContext>(Lifestyle.Transient);
container.Register<IVdbQueryContext, VdbQueryContext>(Lifestyle.Transient);
GlobalConfiguration.Configuration.Filters.Add(new ExceptionHandlerFilter());
// Force code first migrations to check database and migrate if required
Database.SetInitializer(new MigrateDatabaseToLatestVersion<VdbCommandContext, Configuration>());
VdbCommandContext vdbCommandContext = new VdbCommandContext();
vdbCommandContext.Database.Initialize(true);
}
}
It could be that this are some basic things. But i am new to Webdevelopment and that stuff. In my daily job i am using BizTalk and that stuff. :) But i want to learn new stuff. :)
I now get the following error, but i don't know why...
{
"Message": "An error has occurred.",
"ExceptionMessage": "An error occurred when trying to create a controller of type 'OilTypesController'. 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.<SendAsync>d__1.MoveNext()",
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "No registration for type OilTypesController could be found and an implicit registration could not be made. The constructor of type OilTypesController contains the parameter of type IRequestHandler<FindOilTypesQuery, FindOilTypesQueryResult> with name 'findOilTypesQueryHandler' that is not registered. Please ensure IRequestHandler<FindOilTypesQuery, FindOilTypesQueryResult> is registered in the container, or change the constructor of OilTypesController.",
"ExceptionType": "SimpleInjector.ActivationException",
"StackTrace": " at SimpleInjector.InstanceProducer.GetInstance()\ \ at SimpleInjector.Container.GetInstance(Type serviceType)\ \ at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)",
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "The constructor of type OilTypesController contains the parameter of type IRequestHandler<FindOilTypesQuery, FindOilTypesQueryResult> with name 'findOilTypesQueryHandler' that is not registered. Please ensure IRequestHandler<FindOilTypesQuery, FindOilTypesQueryResult> is registered in the container, or change the constructor of OilTypesController.",
"ExceptionType": "SimpleInjector.ActivationException",
"StackTrace": " at SimpleInjector.Advanced.DefaultConstructorInjectionBehavior.BuildParameterExpression(ParameterInfo parameter)\ \ at SimpleInjector.ContainerOptions.BuildParameterExpression(ParameterInfo parameter)\ \ at SimpleInjector.Registration.BuildConstructorParameters(ConstructorInfo constructor)\ \ at SimpleInjector.Registration.BuildNewExpression(Type serviceType, Type implementationType)\ \ at SimpleInjector.Registration.BuildTransientExpression[TService,TImplementation]()\ \ at SimpleInjector.Registration.BuildExpression(InstanceProducer producer)\ \ at SimpleInjector.InstanceProducer.BuildExpressionInternal()\ \ at System.Lazy`1.CreateValue()\ \ --- End of stack trace from previous location where exception was thrown ---\ \ at SimpleInjector.InstanceProducer.BuildInstanceCreator()\ \ at SimpleInjector.InstanceProducer.GetInstance()"
}
}
}
My WebApi looks now likes this... Controller is still the same...
public static class WebApiConfig
{
public sealed class AcceptHeaderRequestVersionDetector : SDammann.WebApi.Versioning.Request.AcceptHeaderRequestVersionDetector
{
protected override ApiVersion GetVersionFromSingleHeader(MediaTypeWithQualityHeaderValue headerValue)
{
string rawVersion = headerValue.Parameters.First(x => x.Name == "version").Value;
int version = Convert.ToInt32(rawVersion);
return new SemVerApiVersion(
new Version(version, 0)
);
}
}
public static void Register(HttpConfiguration config)
{
Container container = new Container();
container.Register<DefaultControllerIdentificationDetector>();
container.Register<DefaultRequestControllerIdentificationDetector>();
container.Register(() => config);
container.RegisterManyForOpenGeneric(typeof(IRequestHandler<,>), Assembly.GetExecutingAssembly());
container.Register<IVdbCommandContext, VdbCommandContext>();
container.Register<IVdbQueryContext, VdbQueryContext>();
GlobalConfiguration.Configuration.Filters.Add(new ExceptionHandlerFilter());
config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
container.Verify();
config.Services.Replace(typeof(IHttpControllerSelector), new VersionedApiControllerSelector(config));
ApiVersioning.Configure()
.ConfigureRequestVersionDetector<AcceptHeaderRequestVersionDetector>();
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
SECOND EDIT
public class FindOilTypesQueryHandler: IRequestHandler<FindOilTypesQuery,FindOilTypesQueryResult>
{
private readonly IVdbQueryContext _vdbQueryContext;
public FindOilTypesQueryHandler(IVdbQueryContext vdbQueryContext)
{
_vdbQueryContext = vdbQueryContext;
}
public FindOilTypesQueryResult Execute(FindOilTypesQuery request)
{
var oilTypes = request.ODataQuery.ApplyTo(_vdbQueryContext.OilTypes).Cast<OilType>();
return new FindOilTypesQueryResult(oilTypes);
}
}
EDIT: MVC Application I get now something back when i do a test --> 'PostMan a chrome app' Now i try to do that in an ASP.Net MVC application...
But i get the error...
For the container to be able to create AccountController, it should contain exactly one public constructor, but it has 2.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: SimpleInjector.ActivationException: For the container to be able to create AccountController, it should contain exactly one public constructor, but it has 2.
Source Error:
Line 27: container.RegisterMvcIntegratedFilterProvider();
Line 28:
Line 29: container.Verify();
Line 30:
Line 31: DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
The accountController is the default accountcontroller... My Global file looks like this in my MVC application.
Just like the guide on.... , no?https://simpleinjector.readthedocs.org/en/latest/mvcintegration.html
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
Container container = new Container();
container.Register<IVdbService, VdbService>();
container.Register<IRequestExecutor,RequestExecutor>();
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.RegisterMvcIntegratedFilterProvider();
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
} }
The exception is pretty clear:
The constructor of type FindOilTypesQueryHandler contains the parameter of type IVdbQueryContext with name 'vdbQueryContext' that is not registered. Please ensure IVdbQueryContext is registered in the container, or change the constructor of FindOilTypesQueryHandler.
This means that the IVdbQueryContext
isn't registered. It is easy to see why, because you create two Container
instances. The second one (in the Application_Start
method) contains this IVdbQueryContext
registration, but that instance is never used. The first one (in the Register
method) is registered as DependencyResolver
and therefore used by Web API for resolving your controllers, but this instance does not contain the IVdbQueryContext
registration.
Best practice is to have one single container instance per application.