I have an ASP.NET Web Api 2 REST service with several controllers. Each one of these controllers' constructor has got an ILogger argument which I have to inject with StructureMap. Is it possibile to instantiate an ILogger per request, in order to get client's specific informations - such as the IP address - and thus save the log file to a specific path?
This is the code I'm trying to run in the DefaultRegistry, but HttpContext is always null. Where am I wrong?
For<ILogger>()
.Use(() => new TextFileLogger(
HttpContext.Current.Request.UserHostAddress +
DirectorySeparatorChar + "log.txt"));
I'm not an expert on StructureMap but I understand the problem. The problem you have is that you use runtime data to build up your object graph. And injecting runtime data is an anti-pattern.
The simple solution here is not to use the HttpContext directly in your composition root but to create a provider which you can use to determine the path in the FileLogger. In that case both the FileLogger as this new provider can become singleton, which is far easier to work with and understand.
A provider could be as simple as (c#6 syntax):
public class HttpLogfileProvider : ILogFileProvider
{
public string PathToLogfile =>
Path.Combine(HttpContext.Current.Request.UserHostAddress, "log.txt");
}
Your FileLogger can use this provider as follows:
public class FileLogger : ILogger
{
private readonly ILogFileProvider logFileProvider;
public FileLogger(ILogFileProvider logFileProvider)
{
this.logFileProvider = logFileProvider;
}
public void Log(string message)
{
using (var writer = new StreamWriter(this.currentLogFile))
{
writer.WriteLine(message);
}
}
private string currentLogFile =>
this.logFileProvider.PathToLogFile;
}
I'm not an structuremap user but I think the registration should be:
For<ILogFileProvider>.Use<HttpLogfileProvider>.Singleton;
For<ILogger>.Use<FileLogger>.Singleton;
Related
I have a multi tenant system with background job. The tenancy details are stored in database and based on the tenant adding request in service bus, I want to resolve the dependencies based on tenant.
For this I would have to add dependencies to service collection before creating scope. When trying to inject IServiceCollection, it gives me error.
I am looking for the best way to inject dependencies from HostedService
public async Task MessageHandler(object sender, Message message)
{
// Inject dependencies
services.AddScoped<IMyService,Myservice>(); // No way to get services here
using (var scope = serviceProvider.CreateScope())
{
var ... = scope.ServiceProvider.GetService<...>();
//...
}
}
I had a similar need a while back. I created my own service bus handler.
You could try something like the below, where you inject a service (here as an example I'm using IMessageService) to the ServiceeBusHandler that itself has a dbcontext injected.
Then where ever you implement IServiceBusHandler you can specify for which tenant (and their queues) you want the connection built.
public class ServiceBusHandler : IServiceBusHandler
{
private readonly ServiceBusSender _serviceBusSender;
private readonly IMessageService _messageService;
public ServiceBusHandler(
ServiceBusSender serviceBusSender,
IMessageService messageService)
{
_serviceBusSender = serviceBusSender;
_messageService = messageService;
}
public async Task PublishMessageAsync<T>(T message)
{
var jsonString = JsonConvert.SerializeObject(message);
var serviceBusMessage = new ServiceBusMessage(jsonString);
await _serviceBusSender.SendMessageAsync(serviceBusMessage);
}
internal static IServiceBusHandler Create(ServiceBusSender sender)
{
return new ServiceBusHandler(sender);
}
}
public class ServiceBusHandlerFactory : IServiceBusHandlerFactory
{
private readonly IAzureClientFactory<ServiceBusClient> _serviceBusClientFactory;
public ServiceBusHandlerFactory(
IAzureClientFactory<ServiceBusClient> serviceBusClientFactory)
{
_serviceBusClientFactory = serviceBusClientFactory;
}
public IServiceBusHandler GetClient(string tenantId)
{
var tenantDetails = _messageService.GetTenantDetails(tenantId); // Call to your DB to get details about the Tenant
var client = GetServiceBusClient(tenantDetails.QueueName);
var sender = client.CreateSender(tenantDetails.QueueName);
return ServiceBusHandler.Create(sender);
}
protected virtual ServiceBusClient GetServiceBusClient(string queueName)
{
var client = _serviceBusClientFactory.CreateClient(queueName);
return client;
}
}
What you are trying to achieve is to change the set of registrations after the Container was built. MS.DI does not support this, and while historically, more mature DI Containers tended to support this behavior, most modern DI Containers stopped supporting this, because there are too many negative consequences in allowing this. Autofac, for instance, obsoleted its Update method in 2016 and described the issues with updating the Container in details. Ninject has gone through a similar process, although development stopped before the final release that removed the possibility to update the Container. The Simple Injector DI Container never supported updating, and its documentation has some clear texts that describe what the issue is.
You might find a DI Container that supports this, but I would urge you to abbondon this path, because of the negative consequences that it can (and probably will) cause, as the previous links described.
Instead, you will have to find a different way to get tenant-specific behavior, with one single set of registrations. The trick here, typically lies in creating a Proxy implementation of your IMyService that can forward the call to the correct tenant implementation.
This might look something like this:
public class ProxyMyService : IMyService
{
public IMyService Service { get; set; }
// IMyService methods
public void SomeMethod() => this.Service.SomeMethod();
}
This proxy class can be registered at startup, together with other IMyService implementations, as follows:
services.AddScoped<IMyService, ProxyMyService>();
services.AddTransient<MyServiceTenant1>();
services.AddTransient<DefaultMyServiceTenant>();
With this, your hosted service can become the following:
private ProxyMyService service;
public MyHostedService(IMyService service)
{
this.service = (ProxyMyService)service;
}
public async Task MessageHandler(object sender, Message message)
{
using (var scope = serviceProvider.CreateScope())
{
var p = scope.ServiceProvider;
var proxy = (ProxyMyService)p.GetRequiredService<IMyService>();
proxy.Service = IsTentant1
? p.GetRequiredService<MyServiceTenant1>()
: p.GetRequiredService<DefaultMyServiceTenant>();
var ... = p.GetRequiredService<...>();
//...
}
}
A more evolved solution would entail a Proxy implementation that allows to switch between tenant-specific implementations internally. That would likely mean moving part of the logic that's currently inside MessageHandler into the ProxyMyService.
Do notice that the solutions I suggested do not require an abstract factory. Abstract factories are typically not needed.
Is it possible to set up injection scopes for the default DI in Asp.Net Core? I mean For example:
services.AddSingleton<IUser, UserService>
services.AddSingleton<IUser, UserService>
And for the second configuration somehow specify that it should be injected into only HomeController. Unlike the first one should be injected to all others. Is it possible with default DI?
I answered a similar question here but using scoped instead of singleton:
How to register multiple implementations of the same interface in Asp.Net Core?
My gut feeling is that this might be what you're trying to achieve, or might be a better approach, and you might be mixing up the User with the UserService. When you have multiple implementations of the same interface DI will add these to a collection, so it's then possible to retrieve the version you want from the collection using typeof.
// In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped(IUserService, UserServiceA);
services.AddScoped(IUserService, UserServiceB);
services.AddScoped(IUserService, UserServiceC);
}
// Any class that uses the service(s)
public class Consumer
{
private readonly IEnumerable<IUserService> _myServices;
public Consumer(IEnumerable<IUserService> myServices)
{
_myServices = myServices;
}
public UserServiceA()
{
var userServiceA = _myServices.FirstOrDefault(t => t.GetType() == typeof(UserServiceA));
userServiceA.DoTheThing();
}
public UserServiceB()
{
var userServiceB = _myServices.FirstOrDefault(t => t.GetType() == typeof(UserServiceB));
userServiceB.DoTheThing();
}
public UseServiceC()
{
var userServiceC = _myServices.FirstOrDefault(t => t.GetType() == typeof(UserServiceC));
userServiceC.DoTheThing();
}
}
Assuming this registration, how should the dependency injection container possibly know which “singleton” (it’s not really a singleton when there are two of them) it should inject into the HomeController, or a different service, when they are all just depend on IUser?
The type the dependency gets registered as, in your case IUser, is the “key” which DI containers use to resolve the dependency. So two services that both depend on IUser will get their dependency resolved in the same way. With a singleton lifetime, this means that both services get the same instance.
Service registrations are also usually replacing. So if you have one registration AddSingleton<X, Y>() and then have another one AddSingleton<X, Z>(), then the latter will replace the former. So all services dependending on X will receive Z.
DI containers, including the default container that ships with ASP.NET Core, do usually support resolving all registrations by depending on IEnumerable<X> instead. But for this example this just means that a services would get both Y and Z.
The closest thing you are looking for are keyed or named dependencies. While these are supported in some DI containers, they are technically not part of dependency injection and as such often deliberately absent from many containers, including the ASP.NET Core one. See this answer for more details on that and for some idea to get around that.
To get back to your use case, you should really think about what you are actually doing there. If you have two “singleton” instances of UserService, you should really think about why that is the case: Why isn’t there just one? And if there is support for multiple, why not register it as transient?
More importantly, what would possibly differ between those two instances? After all, they are both instances of the same implementation, so there isn’t much that they can do differently.
If you can identify that, and also confirm that this is something that actually makes the instances different, then consider splitting this up in the type hierarchy as well. It’s difficult to explain this without having a use case here, but what you should try is to end up with two different interfaces that each do exactly what each dependent service type needs. So HomeController can depend on IUserA, and others can depend on IUserB (please choose better names than this).
I have the similar issue. There is my solution.
On the top level in controller I use custom attribute for the action, where I need specific service implementation (for reports for example):
public class HomeController : ControllerBase
{
private readonly IService _service;
public HomeController(IService service)
{
_service = service;
}
[HttpGet]
[ReportScope]
public IEnumerable<WeatherForecast> Get()
{
_service.DoSomeThing();
}
This attribute is processed by custom middleware:
public class ReportScopeLoggingMiddleware
{
private readonly RequestDelegate _next;
public ReportScopeLoggingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context, ReportScopeContext scopeContext)
{
var controllerActionDescriptor = context
.GetEndpoint()
.Metadata
.GetMetadata<ControllerActionDescriptor>();
bool analytical = controllerActionDescriptor.EndpointMetadata.Any(m => m is ReportScopeAttribute);
if (analytical) scopeContext.SetActive();
await _next(context);
}
}
In this middleware I use ReportScopeContext.
public class ReportScopeContext
{
public bool Active { get; private set; } = false;
public void SetActive()
{
Active = true;
}
}
This ReportScopeContext has scoped lifetime in DI and I use it to select an implementation of IService:
services.AddScoped<ReportScopeContext>();
services.AddTransient<Service2>();
services.AddTransient<Service1>();
services.AddTransient<IService>(sp =>
sp.GetRequiredService<ReportScopeContext>().Active
? sp.GetRequiredService<Service1>()
: sp.GetRequiredService<Service2>());
I have a web api project where controllers depend on some storage layer. E.g.
each controller has similar code:
public class ResourceController : ApiController
{
private readonly IResourceStorage _resourceStorage;
private readonly IOtherStorage _otherStorage;
public ResourceController(IResourceStorage resourceStorage, IOtherStorage otherStorage)
{
_resourceStorage = resourceStorage;
_otherStorage = otherStorage;
}
// Web API Actions
}
A common code for storage looks like this:
public class ResourceStorage : DBProvider, IResourceStorage
{
public ResourceStorage(string connectionString) : base(connectionString)
{
}
// storage methods
}
Based on some specific condition of the Web Api request, I need to be able to inject different connectionStrings to Storages of controller. Pseudo-code could look like that:
public class WindsorControllerActivator : IHttpControllerActivator
{
public IHttpController Create(
HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
string connectionString = ChooseDbConnectionStringBasedOnRequestContext(request);
var controller =
(IHttpController)_container.Resolve(connectionString, controllerType, new {databaseType = connectionString});
request.RegisterForDispose(
new Release(
() => _container.Release(controller)));
return controller;
}
}
I do not know how to pass the parameter to the storage in the less destructive way:)
What have I tried? Alternatives:
Pass parameterers as Castle Windsor Additional Arguments and treat it in next layer using DynamicParameters. The arguments get the controller layer but I could not find a way to get them to the storage - it has its own CreationContext, and I cannot find a way to pass it on from controller to storage.
Have N(equal to number of connection strings) containers and choose one of those inside ControllerActivator. Seems a huge and ugly solution, totally non-flexible but it works.
Create N sets of Controllers each with their own name and inside of storage DynamicParameters check Handler's component name and choose the connection string. From the ControllerActivator pass in the key to the correct set of Controllers. Also ugly - too many registrations of controllers and a lot of plumbing code.
You could use a factory pattern:
public interface IResourceStorageFactory
{
IResourceStorage Create(int numberOfResources);
}
public class ResourceStorageFactory : IResourceStorageFactory
{
public IResourceStorage Create(HttpRequestMessage request)
{
var connectionString = ChooseDbConnectionStringBasedOnRequestContext(request);
return new ResourceStorage(connectionString);
}
}
and then simply
private readonly IResourceStorage _resourceStorage;
private readonly IOtherStorage _otherStorage;
public ResourceController(IResourceStorageFactory resourceStorageFactory, IOtherStorage otherStorage)
{
_resourceStorage = resourceStorageFactory.Create(Request);
_otherStorage = otherStorage;
}
The solution I found is introducing a connection string provider:
public interface IConnectionStringProvider
{
string ConnectionString { get; }
}
When register this provider as per web request with a factory method:
kernel.Register(
Component.For(typeof (IConnectionStringProvider))
.ImplementedBy(typeof (ConnectionStringProvider))
.UsingFactoryMethod(
(k, context) =>
new ConnectionStringProvider(context.AdditionalArguments["connectionString"].ToString()))
.LifestylePerWebRequest());
And inside the controller activator first resolve the connection string provider with the right parameters and then the controller:
// The lifecycle of connection string provider if per web request.
// We resolve it first time with the correct parameters,
// so it is injected with the correct connection string throught the lifecycle of the request.
_container.Resolve<IConnectionStringProvider>(new {connectionString});
var controller =
(IHttpController) _container.Resolve(controllerType);
It still not perfect and looks kind of hackish but it allows to keep dependencies on the interfaces of the inferior layer and requires less changes of the codebase from the solutions I've found
I am building an MVC application that connect to diferent databases depending on the user that has log in.
For this i have 3 projects DAL using entity framework(DataBaseFirst) where i have extended the dbcontext so that i can pass the connectionstring like this:
public partial class ARACultivoEntities
{
public ARACultivoEntities(string nameOfConnectionString)
: base(nameOfConnectionString)
{
}
}
Note: I have the connections strings defined in the web.config of the mvc project.
There is also another project, Services where i have a genericService from where other service can inherit this like this:
public class GenericService<T> : IGenericService<T>
where T : class
{
protected ARACultivoEntities Db;
protected DbSet<T> Table;
public GenericService(string nameConnectionString)
{
if (string.IsNullOrEmpty(nameConnectionString))
{
throw new ArgumentNullException("nameConnectionString");
}
Db = new ARACultivoEntities(nameConnectionString);
Table = Db.Set<T>();
}
Now i save the name of the connection string in the user claims when he logs in and in the controllers i have something like this:
public class DeduccionController : Controller
{
private IGenericService<Deducciones> service;
public DeduccionController()
{
service = ServiceFactoryGeneric<Deducciones>.InitGenericService(GetClaimsUser.Cadena);
//GetClaimsUser.Cadena has the name of the connectionString
//ServiceFactoryGeneric<Deducciones>.InitGenericService do this:
// return new GenericService<T>(connectionString);
}
now i want to instead of having my own factories i want to use an Ioc Container and i have chosen unity for this, i am new to this, i've read some articles and i think i undsertand the basics but i dont know how to pass the connection string after the user has log in because my RegisterTypes hapen at the application start
public static void RegisterTypes(IUnityContainer container)
{
// this happen at application start
// string nameOfConnectionString = *user is still not loged in*
container.RegisterType<IGenericService<T>, GenericService<T>>(
new InjectionConstructor(nameOfConnectionString));
}
i been thinkin to try to tweet the code to register my types after the user has loged in but i dont think this a good idea..
i also have been thinking about adding a public method to my IGenericService so that i can set my connectionString after the service is constructed and implemented something like this:
public void SetConnectionString(string nameOfConnectionString)
{
Db.Database.Connection.ConnectionString = nameOfConnectionString;
//not sure if this actually works
}
then my controller will be something like this:
public class DeduccionController : Controller
{
private IGenericService<Deducciones> _service;
public DeduccionController(IGenericService<Deducciones> service)
{
_service = service;
_service.SetConnectionString(GetUserClaims.Cadena);
}
and let my RegisterTypes just with the:
container.RegisterType<IGenericService<T>, GenericService<T>>()
but since i new to this world of IoCs i am not sure if this is the best way
What would be the correct way to do this using Unity?
Thank you for reading.
I am sorry for my english not my first languague.
I recently had to do something similar by swapping connection strings based on a route parameter specifying a geo-location.
I would recommend building your own Unity LifetimeManager that acts in a instance per session scope. Register an object that acts as a configuration container for the connection string property.
[See Unity Lifetime Manager: http://msdn.microsoft.com/en-us/library/microsoft.practices.unity.lifetimemanager(v=pandp.30).aspx]
Then you could inject that singleton instance of this configuration object into your controller and set the connection string property once a user has logged in. You could then inject that same singleton instance into a DbContext factory that instantiates your DbContext using the connection string specified in your configuration object.
Like I said, it may not be the most elegant solution, but I liked it better than having to pass a connection string through the many tiers of your application stack. Hope this helps.
I'm using Drum which provides a generic class `UriMaker:
public class UriMaker<TController>
{
// I need use this one
public UriMaker(UriMakerContext context, HttpRequestMessage request) { }
public UriMaker(Func<MethodInfo, RouteEntry> mapper, UrlHelper urlHelper) { }
}
Used like this:
public class UserController : ApiController
{
public UserController(UriMaker<UserController> urlMaker) {}
}
I've used to register it with Unity:
container.RegisterType(typeof(UriMaker<>),
new InjectionConstructor(typeof(UriMakerContext), typeof(HttpRequestMessage)));
but now migrating to Simple Injector. I already have this:
UriMakerContext uriMaker = config.MapHttpAttributeRoutesAndUseUriMaker();
container.RegisterSingle(uriMakerContext);
So how now register UriMaker<> itself?
Although it is possible to configure Simple Injector to allow injecting an UriMaker<TController> directly into your controllers, I strongly advice against this for multiple reasons.
First of all, you should strive to minimize the dependencies your application takes on external libraries. This can easily be done by defining an application specific abstraction (conforming the ISP).
Second, injecting the UriMaker directly makes your extremely hard to test, since the UriMaker is pulled into your test code, while it assumes an active HTTP request and assumes the Web API route system to be configured correctly. These are all things you don't want your test code to be dependent upon.
Last, it makes verifying the object graph harder, since the UriMaker depends on an HttpRequestMessage, which is a runtime value. In general, runtime values should not be injected into the constructors of your services. You should build up your object graph with components (the stuff that contains the application's behavior) and you send runtime data through the object graph after construction.
So instead, I suggest the following abstraction:
public interface IUrlProvider
{
Uri UriFor<TController>(Expression<Action<TController>> action);
}
Now your controllers can depend on this IUrlProvider instead of depending on an external library:
public class UserController : ApiController
{
private readonly IUrlProvider urlProvider;
public UserController(IUrlProvider urlProvider)
{
this.urlProvider = urlProvider;
}
public string Get()
{
this.urlProvider.UriFor<HomeController>(c => c.SomeFancyAction());
}
}
Under the covers you of course still need to call Drum, and for this you need to define a proxy implementation for IUrlProvider:
public class DrumUrlProvider : IUrlProvider
{
private readonly UriMakerContext context;
private readonly Func<HttpRequestMessage> messageProvider;
public DrumUrlProvider(UriMakerContext context,
Func<HttpRequestMessage> messageProvider)
{
this.context = context;
this.messageProvider= messageProvider;
}
public Uri UriFor<TController>(Expression<Action<TController>> action)
{
HttpRequestMessage message = this.messageProvider.Invoke();
var maker = new UriMaker<TController>(this.context, message);
return maker.UriFor(action);
}
}
This implementation can be registered as singleton in the following way:
container.EnableHttpRequestMessageTracking(config);
UriMakerContext uriMakerContext =
config.MapHttpAttributeRoutesAndUseUriMaker();
IUrlProvider drumProvider = new DrumUrlProvider(uriMakerContext,
() => container.GetCurrentHttpRequestMessage());
container.RegisterSingle<IUrlProvider>(drumProvider);
This example uses the Simple Injector Web API integration package to allow retrieving the current request's HttpRequestMessage using the EnableHttpRequestMessageTracking and GetCurrentHttpRequestMessage extension methods as explained here.