The IServiceCollection
interface is used for building a dependency injection container. After it's fully built, it gets composed to an IServiceProvider
instance which you can use to resolve services. You can inject an IServiceProvider
into any class. The IApplicationBuilder
and HttpContext
classes can provide the service provider as well, via their ApplicationServices
or RequestServices
properties respectively.
IServiceProvider
defines a GetService(Type type)
method to resolve a service:
var service = (IFooService)serviceProvider.GetService(typeof(IFooService));
There are also several convenience extension methods available, such as serviceProvider.GetService<IFooService>()
(add a using
for Microsoft.Extensions.DependencyInjection
).
Resolving services inside the startup class
Injecting dependencies
The runtime's hosting service provider can inject certain services into the constructor of the Startup
class, such as IConfiguration
,
IWebHostEnvironment
(IHostingEnvironment
in pre-3.0 versions), ILoggerFactory
and IServiceProvider
. Note that the latter is an instance built by the hosting layer and contains only the essential services for starting up an application.
The ConfigureServices()
method does not allow injecting services, it only accepts an IServiceCollection
argument. This makes sense because ConfigureServices()
is where you register the services required by your application. However you can use services injected in the startup's constructor here, for example:
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
// Use Configuration here
}
Any services registered in ConfigureServices()
can then be injected into the Configure()
method; you can add an arbitrary number of services after the IApplicationBuilder
parameter:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IFooService>();
}
public void Configure(IApplicationBuilder app, IFooService fooService)
{
fooService.Bar();
}
Manually resolving dependencies
If you need to manually resolve services, you should preferably use the ApplicationServices
provided by IApplicationBuilder
in the Configure()
method:
public void Configure(IApplicationBuilder app)
{
var serviceProvider = app.ApplicationServices;
var hostingEnv = serviceProvider.GetService<IHostingEnvironment>();
}
It is possible to pass and directly use an IServiceProvider
in the constructor of your Startup
class, but as above this will contain a limited subset of services, and thus has limited utility:
public Startup(IServiceProvider serviceProvider)
{
var hostingEnv = serviceProvider.GetService<IWebHostEnvironment>();
}
If you must resolve services in the ConfigureServices()
method, a different approach is required. You can build an intermediate IServiceProvider
from the IServiceCollection
instance which contains the services which have been registered up to that point:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IFooService, FooService>();
// Build the intermediate service provider
var sp = services.BuildServiceProvider();
// This will succeed.
var fooService = sp.GetService<IFooService>();
// This will fail (return null), as IBarService hasn't been registered yet.
var barService = sp.GetService<IBarService>();
}
Please note:
Generally you should avoid resolving services inside the ConfigureServices()
method, as this is actually the place where you're configuring the application services. Sometimes you just need access to an IOptions<MyOptions>
instance. You can accomplish this by binding the values from the IConfiguration
instance to an instance of MyOptions
(which is essentially what the options framework does):
public void ConfigureServices(IServiceCollection services)
{
var myOptions = new MyOptions();
Configuration.GetSection("SomeSection").Bind(myOptions);
}
Or use an overload for AddSingleton/AddScoped/AddTransient
:
// Works for AddScoped and AddTransient as well
services.AddSingleton<IBarService>(sp =>
{
var fooService = sp.GetRequiredService<IFooService>();
return new BarService(fooService);
}
Manually resolving services (aka Service Locator) is generally considered an anti-pattern. While it has its use-cases (for frameworks and/or infrastructure layers), you should avoid it as much as possible.
Ok, since it's a date which was input as string, there are at least 2 ways you can do it.
Method 1
Databind the string as a Date
object instead of String
. As I do not now the exact date format of the original date, dd/MM/yyyy or MM/dd/yyyy, you'll have to figure it out yourself.
If you can do that, just add this to the "BoundField" element:
DataFormatString="{0:yyyy/MM/dd}"
or
DataFormatString="{0:yyyy/dd/MM}"
Method 2
Manipulate the text in ROwDataBound oevent. I've done a crude one here which can be polished up. You should probably manipulate them as Date
objects.
In the ASPX:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false"
onrowdatabound="GridView1_RowDataBound">
CodeBehind:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType != DataControlRowType.DataRow)
return;
// assuming the date is at cell index 1
string[] arr = e.Row.Cells[1].Text.ToString().Split('/');
e.Row.Cells[1].Text = string.Format("{0}/{1}/{2}", arr[2], arr[1], arr[0]);
}
Best Answer
This is more of a design issue.
The controller should not be creating child classes anyway. That is not a concern the controller should be dealing with and goes against SRP (Single Responsibility Principle).
If your preference is to separate the loggers, then there really isn't any other choice here than to have child (dependent) classes have their own loggers.
Have child classes inject their own logger
and then inject the child class into the controller.
That way, the child loggers will get resolved when the child classes are being resolved and injected into the controller.