Injecting DbContext into FileProvider in ASP.NET Core - razor

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).

Related

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

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.

I am not able to store entity using em.merge in broadleaf

I am new to broadleaf application. I am able to run application using tomcat + mysql integration well. Now I want to move on with the development to customize the site project as per my requirement.
I am stuck on the point of persistant in broadleaf site module. I have tried using em.merge that returns my entity but do not save it in database and also tried #Transactional(value="blTransactionManager") but It still problem persists. I have tried bellow code in applicationContext-servlet.xml
<aop:config>
<aop:pointcut id="blMyStoreDao" expression="execution(* com.mycompany.dao.StoreDaoImpl.save*(..))"/>
<aop:advisor advice-ref="blTxAdvice" pointcut-ref="blMyStoreDao"/>
</aop:config>
Here is my controller code
newStore.setCustomer(customer);
newStore.setProductList(new ArrayList<ProductImpl>());
Store getStore=store.save(em, newStore);
System.out.println(getStore.getCustomer().getUsername());
System.out.println("customer fetched: "+customer.getEmailAddress());
Here is my daoimpl code
#Repository("blMyStoreDao")
#Transactional(value="blTransactionManager")
public class StoreDaoImpl implements StoreDao {
#PersistenceContext(unitName="blPU")
protected EntityManager em;
#Transactional(value="blTransactionManager")
public Store save(EntityManager em, Store store) {
System.out.println(em);
System.out.println(store.getCustomer().getUsername());
Store s= em.merge(store);
return s;
}
}
But it also didn't resolve my issue.
Code runs perfectly as it should be, but it doesn't save my entity in database.
Anybody Help. Thanks In advance
There isn't any reason to use <aop:config> especially in applicationContext-servlet.xml (if anywhere it should be in the root application context)
You should use #Transactional(TransactionUtils.DEFAULT_TRANSACTION_MANAGER to annotate your method
It is likely that your class was not being scanned by Spring. In Broadleaf, there is a default component scan set up in applicationContext.xml to scan com.mycompany.core.
I would recommend verifying that your dao is actually scanned by Spring and is initialized as a Spring bean. The fact that the entity manager did not get injected indicates that it did not get loaded by Spring correctly. One way to verify this would be to add an #PostConstruct method and print something or set a breakpoint to verify that it gets hit.

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.

CloudFoundry MySQL Java configuration

I have a Spring MVC app that is running fine on local tomcat etc. Its a Spring 3.1 MVC/Hibernate app.
I am using (where possible) pure Java #Configuration for the app - and I am now trying to deploy the app to CloudFoundry (via STS), but I am struggling to get the MySql db configured (from memory, with xml config you dont need to do anything and Spring/CloudFoundry auto-injects the required user/password etc, but its been a while since I deployed anything to CF).
I have tried both of the following configurations:
#Bean
public BasicDataSource dataSource() throws PropertyVetoException {
//CloudFoundry config
final CloudEnvironment cloudEnvironment = new CloudEnvironment();
final List<MysqlServiceInfo> mysqlServices = cloudEnvironment.getServiceInfos(MysqlServiceInfo.class);
final MysqlServiceInfo serviceInfo = mysqlServices.get(0);
BasicDataSource bean = new BasicDataSource();
bean.setDriverClassName("com.mysql.jdbc.Driver");
bean.setUrl(serviceInfo.getUrl());
bean.setUsername(serviceInfo.getUserName());
bean.setPassword(serviceInfo.getPassword());
return bean;
}
The above failed on out of bounds on the .get(0) line of the mysqlServices. This was based on the answer suggested here.
I also tried leaving the datasource as what it runs on as local to see if the properties just get injected, but no luck there either. (the below was tried with the values as per the Spring sample code here, and also using property placeholders from my db.connection props file)
#Bean
public BasicDataSource dataSource() throws PropertyVetoException {
BasicDataSource bean = new BasicDataSource();
bean.setDriverClassName("com.mysql.jdbc.Driver");
bean.setUrl("");
bean.setUsername("spring");
bean.setPassword("spring");
return bean;
}
Edit
I have also used the getServiceInfo(String, Class) method passing in the name of the MySql service that I have created and bound to the application, but that just NPEs similar to the getServiceInfos(..) approach
Ok, this was just a stupid mistake - when I deployed the app via STS I had selected Java Web app rather than the "Spring" type. Not sure why that would make the CloudEnvironment properties not be available (I was under the impression that approach was the common method to inject the details in non-Spring apps) - but re-deploying it to the server as a Spring app resolved the probs!

entity and repository pattern with ninject, Dispose Issue

I have build my site using entity and repository pattern with ninject injection. My problem is my connections don't seem to get disposed. I have around 30 repositories (one for each table) and I get sql expiration timout preety quick. I can't use the regular using statement because the code recognize only the interface before the injection.
(in each controler I have my repositories interface instances which get injected via ninject).
I have searched the net but couldn't find a solution that was accurate for me.
can anyone please help me?
code example:
this is in the ninject controller under addBindings():
ninjectKernel.Bind<IMovieRepository>().To<MovieRepository>().InRequestScope();
and one of my repositories:
public class MovieRepository : IMovieRepository, IDisposable
{
private Entities dataContext = new Entities();
public System.Data.Entity.DbContext DbContext
{
get { return dataContext ?? (dataContext = new Entities()); }
}
public void Dispose() { dataContext.Dispose(); }
}
and in the Global.asax file:
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory() as IControllerFactory);
I would guess that your repositories (and therefore presumably your DbContexts) are being bound in transient scope, which I believe means a new one will be created every time Ninject needs to inject one somewhere. I'm not certain but I'm guessing then that these are all staying around for the lifetime of your application and maybe not being disposed.
Try binding your repositories in request scope, so that they are created and disposed per web request.
e.g.
Bind<IFooRepository>().To<ConcreteFooRepository>().InRequestScope();
From the Ninject wiki:
There are four built-in scopes available in Ninject:
Transient - A new instance of the type will be created each time one is requested. (This is the default scope). Binding method is .InTransientScope()
Singleton - Only a single instance of the type will be created, and the same instance will be returned for each subsequent request. Binding method is .InSingletonScope()
Thread - One instance of the type will be created per thread. Binding method is .InThreadScope()
Request - One instance of the type will be created per web request, and will be destroyed when the request ends. Binding method is .InRequestScope()
This kind of problem usually occur if long living objects depend on shorter living objects. E.g. A singleton service uses a repository in request scope.