Just upgraded from Microsoft.AspNet.OData 5.9.0 to 6.0.0.
The DefaultODataSerializerProvider class now has a constructor argument IServiceProvider.
I had a class NullSerializerProvider that implemented DefaultODataSerializerProvider.
This was adding a formatter to HttpConfiguration.
e.g.
public static void Register(HttpConfiguration config)
{
...
config.Formatters.InsertRange(0, ODataMediaTypeFormatters.Create(new
NullSerializerProvider(), new DefaultODataDeserializerProvider()));
}
My question:
NullSerializerProvider expects an instance of a class that implements IServiceProvider to be supplied. How do I supply this?
Here is the documentation on the OData dependency injection:
http://odata.github.io/odata.net/v7/#01-05-di-support
http://odata.github.io/WebApi/#13-04-DependencyInjection
I spent the whole day pouring over this information and trying to create my own IContainerBuilder around Ninject with no luck.
I finally gave up and let OData use its own DI container and keep that separate from my use of Ninject. I then realized I could create the DefaultContainerBuilder and register it like a custom container builder. I could then use the DefaultContainerBuilder to get the IServiceProvider.
var containerBuilder = new DefaultContainerBuilder();
config.UseCustomContainerBuilder(() => containerBuilder);
config.EnableDependencyInjection();
var serviceProvider = containerBuilder.BuildContainer();
var oDataSerializerProvider = new DefaultODataSerializerProvider(serviceProvider);
I also faced with this issue and after day of research find this solution:
using Microsoft.Extensions.DependencyInjection;
var serviceProvider = new ServiceCollection().BuildServiceProvider() as IServiceProvider;
Now you can create your own SerializerProvider or DeserializerProvider and use like:
var odataFormatters = ODataMediaTypeFormatters.Create(new DefaultODataSerializerProvider(serviceProvider), new JsonODataDeserializerProvider(serviceProvider));
config.Formatters.AddRange(odataFormatters);
Hope it save a lot of time and headache.
Related
I've been searching over the web how could I resolve instance using Prism DryIOC that uses parameter during runtime, but to luck yet.
For example, I have a class:
internal sealed class ItemInfoHelper : IItemInfoHelper
{
//ctor
public ItemInfoHelper(Item item) {...}
public string GetSomething() {...}
}
And in registering service I need to register it.
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.Register<IItemInfoHelper, ItemInfoHelper>();
}
If I do this, when I resolve it somewhere like:
var helperInstance = container.Resolve<IItemInfoHelper>();
it will be obviously resolved using empty Item (using default Item constructor). I have seen a lot of examples that register instances using some parameters that are known at compile time. But the case is that I would like to resolve instance being initialized dynamically using Item that would be a different one in different places (i.e. known at runtime only).
Is there a way to register/resolve it using such behavior if I use Prism + DryIoc?
Thanks in advance.
The simplest type-safe way to do so is to resolve the function of item:
var getHelperInstance = container.Resolve<Func<Item, IItemInfoHelper>>();
var helperInstance = getHelperInstance(myItem);
I have been struggling to get NopCommerce to pick up a registered interface.
This line here
this._connectionService = EngineContext.Current.Resolve<IConnectionService>();
is causing the error
Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it has already been disposed.
I have registered the interface in the DependencyRegistrar
builder.RegisterType<ConnectionService>().As<IConnectionService>().InstancePerLifetimeScope();
The issue is that it works when the constructor is called once, but when the constructor is called again the interface has been disposed, the constructor is as seen below -
public ClientHub()
{
this._connectionService = EngineContext.Current.Resolve<IConnectionService>();
}
By default NopCommerce has a lot of registered interface already so I have tried using what looks like a cached version
builder.RegisterType<CustomerActivityService>().As<ICustomerActivityService>()
.WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static"))
.InstancePerLifetimeScope();
But I still get an error when trying to use the ConnectionService like this.
I have tried using multiple different methods on the builder such as
InstancePerHttpRequest();
and
InstancePerDependency();
But it's all being disposed of when the constructor is called a second time, I did head over to the NopCommerce for any help but no luck.
Any guidance / help would be amazing !
public ClientHub()
{
this._connectionService = EngineContext.Current.Resolve<IConnectionService>();
}
well, that may create an issue, you're trying to resolve dependency, but that messed up.
It could be:
private readonly IConnectionService _connectionService
public ClientHub(IConnectionService connectionService)
{
this._connectionService = connectionService;
}
Or either it could be only:
private readonly IConnectionService _connectionService = EngineContext.Current.Resolve<IConnectionService>();
And not in constructor.
Im trying to use a HTML view to string rendering class i found online. Its called PDFRender atm cause this is what it will be used for. Ive been told that its set up using Dependency Injection and that it should work out of the box.
Im not sure how to instantiate it though. Since the dependencies are supposed to be injected through the constructor.
My class constructor look like this
public PdfRender(IRazorViewEngine viewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider)
{
_viewEngine = viewEngine;
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
And i set it up in the Startup classes ConfigureMetod() like this
// Set up Report PDF html renderer
services.AddScoped<PdfRender, PdfRender>();
Now m trying this in my code (after looking at the links example)
PdfRender pdfRender;
string iWantToBetml = pdfRender.ModelToHTML(inspection);
But i get an error (ofcourse) saying that i cant use an unassigned variable. I guess i dont understand how the DI is supposed to be used. Im assuming the idea is to give the default viewEngine, dataProvider and serviceProviders.
You just need to add a PdfRender parameter to the constructor of your controller:
public PdfRender(PdfRender pdfRender, IRazorViewEngine viewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider)
{
_pdfRender = pdfRender;
_viewEngine = viewEngine;
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
Then you can use in in an instance method on that controller
public SomeMethod(){
string iWantToBetml = _pdfRender.ModelToHTML(inspection);
}
Note that in your controller constructor you don't necessarily need to specify all these parameters, just specify the ones that the class needs and then those will be injected in from the DI container provided their types have been registered with the DI container at startup.
I have a simple AutoFac example working but now want to apply this to my web api project AND have the correct separation between the layers.
The issue I am seeing is the standard controller x "does not have a default constructor" but i am stumped so asking for advice..
I am calling RegisterApiControllers as well as RegisterControllers..
this is what I have in my DependencyInjectionContainer
public static class DependencyInjectionContainer
{
public static ContainerBuilder Builder;
public static IContainer Container;
public static void Init(Assembly mainAssembly)
{
Builder = new ContainerBuilder();
var config = GlobalConfiguration.Configuration;
RegisterTypes(mainAssembly);
Container = Builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(Container);
DependencyResolver.SetResolver(new AutofacDependencyResolver(Container));
}
private static void RegisterTypes(Assembly mainAssembly)
{
var roomBookingConnectionString = ConfigurationManager.ConnectionStrings["RoomBooking"].ConnectionString;
Builder.RegisterControllers(mainAssembly);
Builder.RegisterType<RoomRepository>().As<IRoomRepository>().WithParameter(new TypedParameter(typeof(string), roomBookingConnectionString));
Builder.RegisterType<RoomService>().As<IRoomService>();
Builder.RegisterApiControllers(mainAssembly);
Builder.RegisterFilterProvider();
}
}
I am calling this in my Global.asax.cs
DependencyInjectionContainer.Init(typeof(MvcApplication).Assembly);
One big assumption here is that this is correct...
Builder.RegisterApiControllers(mainAssembly);
edit---------------------------------------------------------------------
I have just tried moving all of the DI registrations etc in the 2 methods above back to the global.asax.cs and it works!?!?
I think its something to do with the 'RegisterApiControllers'. I am passing the calling assembly into the above init method using 'typeof(MvcApplication).Assembly'. Is there something wrong with this?
Thanks.
The RegisterApiControllers method is used by Autofac to locate the controllers.
When you do Builder.RegisterApiControllers(mainAssembly); are you sure the mainAssembly parameter is the assembly containing the controllers?
Anyway, if you have this kind of problems, you can do something like this (guessing you have a controller called RoomBookingController) :
builder.RegisterApiControllers(typeof(RoomBookingController).Assembly);
This way Autofac will locate the assembly containing your controller, no matter where it is.
I've got a ConfigurationReader class that I'm trying to wire up using StructureMap or AutoFac (I haven't settled on which container I'm using).
public class ConfigurationReader {
private string _filePath;
public ConfigurationReader(string filePath){
this._filePath = filePath;
}
public IList<Baz> ListStuff(){
//do something with _filePath;
}
}
There will be 1..n to instances of this class based on how the app is configured (web.config will contain a delimited list of files). I'm looking for an extension point in either IoC container that would allow me to leverage them to create instances of ConfigurationReader.
Well, in AutoFac you can just register each one in the Container (during Application_Start for example).
Whenever you need to read all configurations you can add a dependency to IEnumerable<ConfigurationReader> (or IConfigurationReader if you decide to extract an interface) and it will provide you with all of them.
Something like this:
var builder = new ContainerBuilder();
foreach(var file in ConfigurationManager.AppSettings[yourKey].Split(','))
{
var fileName = file;
builder.Register(c => new ConfigurationReader(fileName));
}
DependencyResolver.SetResolver(new AutofacDependencyResolver(builder.Build()));
If you extract interfaces, then you may want to register by adding the .AsImplementedInterfaces() or .As<IConfigurationReader>() at end as well.