.net core, n-layered app, should services layer have dependency on Microsoft.Extensions.Options.dll - configuration

Straightforward question is: are Microsoft.Extensions.Options.IOptions meant to be used only within the context of umbrella app (web app in this case) or in class libraries also?
Example:
In a n-layered, asp.net core app we have services layer that is dependant on some settings coming from appsettings.json file.
What we first started with is something along these lines in Startup.cs:
services.Configure<Services.Options.XOptions>(options =>
{
options.OptionProperty1 = Configuration["OptionXSection:OptionXProperty"];
});
And then in service constructor:
ServiceConstructor(IOptions<XOptions> xOptions){}
But that assumes that in our Service layer we have dependecy on Microsoft.Extensions.Options.
We're not sure if this is recomended way or is there some better practice?
It just feels a bit awkward our services class library should be aware of DI container implementation.

You can register POCO settings for injection too, but you lose some functionalities related to when the appsettings.json gets edited.
services.AddTransient<XOptions>(
provider => provider.GetRequiredService<IOptionsSnapshot<XOptions>>().Value);
Now when you inject XOptions in constructor, you will get the class. But when your edit your appsettings.json, the value won't be updated until the next time it's resolved which for scoped services would be on next request and singleton services never.
On other side injecting IOptionsSnapshot<T> .Value will always get you the current settings, even when appsettings.json is reloaded (assuming you registered it with .AddJsonFile("appsettings.json", reloadOnSave: true)).
The obvious reason to keep the functionality w/o pulling Microsoft.Extensions.Options package into your service/domain layer will be create your own interface and implementation.
// in your shared service/domain assembly
public interface ISettingsSnapshot<T> where T : class
{
T Value { get; }
}
and implement it on the application side (outside of your services/domain assemblies), i.e. MyProject.Web (where ASP.NET Core and the composition root is)
public class OptionsSnapshotWrapper<T> : ISettingsSnapshot<T>
{
private readonly IOptionsSnapshot<T> snapshot;
public OptionsSnapshotWrapper(IOptionsSnapshot<T> snapshot)
{
this.snapshot = snapshot ?? throw new ArgumentNullException(nameof(snapshot));
}
public T Value => snapshot.Value;
}
and register it as
services.AddSingleton(typeof(ISettingsSnapshot<>), typeof(OptionsSnapshotWrapper<T>));
Now you have removed your dependency on IOptions<T> and IOptionsSnapshot<T> from your services but retain all up advantages of it like updating options when appsettings.json is edited. When you change DI, just replace OptionsSnapshotWrapper<T> with your new implementation.

Related

Injecting DbContext into FileProvider in ASP.NET Core

I am trying to load some of the views from the database as described in here. So I want to use EF Core in the File provider.
RazorViewEngineOptions has a FileProviders property that you can add your file provider to. The problem is that you have to give it an instace of the file provider. So you'll need to instantiate all of the file providers' dependencies right there in Startup's ConfigureServices method.
Currently I inject an instance of IServiceProvider into the Configure method of Startup. Then I store the instance in a field (called _serviceProvider):
IServiceProvider _serviceProvider;
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider provider)
{
_serviceProvider = provider;
...
}
Then in ConfigureServices I use that field to instanciate the UIDbContext.
services.Configure<RazorViewEngineOptions>(options =>
{
var fileProvider = new DbFileProvider(_serviceProvider.GetService<UIDbContext>());
options.FileProviders.Add(fileProvider);
});
Is there any better way to be able to inject the UIDbContext into the DbFileProvider constructor Or any way to instantiate a UIDbContext inside DbFileProvider without IServiceProvider?
You don't want to use DbContext as a file provider source the way you did.
DbContext isn't thread-safe, so it won't work when you have one single DbContext instance for the whole provider, because multiple requests could call the DbContext and it's operation more than once at the same time, resulting in exception when trying to execute 2 queries in parallel.
You'd have to instantiate a connection (like in the linked article) or DbContext per IFileInfo/IDirectoryContents instance.
DbContextOptions<UIDbContext> should be registered as singleton, so you can resolve it onceinside Configure` w/o any issues and pass it to your provider.
Alternatively you can also call DbContextOptionsBuilder and build/construct a DbContextOptions<T>, but then you have to repeat the configuration for you did inside AddDbContext (i.e. .UseSqlServer()).
However it can be useful, as it allows you to set different settings (i.e. changing the way how includes, errors etc. are logged).

How to pass configuration parameters to SimpleInjector packaging?

So SimpleInjector now has a packaging nuget that you can use to isolate different aspects of root composition.
Say I have a configurable composition root in a library that is reused by multiple projects in an application. For example, in an Azure solution I might have a Web role and a Worker role which share a large set of the same dependencies for the most part, but with slightly different configuration options depending on the consumer. When I compose the root, I can pass in a plain old RootCompositionSettings object with properties that tell SimpleInjector how to register dependencies.
However, I am not sure how (or if) I can pass these settings to an IPackage instance. Is it possible to pass custom settings to a SimpleInjector package, and if so, how?
I see that the standard practices for registering packages is to invoke either
container.RegisterPackages(); // scans all loaded assemblies for IPackage
// or
container.RegisterPackages(IEnumerable<Assembly>) // specific assemblies only
...so how can we pass parameters into the packaging instance(s)? Is there some way to do it via the container?
The trick here is to pass the information on with the container to the package. You can do this by using the container's Items dictionary, that is much like ASP.NET's HttpContext.Items collection. This can be done as follows:
using SimpleInjector.Advanced;
container.SetItem(typeof(RootCompositionSettings), settings);
container.RegisterPackages();
Now inside your packages, you can do the following:
var settings =
(RootCompositionSettings)container.GetItem(typeof(RootCompositionSettings));
Please note that:
SetItem and GetItem are extension methods that are located in the SimpleInjector.Advanced namespace. Those methods allow you to access the (internal) Items dictionary.
You can pass in any key you like. Passing in typeof(RootCompositionSettings) is just convenient in this case, but not required.
If you need to call the settings in more places, it might be useful to create a more specific extension method that allows you to access the setting instance, but that's up to you.
Another option is to not use the IPackage interface and the SimpleInjector.Packaging library at all. In most cases it doesn't really add anything and you could simply define a public static method in the assembly that does the same as a package does. For instance:
public static class BusinessLayerBootstrapper
{
public static void Bootstrap(Container container, ScopedLifestyle scopedLifestyle,
RootCompositionSettings settings)
{
// Here the same logic as what you would write in your package.
}
}
Most applications are not that dynamic that you need to load assemblies dynamically and the startup project usually has a hard reference to all the other assemblies. In that case it is perfectly sane to simply call a static method.
And even if you have the requirement of dynamically loading assemblies and allowing them to register their stuff in the container, it's quite trivial to build your own IPackage abstraction instead:\
// Your own IPackage interface
public interface IPackage
{
void RegisterServices(Container container, RootCompositionSettings settings);
}
// Your own extension method
public static void RegisterPackages(this Container container,
RootCompositionSettings settings)
{
var packages =
from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetExportedTypes()
where typeof(IPackage).IsAssignableFrom(type)
where !type.IsAbstract
select (IPackage)Activator.CreateInstance(type);
packages.ToList().ForEach(p => p.RegisterServices(container, settings));
}
In fact, except for some extra validations and filtering out dynamic assemblies, the SimpleInjector.Packaging project is not much more than this.

Resolving a dependency while supplying values for downstream dependencies

I've been running into endless problems attempting to use Windsor with Web API and injecting HttpRequestMessage into downstream dependencies of a controller. Since I've tried all the matching answers on Stackoverflow, I'd like to ask the question in a different way:
In Castle Windsor, how can I resolve a component instance while supplying a value for a downstream dependency? That is, the supplied value is required by a component that is required by the component being resolved.
For context, I'm trying to inject HttpRequestMessage so that I can use it to resolve the request context (primarily to resolve an absolute URL).
Edit I'd also like to point out that I don't currently have a dependency on Web Host / System.Web and I'd rather not change that.
A proper approach is to
Create IMyDesiredRouteParameterProvider
Implement it. Get the current request inside it and get the url
Register it and inject it in the desired dependent class via constructor.
I made myself such an implementation and I can say that this way it works fine. You can make Web.Infrastructure assembly and put the implementation there. Or put both the interface and the implementation there if you are going to reference it from another web module.
using System;
using System.Web;
namespace RouteParameterProvider
{
interface IMyRouteParameterProvider
{
string GetRouteParameter();
}
public class ControllerActionMethodRouteParameterProvider : IMyRouteParameterProvider
{
public string GetRouteParameter()
{
string Parameter = HttpContext.Current.Request.RequestContext.RouteData.Values["controller"] as string;
if (string.IsNullOrEmpty(Parameter))
{
throw new InvalidOperationException();
}
return Parameter;
}
}
}
You can get every possible thing that the Request Context contains from :
HttpContext.Current.Request.RequestContext
And it will be better if you rethink your design decision :
I need HttpRequestMessage to be regstered prior to creating each
instance of SomethingController so that it will be available down at
the LinkGenerator layer.
Containers are to be initialized at runtime and then used to resolve.
I need HttpRequestMessage to be regstered prior to creating each
instance of SomethingController so that it will be available down at
the LinkGenerator layer.
It sounds like you want to register an item with the container at runtime, post-startup. In general, this is not a good practice--registration should be a discrete event that happens when the app is fired up, and the container's state should not be changed during runtime.
Dependency Injection is about resolving service components, not runtime state--state is generally passed via methods (method injection). In this case it sounds like your LinkGenerator component needs access to the ambient state of the request.
I'm not that familiar with HttpRequestMessage, but this answer seems to show that it is possible to retreive it from HttpContext.Current. You could make this a method on your LinkGenerator class, or wrap this call in a separate component that gets injected into LinkGenerator (HttpRequestMessageProvider?). The latter would be my preferred method, as it allows LinkGenerator to be more testable.
Given the lack of a clean way of doing this and Web API not providing information as to the hosted endpoint beyond per-request context objects, I ended up injecting the base url from configuration.
Is this library by Mark Seemann the answer? In the description he writes explicitly :
This approach enables the use of Dependency Injection (DI) because the
request can be injected into the services which require it.
Then gives an example :
// Inside an ApiController
var uri = this.Url.GetLink(a=> a.GetById(1337));
By which you can then pass the URL down the road in the service that you have injected in the controller.
UPDATE :
Mark Seemann wrote about the same exact problem here:
"Because HttpRequestMessage provides the context you may need to
compose dependency graphs, the best extensibility point is the
extensibility point which provides an HttpRequestMessage every time a
graph should be composed. This extensibility point is the
IHttpControllerActivator interface:..."
This way you can pass request context information to a component deep in the object graph by getting from the HttpRequestMessage and passing it to the DI container.
Just take a look at the interface of IHttpControllerActivator.
The WEB API framework gets the IHttpControllerActivator through DependencyResolver. You probably already replaced it by your CastleWindsorDependencyResolver. Now you have to implement and register your HttpControllerActivator and register it.
When the WEB API framework gets IHttpControllerActivator from DependencyResolver (your Castle Windsor DR) and calls IHttpControllerActivator.Create() it will pass you the HttpRequestMessage. You can get your info from there and pass it to the your CastleDR before you call Resolve(typeof(MyController)) which will resolve the whole object graph - that means you will have MyHttpContextInfo to inject in your XYZComponent deep in the resolution stack.
This way tou are passing the arguments in the last possible moment but it is still possible. In Castle Windsor I make such passing of arguments though CreationContext.AdditionalArguments["myArgument"];.

Managing RavenDb session in Windsor under NServiceBus

I'm using NServiceBus (3.2.2), RavenDB (1.2.2017-Unstable) and Windsor (3.0.0.4001) in an MVC 4 project.
I have a IHandleMessages class that handles 3 different messages, and that needs an IDocumentSession, and therefore defines a property such as:
public IDocumentSession DocumentSession { get; set; }
I've copied the RavenDbUnitOfWork implementation from NServiceBus' website
I've registered IDocumentStore, IDocumentSession and IManageUnitsOfWork in my Windsor container as follow:
container.Register(
Component
.For<IManageUnitsOfWork>()
.ImplementedBy<RavenUnitOfWork>()
.LifestyleTransient()
);
container.Register(
Component
.For<IDocumentStore>()
.UsingFactoryMethod(k => DocumentStoreHolder.DocumentStore)
.LifestyleSingleton(),
Component
.For<IDocumentSession>()
.UsingFactoryMethod(k => k.Resolve<IDocumentStore>().OpenSession())
.LifestyleTransient()
);
NServiceBus is configured to use my container:
Configure.With()
.CastleWindsorBuilder(container);
I'm encountering the problem that the UnitOfWork and the message handler receive different instances of the DocumentSession. This means that objects stored in the session in the message handler are not saved, since SaveChanges() is called on a different DocumentSession.
Removing the Transient lifestyle causes different kind of problems, that result in concurrency/conflicts when updating objects from RavenDb, since (probably) the message handler keeps getting the same instance of the DocumentSession, which holds a cached version of the updated object.
Update:
As suggested, I've tried changing the registration of the IDocumentSession in Windsor, to the Scope lifestyle, like this:
Component
.For<IDocumentSession>()
.UsingFactoryMethod(k => k.Resolve<IDocumentStore>().OpenSession())
.LifestyleScope()
This causes exceptions when the container tries to resolve the MVC Controller, saying that the scope was not found, and asking if I forgot to call BeginScope().
You need to have a scope of Per Message, not transient or singleton.
I am assuming that your mvc controller has a direct dependency on the IDocumentStore. You need to call container.BeginScope() before each request from the web. You can either do this as an action filter attribute http://msdn.microsoft.com/en-us/library/system.web.mvc.actionfilterattribute.aspx or as an AOP aspect on the controller itself http://cangencer.wordpress.com/2011/06/02/asp-net-mvc-3-aspect-oriented-programming-with-castle-interceptors/.
The issue is you need different lifestyles when using nservicebus in an asp.net mvc website when sharing the IDocumentSession in the same container.
For ASP.NET MVC you need a PerWebRequest lifestyle and for NServiceBus you need the Scoped lifestyle.
To do that i've used the hybrid lifestyle code in the castle contrib project:
https://github.com/castleprojectcontrib/Castle.Windsor.Lifestyles/tree/master/Castle.Windsor.Lifestyles
When calling from an ASP.NET context, it uses the WebRequestScopeAccessor. For NServicebus you need the LifetimeScopeAccessor. This is not in the contrib project, but is easy to add:
public class HybridPerWebRequestLifetimeScopeScopeAccessor : HybridPerWebRequestScopeAccessor
{
public HybridPerWebRequestLifetimeScopeScopeAccessor()
: base(new LifetimeScopeAccessor())
{
}
}
And in your registration code you need something like:
container.Register(Component.For<IDocumentSession>().LifestyleScoped<HybridPerWebRequestLifetimeScopeScopeAccessor>().UsingFactoryMethod(() => RavenDbManager.DocumentStore.OpenSession()));
And here's an implementation for Rhino Service Bus i used before switching to nservicebus:
https://gist.github.com/4655544

How to get instance of service in Windsor Castle

In a multilayer application (ASP MVC: UI project, DAL project) i registered in web.config the components.
Now i have this problem: Unit of Work pattern has do be implemented and i need to get the current instance of a particular service. The registration of the services happened in the UI project, but i need to get the current instance of this service in the DAL project. How do i get this reference?
In the UI project i already needed a way to get something resolved:
container = new WindsorContainer(
new XmlInterpreter(new ConfigResource("castle"))
);
personRepository= container.Resolve<IPersonRepository>();
Would it be OK to use the same technique in the DAL project? If yes, should i write the configuration in a separate file, so that it can be accessed by all the layers(projects)?
Sorry for this (i think) naive question but it's my first project using Castle and i think i don't understand the big picture of it!
Code snippet would help a lot.
Thanks in advance!
In a nutshell: one container instance per application, one container configuration that has all the components you need for the application. If you need a service in your DAL, inject the appropriate service interface in your DAL class via constructor (if the dependency is required) or setter (if the dependency is optional).
Try really hard to avoid using a static IoC gateway, it hides the true dependencies of a component and it hampers testability.
See these related questions:
Usage of IoC Containers; specifically Windsor
Is it correct to have many Castle Windsor containers per application if those containers belong to different tiers?
Have a look at this article. It shows you how to write a static class that performs dependency resolution using Castle Windsor. You should consider putting this class in a separate project that can be referenced from both your UI and DAL projects to allow code reuse. As the article explains, your class should provide a bootstrapper facility that initializes your IoC container. In your case, this would look like:
public static class IoC
{
private WindsorContainer _container;
public static void Initialize()
{
_container = new WindsorContainer(
new XmlInterpreter(new ConfigResource("castle"))
);
}
}
The bootstrapper would be invoked from the application startup event in your UI projects Global.asax file.
The other methods for obtaining instances of objects from the container would be as per the article.