InRequestScope действует как InTransientScope - PullRequest
6 голосов
/ 17 июня 2020

У меня есть веб-приложение ASP. NET (. NET Framework 4.8), в котором я настроил NInject, но все службы, которые я установил с помощью InRequestScope, проходят, как если бы переходная область (т.е. новые экземпляры создаются для каждой сущности, которая зависит от нее - в рамках одного и того же веб-запроса).

Я использую следующие пакеты NuGet (последние):

  1. Ninject v3.3.4
  2. Ninject.Web.Common v.3.32 («Загрузчик для веб-проектов»)

App_Start\Ninject.Web.Common.cs присутствует и является правильным и выглядит следующим образом:

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(ScormWebService.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(ScormWebService.App_Start.NinjectWebCommon), "Stop")]

namespace ScormWebService.App_Start
{
    using Microsoft.Web.Infrastructure.DynamicModuleHelper;
    using Ninject;
    using Ninject.Web.Common;
    using Ninject.Web.Common.WebHost;
    using Services;
    using System;
    using System.Web;

    public static class NinjectWebCommon
    {
        private static readonly Bootstrapper bootstrapper = new Bootstrapper();
        public static IKernel Kernel { get; private set; }

        /// <summary>
        /// Starts the application
        /// </summary>
        public static void Start()
        {
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
            DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
            bootstrapper.Initialize(CreateKernel);
        }

        /// <summary>
        /// Stops the application.
        /// </summary>
        public static void Stop()
        {
            bootstrapper.ShutDown();
        }

        /// <summary>
        /// Creates the kernel that will manage your application.
        /// </summary>
        /// <returns>The created kernel.</returns>
        private static IKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            try
            {
                RegisterServices(kernel);
                return kernel;
            }
            catch
            {
                kernel.Dispose();
                throw;
            }
        }

        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel</param>
        private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
            kernel.Bind<IDumpConfigService>().To<DumpConfigService>().InSingletonScope();

            // These objects are created fresh for each request
            kernel.Bind<ILogService>().To<LogService>().InRequestScope();
            kernel.Bind<IDumpService>().To<DumpService>().InRequestScope();
            kernel.Bind<ISaveDataRequestReader>().To<SaveDataRequestReaderXml>().InRequestScope();
            kernel.Bind<ISaveDataResponseWriter>().To<SaveDataResponseWriterXml>().InRequestScope();
            kernel.Bind<IHttpContextAccessor>().To<HttpContextAccessor>().InRequestScope();

            Kernel = kernel;
        }
    }
}

Входящий запрос на самом деле является реализацией IHttpHandler (т.е. файл ashx, а не aspx). Однако это по-прежнему запрос страницы с текущим запросом и HttpContext.Current.

Вот как я настраиваю объекты для запроса страницы

public class SaveDataHandler : IHttpHandler, IRequiresSessionState
{
    /// <summary>
    /// A new handler is required for each and every incoming request
    /// </summary>
    public bool IsReusable => false;

    public SaveDataHandler()
    {
        var kernel = App_Start.NinjectWebCommon.Kernel;
        LogService = (ILogService)kernel.GetService(typeof(ILogService));
        Reader = (ISaveDataRequestReader)kernel.GetService(typeof(ISaveDataRequestReader));
        Writer = (ISaveDataResponseWriter)kernel.GetService(typeof(ISaveDataResponseWriter));
        DumpService = (IDumpService)kernel.GetService(typeof(IDumpService));
    }

}

Так, например, в конструкторе SaveDataHandler для каждого запроса создаются три экземпляра ILogService вместо одного: SaveDataHandler сам запрашивает его (см. выше), как и class DumpService : IDumpService и class SaveDataRequestReaderXml : ISaveDataRequestReader.

Может ли кто-нибудь дать представление Что касается того, почему InRequestScope действует как переходный осциллограф? Я подозреваю, что причина в использовании страницы IHttpHandler (ashx) вместо страницы веб-формы (aspx), но я не понимаю, почему это не сработает, поскольку HttpContext.Current одинаков во всем запросе, и это то, что NInject.Web.Common используется в качестве идентификатора области запроса. Я создал страницу WebForm.aspx, но такая же проблема возникает и для нее, поэтому она не указывает c на ashx / IHttpHandler запросы:

namespace ScormWebService
{
    public partial class WebForm1 : Page
    {
        protected void Page_Init(object sender, EventArgs e)
        {
            var kernel = App_Start.NinjectWebCommon.Kernel;
            var LogService = (ILogService)kernel.GetService(typeof(ILogService));
            var Reader = (ISaveDataRequestReader)kernel.GetService(typeof(ISaveDataRequestReader));
            var Writer = (ISaveDataResponseWriter)kernel.GetService(typeof(ISaveDataResponseWriter));
            var DumpService = (IDumpService)kernel.GetService(typeof(IDumpService));
            // At this point, three instances of LogService have been created.
        }
    }
}

Изменить: я создал fre sh минимальный ASP. NET проект веб-форм, который воспроизводит проблему, которую вы можете скачать здесь , но все основные элементы уже описаны в код выше.

Спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...