简体   繁体   English

SimpleInjector和SDammann WebAPI版本控制

[英]SimpleInjector and SDammann WebAPI versioning

I try to configer the SimpleInjector container to use it with the SDammann WebAPI Versioning 我尝试配置SimpleInjector容器以将其与SDammann WebAPI版本控制一起使用

I have this in my WebAPI config.. 我的WebAPI配置中有这个。

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 当我只测试测试控制器时,一切正常-> 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... 顺便说一句,我的Global.asax看起来像这样...

 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. 但是我是Web开发之类的新手。 In my daily job i am using BizTalk and that stuff. 在我的日常工作中,我正在使用BizTalk和类似的东西。 :) But i want to learn new stuff. :)但是我想学习新的东西。 :) :)

EDIT FROM THIS POINT 从这个点编辑

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... 我的WebApi现在看起来像这样...控制器仍然相同...

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... 编辑:MVC应用程序现在,当我进行测试->'PostMan a chrome app'时,我会得到一些回报。现在,我尝试在ASP.Net MVC应用程序中执行此操作...

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. accountController是默认的accountcontroller ...我的全局文件在MVC应用程序中看起来像这样。

Just like the guide on.... , no? 就像上面的指南一样...,不? https://simpleinjector.readthedocs.org/en/latest/mvcintegration.html 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. FindOilTypesQueryHandler类型的构造函数包含IVdbQueryContext类型的参数,名称为“ vdbQueryContext”,未注册。 Please ensure IVdbQueryContext is registered in the container, or change the constructor of FindOilTypesQueryHandler. 请确保IVdbQueryContext已在容器中注册,或更改FindOilTypesQueryHandler的构造函数。

This means that the IVdbQueryContext isn't registered. 这意味着未注册IVdbQueryContext It is easy to see why, because you create two Container instances. 很容易理解为什么,因为您创建了两个Container实例。 The second one (in the Application_Start method) contains this IVdbQueryContext registration, but that instance is never used. 第二个(在Application_Start方法中)包含此IVdbQueryContext注册,但是从不使用该实例。 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. 第一个(在Register方法中)注册为DependencyResolver ,因此由Web API使用它来解析您的控制器,但是此实例不包含IVdbQueryContext注册。

Best practice is to have one single container instance per application . 最佳实践是每个应用程序只有一个容器实例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM