I have created a base controller with the following constructor:
public BaseController(ICustomer customer, ISiteSettings siteSettings, ILogger logger, ILocalizer localizer)
All my controllers are using the base as they all use all the dependecies. Now I am creating a new controller ErrorController which uses only uses siteSettings and not the other dependencies.
I was wondering if it would make sense to not to use the BaseController as an inheritance in ErrorController and just create a dependency for SiteSettings. On the other hand if the using BaseController is not too expensive, may be I should just keep the consistency with other controllers?
My feelings are since the dependencies are already registered with Unity, hitting the base controller would be a very inexpensive process. Just a thought. Please let me know if you think otherwise.
BaseController Code for your review:
public class BaseController : Controller
{
#region Private Members
/// <summary>
/// Factory to obtain customer object
/// </summary>
protected readonly ICustomer Customer;
/// <summary>
/// Site Settings
/// </summary>
protected readonly ISiteSettings SiteSettings;
/// <summary>
/// The Localization interface
/// </summary>
protected readonly ILocalizer Localizer;
/// <summary>
/// The Logger is used for exception handling
/// </summary>
protected readonly ILogger Logger;
#endregion
#region Ctor
/// <summary>
/// <para>Initializes a new instance of the <see cref="BaseController"/> class.</para>
/// <para>Parameters are injected via Unity.</para>
/// </summary>
/// <param name="customer">The customer.</param>
/// <param name="siteSettings">The site settings.</param>
/// <param name="logger">The logger.</param>
/// <param name="localizer">The localizer.</param>
public BaseController(ICustomer customer, ISiteSettings siteSettings, ILogger logger, ILocalizer localizer)
{
if (customer == null)
{
throw new ArgumentNullException("customer");
}
Customer = customer;
if (siteSettings == null)
{
throw new ArgumentNullException("siteSettings");
}
SiteSettings = siteSettings;
if (logger == null)
{
throw new ArgumentNullException("logger");
}
Logger = logger;
if (localizer == null)
{
throw new ArgumentNullException("localizer");
}
Localizer = localizer;
}
#endregion
}
Unless you have some hairy constructors on those dependencies (not the BaseController constructor itself), this should not be an issue. Your container should handle the grunt work and lifecycle of these. Would use the BaseController for consistency and ease of further expansion.
Related
I have the following classes in ProjectA:
public class ApplicationBuilder
{
private readonly IServiceCollection _services;
internal ApplicationBuilder() => _services = new ServiceCollection();
public ApplicationBuilder ConfigureServices(Action<IServiceCollection> services)
{
_services.AddSingleton<ILoggerFactory, LoggerFactory>();
_services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
_services
.AddLogging(builder => builder
.AddConsole()
.ClearProviders()
.SetMinimumLevel(LogLevel.Information));
_services.AddSingleton<Application>();
services.Invoke(_services);
return this;
}
public Application Build()
{
var provider = _services.BuildServiceProvider();
return provider.GetRequiredService<Application>();
}
}
[assembly: InternalsVisibleTo("Microsoft.Extensions.DependencyInjection")]
public class Application
{
private readonly ILogger<Application> _logger;
internal Application(ILogger<Application> logger) => _logger = logger;
public static ApplicationBuilder Create() => new();
public void Run()
{
_logger.LogInformation("Application started");
while (true)
{
}
}
}
And the following in ProjectB:
Application.Create()
.ConfigureServices(services =>
{
})
.Build()
.Run();
I get the following exception:
Unhandled exception. System.InvalidOperationException: A suitable constructor for type 'Application' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor.
I thought [assembly: InternalsVisibleTo("Microsoft.Extensions.DependencyInjection")] would allow DI to construct the type but apparently not. Is there some way to create my own constructor resolver that can use internal constructors?
Also if I skip this problem and make the constructor public (which I don't want to do), the logger doesn't log anything. Am I missing something with the setup for the logger?
Thanks
EDIT: Turns out AddLogging / ClearProviders() was the problem with the logger, I normally do this when using full .NET hosts to clear out the default framework messages but as they aren't here anyways it was clearing out the console logging provider.
Edit: I saw your issue was different, but still, consider this a rewrite for how it can be done.
First of all, remember Application is from System.Windows namespace. So I wouldn't use it. Further below, I'll rewrite the code with some other name.
internal Application(ILogger<Application> logger) => _logger = logger;
Why not removing the internal keyword as a whole alongside the code above? Let's try rewriting it in a way you don't need to do crazy internal witchcraft.
A better approach
Interfaces:
They can be set up in Project B or in a standalone Abstractions project shared by both Project A and Project B.
The following is an interface for configuring services (which returns the second interface when calling ConfigureServices:
/// <summary>
/// Configures the service application and returns the service built.
/// </summary>
/// <typeparam name="TApplication">Application Type</typeparam>
public interface IAppBuilderConfigureServices<TApplication>
where TApplication: class
{
/// <summary>
/// Creates a service injection container.
/// </summary>
/// <param name="services">Opts for configuring services.</param>
/// <returns>App Service Builder</returns>
IAppBuildService<TApplication> ConfigureServices(Action<IServiceCollection> services);
}
Interface for building the service:
/// <summary>
/// Builds the configuration and gets <see cref="TApplication"/> from container.
/// </summary>
/// <typeparam name="TApplication">Application Type</typeparam>
public interface IAppBuildService<TApplication>
where TApplication: class
{
/// <summary>
/// App Service builder that returns Singleton of <see cref="TApplication"/>
/// </summary>
/// <returns>Instance of <see cref="TApplication"/></returns>
TApplication Build();
}
Project A:
internal application builder:
/// <summary>
/// Internally builds the service application and returns the service built.
/// </summary>
/// <typeparam name="TApplication">Application Type</typeparam>
internal class AppBuilder<TApplication> : IAppBuilderConfigureServices<TApplication>, IAppBuildService<TApplication>
where TApplication: class
{
private readonly IServiceCollection _services = new ServiceCollection();
public IAppBuildService<TApplication> ConfigureServices(Action<IServiceCollection> services)
{
_services.AddLogging(s => s.ClearProviders().AddConsole().SetMinimumLevel(LogLevel.Debug));
_services.AddSingleton<TApplication>();
services.Invoke(_services);
return this;
}
public TApplication Build() => _services.BuildServiceProvider().GetRequiredService<TApplication>();
}
public static class AppBuilder
{
/// <summary>
/// Creates an instance of <see cref="IAppBuilderConfigureServices{TApplication}"/>
/// </summary>
/// <typeparam name="TApplication">Application Type</typeparam>
/// <returns>Application builder</returns>
public static IAppBuilderConfigureServices<TApplication> Create<TApplication>()
where TApplication : class =>
new AppBuilder<TApplication>();
}
Project B:
Just of an example of how it MyApp can be configured.
public static class ProjectB
{
public static MyApp Initialize()
{
return AppBuilder.Create<MyApp>()
.ConfigureServices(config =>
{
// ...
})
.Build();
}
}
Finally, your application code:
public class MyApp
{
private readonly ILogger<MyApp> _logger;
public MyApp(ILogger<MyApp> logger) => _logger = logger;
public void HelloWorld()
{
_logger.LogInformation("Hello, World!");
}
}
This is a draft but I think you get the idea. I'm using interfaces to make it more readable, sorry about the summaries, as I wanted to demonstrate what things were going to do.
Usage:
ProjectB.Initialize().HelloWorld();
In my project I do have many Database Contexts.
1. MyContext1
2. MyContext2
3. MyContext3
I am currently using database first approach (edmx based).
As part of edmx creation all these contexts are created. I would like to disable lazy loading for all these contexts.
I thought of writing a partial class for this. So for each Context there will be a partial class and which is responsible for disabling the lazy loading.
My current approach is something like below
[DbConfigurationType(typeof(InterceptorConfiguration))]
public partial class MyContext1 : DbContext
{
public static MyContext1 Create()
{
var applicationDbContext = new MyContext1();
applicationDbContext.Configuration.LazyLoadingEnabled = false;
return applicationDbContext;
}
}
Here i do have static method where i manually create instance of context and apply the configurations and returning it. Is there any other way to do this without creating a direct instance in the partial class?
Since there is already a default constructor in the edmx auto generated class I cannot write a constructor in the partial class which I have created.
I can disable this one in service layer, but since this one is an existing project I dont want to touch everywhere. So is there any better solution to do the same ?
Since this one is an existing application and it has many edmx files I cannot edit/change anything in the edmx including t4 template
Finally got a solution.
Since I am using Simple Injector Dependency Injection package in my solution.
I have created a provider for getting the instance at run time.
public sealed class DbContextProvider<T> : IDbContextProvider<T>
where T : DbContext
{
/// <summary>
/// The producer
/// </summary>
private readonly InstanceProducer producer;
/// <summary>
/// Initializes a new instance of the <see cref="DbContextProvider{T}"/> class.
/// </summary>
/// <param name="container">The container.</param>
/// <exception cref="InvalidOperationException">You forgot to register {typeof(T).Name}. Please call: " +
/// $"container.Register<{typeof(T).Name}>(Lifestyle.Scope);</exception>
public DbContextProvider(Container container)
{
this.producer = container.GetCurrentRegistrations()
.FirstOrDefault(r => r.ServiceType == typeof(T))
?? throw new InvalidOperationException(
$"You forgot to register {typeof(T).Name}. Please call: " +
$"container.Register<{typeof(T).Name}>(Lifestyle.Scope);");
}
/// <summary>
/// Gets the context.
/// </summary>
/// <value>
/// The context.
/// </value>
public T Context
{
get
{
DbContext dbContext = (T)this.producer.GetInstance();
//Dynamic proxies are used for change tracking and lazy loading
//if DbContext.Configuration.ProxyCreationEnabled is set to false, DbContext will not load child objects
//for some parent object unless Include method is called on parent object.
dbContext.Configuration.ProxyCreationEnabled = false;
return (T)dbContext;
}
}
}
Then the interface
public interface IDbContextProvider<out T> where T : DbContext
{
/// <summary>
/// Gets the context.
/// </summary>
/// <value>
/// The context.
/// </value>
T Context { get; }
}
I can call this one from service layer like
private readonly IDbContextProvider<MyDbContext> _baseContextProvider;
public MyService(IDbContextProvider<MyDbContext> baseContextProvider)
{
this._baseContextProvider = baseContextProvider;
}
We are using NSwag to generate swagger pages for our API. We have a fictitious asp.net core 2.2 controller and the generated swagger pages looks like this:
Is it possible to change the contents of the Example Value (highlighted in yellow)? We would like to display an actual sample value for the testParameter instead of just "string". Is there a data annotation we can use, or some other overriding mechanism available to override this behaviour?
The version of NSwag we are using is NSwag.AspNetCore 13.0.2.
The class that defines the model is:
public class TestQuery : IRequest<TestResponse>
{
[DefaultValue("test1")]
[JsonProperty("testParameter")]
public string TestParameter { get; set; }
}
We are using MediatR hence the IRequest.
Here's the controller class:
[Authorize, Route("api/route/test")]
[ApiController]
public class TestController : ControllerBase
{
private readonly IMediator _mediator;
/// <summary>
/// TestController constructor
/// </summary>
/// <param name="mediator">Dependency Injected mediator reference</param>
public TestController(IMediator mediator)
{
_mediator = mediator;
}
/// <summary>
/// Async method which retrieves a test response for a given testParameter string
/// </summary>
/// <remarks>
///
/// Sample testParameters: "test1", "test2", "test3"
///
/// Sample Request:
/// {
/// "testParameter": "test1"
/// }
///
/// </remarks>
/// <param name="GetTestResponseQuery">Get test response request model</param>
/// <returns>A test response</returns>
[HttpPost]
public async Task<ApiResponse<TestResponse>> GetTestResponse([FromBody]TestQuery testQuery)
{
if (!ModelState.IsValid)
{
throw new Exception($"State for model TestQuery is not valid for service {testQuery.TestParameter}");
}
else
{
var result = await _mediator.Send(testQuery).ConfigureAwait(false);
return new ApiResponse<TestResponse>(result);
}
}
}
Thank you kindly,
Yves Rochon
On your TestResponse class, add the example tag in xml comments of every property, that will be used in the swagger example. eg
public class TestResponse
{
/// <summary>
/// Property description
/// </summary>
/// <example>Sample value</example>
public string Property { get; set; }
}
i have an action on a controller which calls
var result = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
i'm trying to mock this result in a unit test like so
httpContextMock.AuthenticateAsync(Arg.Any<string>()).Returns(AuthenticateResult.Success(...
however that throws an InvalidOperationException
"No service for type 'Microsoft.AspNetCore.Authentication.IAuthenticationService' has been registered"
what is the correct way to mock this method?
That extension method
/// <summary>
/// Extension method for authenticate.
/// </summary>
/// <param name="context">The <see cref="HttpContext"/> context.</param>
/// <param name="scheme">The name of the authentication scheme.</param>
/// <returns>The <see cref="AuthenticateResult"/>.</returns>
public static Task<AuthenticateResult> AuthenticateAsync(this HttpContext context, string scheme) =>
context.RequestServices.GetRequiredService<IAuthenticationService>().AuthenticateAsync(context, scheme);
goes through the IServiceProvider RequestServices property.
/// <summary>
/// Gets or sets the <see cref="IServiceProvider"/> that provides access to the request's service container.
/// </summary>
public abstract IServiceProvider RequestServices { get; set; }
Mock the service provider to return a mocked IAuthenticationService and you should be able to fake your way through the test.
authServiceMock.AuthenticateAsync(Arg.Any<HttpContext>(), Arg.Any<string>())
.Returns(Task.FromResult(AuthenticateResult.Success()));
providerMock.GetService(typeof(IAuthenticationService))
.Returns(authServiceMock);
httpContextMock.RequestServices.Returns(providerMock);
//...
This question already has answers here:
How to avoid Dependency Injection constructor madness?
(10 answers)
Closed 7 years ago.
I have an MVC controller holding several abstractions (components). I want to reduce the amount of params to max 4 params.
To do this, I have several strategies that do not satisfy:
Bundling a set of params into a new class where the params will be properties: that just masks the complexity.
Resolve dependencies not by constructor injection but resolve by using factories: that also masks complexity.
Is there a better alternative approach ?
This the code of the controller:
public abstract class BaseVerificatieController : ExtendedController
{
private readonly IReferentieTabellenSysteemSettings referentieTabellenSysteemSettings;
private readonly IProcessManager processManager;
private readonly INavigationManager navigationManager;
private readonly ITransactionFacade transactionFacade;
private readonly IUISupportFacade uiSupportFacade;
private readonly ProcessIndex process;
protected BaseVerificatieController(
IBackHandler backHandler,
IReferentieTabellenSysteemSettings referentieTabellenSysteemSettings,
IProcessManager processManager,
INavigationManager navigationManager,
ITransactionFacade transactionFacade,
IUISupportFacade uiSupportFacade,
ProcessIndex process)
: base(backHandler)
{
this.referentieTabellenSysteemSettings = referentieTabellenSysteemSettings;
this.processManager = processManager;
this.navigationManager = navigationManager;
this.transactionFacade = transactionFacade;
this.uiSupportFacade = uiSupportFacade;
this.process = process;
}
[HttpGet]
public ActionResult Index()
{
var processStep = processManager.StartProcess(process);
return navigationManager.RedirectFromProcessStep(process, processStep);
}
[HttpGet]
public ActionResult Oe()
{
var model = new OeViewModel();
var transactionResult = transactionFacade.VerifyIdentityStart();
model.SetTransactionResult(transactionResult);
return View(model);
}
[HttpPost]
public ActionResult Oe(OeViewModel viewModel)
{
if (viewModel == null)
{
throw new ArgumentNullException("viewModel");
}
var transactionResult = transactionFacade.VerifyIdentityCheckRegisters(viewModel.SKN, null);
if (transactionResult.MoveToStep != Business.Models.ProcessStepIndex.NoStep)
{
return navigationManager.RedirectFromTransactionResult(process, transactionResult);
}
var model = new OeViewModel();
model.SetTransactionResult(transactionResult);
return View(model);
}
[HttpGet]
public ActionResult Oz()
{
var model = new OzViewModel(uiSupportFacade, referentieTabellenSysteemSettings);
var idStaatResult = transactionFacade.IdStaatStart();
model.SetIdStaatResult(idStaatResult);
return View("Oz_SKDB", model);
}
[HttpPost]
public ActionResult Oz(OzViewModel viewModel)
{
return RedirectToAction("Index", "Home");
}
As #Maarten says in comments, I would get rid of the injection of the process and inject it where its needed (not passing it around).
I would further move all the view model logic into "view model handlers" and use a mediator for executing the view model handlers.
The dependencies such as the transactionFacade and uiSupportFacade would then be injected in the view model handlers. This can be achieved with the following:
/// <summary>
/// Specifices that the target class is a view model. This is a marker interface and has no methods.
/// </summary>
public interface IViewModel
{
// Marker interface
}
/// <summary>
/// Handles the <typeparamref name="TViewModel"/>.
/// </summary>
/// <typeparam name="TViewModel">The view model which should be handled.</typeparam>
public interface IHandleViewModel<out TViewModel> where TViewModel : IViewModel
{
/// <summary>
/// Creates a <typeparamref name="TViewModel"/>.
/// </summary>
/// <returns>An instance of the <typeparamref name="TViewModel"/>.</returns>
TViewModel Handle();
}
/// <summary>
/// Handles the <typeparamref name="TViewModel"/> with the argument of <typeparamref name="TInput"/>
/// </summary>
/// <typeparam name="TInput">The argument for the view model</typeparam>
/// <typeparam name="TViewModel">The view model which should be handled.</typeparam>
public interface IHandleViewModel<out TViewModel, in TInput> where TViewModel : IViewModel
{
/// <summary>
/// Creates a <typeparamref name="TViewModel"/>.
/// </summary>
/// <returns>An instance of the <typeparamref name="TViewModel"/>.</returns>
TViewModel Handle(TInput input);
}
/// <summary>
/// Processes and creates view models.
/// </summary>
public interface IProcessViewModels
{
/// <summary>
/// Creates the <typeparamref name="TViewModel"/>.
/// </summary>
/// <returns>The view model</returns>
TViewModel Create<TViewModel>() where TViewModel : IViewModel;
/// <summary>
/// Create the <typeparamref name="TViewModel"/> with an argument of type <typeparamref name="TInput"/>
/// </summary>
/// <typeparam name="TViewModel">The view model which should be constructed</typeparam>
/// <typeparam name="TInput">The type of argument for the view model</typeparam>
/// <param name="input">The argument for the view model</param>
/// <returns>The view model</returns>
TViewModel Create<TViewModel, TInput>(TInput input) where TViewModel : IViewModel;
}
This means you can inject a single IProcessViewModels into your controller and execute the handlers. E.g. by filling the dependency container (here Simple Injector):
/// <summary>
/// Registers the view models in the Simple Injector container
/// </summary>
/// <param name="container">The Simple Injector container</param>
/// <param name="viewModelAssemblies">The assembly location of the view models</param>
public static void RegisterViewModels(this Container container, Assembly[] viewModelAssemblies)
{
if (container == null)
throw new ArgumentNullException("container");
if (viewModelAssemblies == null)
throw new ArgumentNullException("viewModelAssemblies");
container.RegisterSingle<IProcessViewModels, ViewModelProcessor>();
container.RegisterManyForOpenGeneric(typeof(IHandleViewModel<>), viewModelAssemblies);
container.RegisterManyForOpenGeneric(typeof(IHandleViewModel<,>), viewModelAssemblies);
}
The above code is from my "Nerve Framework" here: https://github.com/janhartmann/nerve-framework/tree/master/NerveFramework.Web.Mvc