public virtual void ConfigureServices(IServiceCollection services)
        {
            var valueTranslatorFilter = new ValueTranslatorFilter(TranslatorService, GetTranslatorClientName);
            var mvc = services.AddMvc(opts => { opts.Filters.Add(valueTranslatorFilter); });

            mvc.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }
        /// <summary>
        /// This method will be called indirectly from the program's Main method to configure the services
        /// </summary>
        /// <remarks>
        /// Don't override this method unless you really know what you are doing.
        /// First see if the following methods could be good enough for your needs:
        /// Always override <see cref="GetSynchronousFastLogger"/> to establish your preferred way of logging.
        /// Always override <see cref="DependencyInjectServices(IServiceCollection)"/> to inject your own services.
        /// Override <see cref="ConfigureServicesInitialUrgentPart"/> if you have things that needs to be initialized early.
        /// Override <see cref="ConfigureServicesSwagger"/> if you want to change how swagger is set up.
        /// </remarks>
        public virtual void ConfigureServices(IServiceCollection services)
        {
            try
            {
                FulcrumApplication.Validate();
                ConfigureServicesInitialUrgentPart(services);
                FulcrumApplication.ValidateButNotInProduction();
                InternalContract.RequireValidated(this, GetType().FullName);
                ConfigureServicesSwagger(services);
                DependencyInjectServices(services);
                using (var serviceScope = services.BuildServiceProvider().CreateScope())
                {
                    ValueTranslatorFilter valueTranslatorFilter = null;
                    var serviceProvider = serviceScope.ServiceProvider;
                    DependencyInjectServicesAdvanced(services, serviceProvider);
                    if (IsBusinessApi)
                    {
                        var translatorService = serviceProvider.GetService <ITranslatorService>();
                        if (translatorService == null)
                        {
                            Log.LogWarning($"Could not resolve {nameof(ITranslatorService)}");
                        }
                        else
                        {
                            ValueTranslatorHttpSender.TranslatorService = translatorService;
                            valueTranslatorFilter = new ValueTranslatorFilter(
                                translatorService,
                                () => FulcrumApplication.Context?.ClientPrincipal?.Identity?.Name);
                        }
                    }
                    var mvc = services.AddMvc(opts =>
                    {
                        if (IsBusinessApi && valueTranslatorFilter != null)
                        {
                            opts.Filters.Add(valueTranslatorFilter);
                        }
                        if (!FulcrumApplication.IsInDevelopment)
                        {
                            return;
                        }
                        Log.LogWarning($"Anonymous service usage is allowed, due to development mode.");
                        opts.Filters.Add(new AllowAnonymousFilter());
                    });
                    mvc
                    .SetCompatibilityVersion(CompatibilityVersion)
                    .ConfigureApplicationPartManager(apm =>
                                                     apm.FeatureProviders.Add(new RemoveRedundantControllers(_controllersToKeep)));
                    AddControllersToMvc(services, mvc);
                }

                Log.LogInformation($"{nameof(StartupBase)}.{nameof(ConfigureServices)} succeeded.");
            }
            catch (Exception e)
            {
                Log.LogCritical(
                    $"{nameof(StartupBase)}.{nameof(ConfigureServices)} failed. The application {FulcrumApplication.Setup?.Name} needs to be restarted.: {e.Message}",
                    e);
                throw;
            }
        }
        public async Task TranslatorServiceIsNotCalledForIfNoTranslations()
        {
            // Mock a translator
            var testServiceMock = new Mock <ITranslatorService>();

            testServiceMock
            .Setup(service => service.TranslateAsync(It.IsAny <IEnumerable <string> >(), It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .ThrowsAsync(new Exception("ITranslatorService should not be called if no translations"));

#if NETCOREAPP
            var foosController             = new FoosController();
            var controllerActionDescriptor = new ControllerActionDescriptor();
            controllerActionDescriptor.MethodInfo = foosController.GetType().GetMethod(nameof(foosController.ServiceTenant));
            var actionContext = new ActionContext
            {
                HttpContext      = new DefaultHttpContext(),
                RouteData        = new RouteData(),
                ActionDescriptor = controllerActionDescriptor
            };
            var executingContext = new ResultExecutingContext(actionContext, new List <IFilterMetadata>(), new ObjectResult(FulcrumApplication.Setup.Tenant), foosController);
#else
            var contextMock = CreateExecutedContextWithStatusCode(HttpStatusCode.OK, FulcrumApplication.Setup.Tenant);
#endif

            // Setup the filter
            var filter = new ValueTranslatorFilter(testServiceMock.Object, () => Foo.ConsumerName);

            // Run the filter
            // There are no translations, so ITranslatorService.TranslateAsync should not be called
#if NETCOREAPP
            await filter.OnResultExecutionAsync(executingContext, () => Task.FromResult(new ResultExecutedContext(actionContext, new List <IFilterMetadata>(), executingContext.Result, foosController)));
#else
            await filter.OnActionExecutedAsync(contextMock, new CancellationToken());
#endif
        }
        /// <inheritdoc />
        public void Configure(MvcOptions options)
        {
            var valueTranslatorFilter = new ValueTranslatorFilter(
                _translatorService,
                GetClientName);

            options.Filters.Add(valueTranslatorFilter);
        }
        public async Task ArgumentsAreDecoratedAsync()
        {
            // Mock a translator
            var testServiceMock = new Mock <ITranslatorService>();

            testServiceMock
            .Setup(service => service.TranslateAsync(It.IsAny <IEnumerable <string> >(), It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(() => new Dictionary <string, string> {
                { $"(foo.id!~consumer!{Foo.ConsumerId1})", Foo.ProducerId1 }
            });

            // Prepare context
            var inFoo = new Foo
            {
                Id   = Foo.ConsumerId1,
                Name = "name"
            };
            var parameters = new Dictionary <string, object> {
                { "id", inFoo.Id }, { "item", inFoo }, { "token", default(CancellationToken) }
            };

#if NETCOREAPP
            var foosController             = new FoosController();
            var controllerActionDescriptor = new ControllerActionDescriptor();
            controllerActionDescriptor.MethodInfo =
                foosController.GetType().GetMethod(nameof(foosController.UpdateAndReturnAsync));
            var actionContext = new ActionContext
            {
                HttpContext      = new DefaultHttpContext(),
                RouteData        = new RouteData(),
                ActionDescriptor = controllerActionDescriptor
            };
            var executingContext = new ActionExecutingContext(actionContext, new List <IFilterMetadata>(),
                                                              parameters, foosController);
#else
            var contextMock = CreateExecutingContext(parameters, nameof(FoosController.UpdateAndReturnAsync));
#endif

            // Setup the filter
            var filter = new ValueTranslatorFilter(testServiceMock.Object, () => Foo.ConsumerName);

            // TODO: Test DecorateUserId

            // Run the filter
            Assert.IsFalse(inFoo.Id.StartsWith("(foo.id!"));
#if NETCOREAPP
            await filter.OnActionExecutionAsync(executingContext, () => Task.FromResult(new ActionExecutedContext(actionContext, new List <IFilterMetadata>(),
                                                                                                                  foosController)));
#else
            await filter.OnActionExecutingAsync(contextMock, new CancellationToken());
#endif
            Assert.IsTrue(inFoo.Id.StartsWith("(foo.id!"), inFoo.Id);
        }
        public async Task ResultIsTranslatedAsync()
        {
            var decoratedProducerId1 = Translator.Decorate(Foo.IdConceptName, Foo.ProducerName, Foo.ProducerId1);
            // Mock a translator
            var testServiceMock = new Mock <ITranslatorService>();

            testServiceMock
            .Setup(service => service.TranslateAsync(It.IsAny <IEnumerable <string> >(), It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(() => new Dictionary <string, string> {
                { decoratedProducerId1, Foo.ConsumerId1 }
            });

            // Prepare context
            var foosController = new FoosController();
            var foo            = new Foo
            {
                Id   = decoratedProducerId1,
                Name = "name"
            };

#if NETCOREAPP
            var controllerActionDescriptor = new ControllerActionDescriptor
            {
                MethodInfo = foosController.GetType().GetMethod(nameof(foosController.UpdateAndReturnAsync))
            };
            var actionContext = new ActionContext
            {
                HttpContext      = new DefaultHttpContext(),
                RouteData        = new RouteData(),
                ActionDescriptor = controllerActionDescriptor
            };
            var executingContext = new ResultExecutingContext(actionContext, new List <IFilterMetadata>(), new ObjectResult(foo), foosController);
#else
            var contextMock = CreateExecutedContextWithStatusCode(HttpStatusCode.OK, foo);
#endif

            // Setup the filter
            var filter = new ValueTranslatorFilter(testServiceMock.Object, () => Foo.ConsumerName);

            // Run the filter
#if NETCOREAPP
            await filter.OnResultExecutionAsync(executingContext, () => Task.FromResult(new ResultExecutedContext(actionContext, new List <IFilterMetadata>(), executingContext.Result, foosController)));
#else
            await filter.OnActionExecutedAsync(contextMock, new CancellationToken());
#endif

#if NETCOREAPP
            var objectResult = executingContext.Result as ObjectResult;
#else
            var objectResult = contextMock.Response.Content.AsString();
#endif

            // Verify that the result has been translated
            Assert.IsNotNull(objectResult);
#if NETCOREAPP
            var outFoo = objectResult.Value as Foo;
            if (outFoo == null && objectResult.Value is JObject jObject)
            {
                outFoo = jObject.ToObject <Foo>();
            }
#else
            var outFoo = JsonConvert.DeserializeObject <Foo>(objectResult);
#endif
            Assert.IsNotNull(outFoo);
            Assert.AreEqual(Foo.ConsumerId1, outFoo.Id);
        }