Getting exception "Value cannot be null" while resolving an object by Unity - c#

I've met an exception while resolving the object using Unity container:
Message "Value cannot be null.\r\nParameter name: container"
Source "Microsoft.Practices.Unity" string
I have a Prism application where I have ServiceModule. ServiceModule just has interface and its implementation:
public interface ICommonService
{
string SomeStorage { get; set; }
}
public class CommonService : ICommonService
{
string fooStorage=DateTime.Now.ToString();
public string FooStorage
{
get
{
return fooStorage;
}
set
{
fooStorage = value;
OnPropertyChanged("FooStorage");
}
}
}
I create a single instance of ICommonService in ViewModelA of ModuleA. It works okay:
unityContainer = new UnityContainer();
unityContainer.RegisterType<ICommonService, CommonService>(new ContainerControlledLifetimeManager());
IMyService someFoo = unityContainer.Resolve<ICommonService>();
someFoo.FooStorage = "AAAOOOBBB";
Then I want to read this data in viewModelB of ModuleB. And this code throws an exception:
ICommonService someFoo = unityContainer.Resolve<ICommonService>();
string str=someFoo.FooStorage;
The exception says:
Message "Value cannot be null.\r\nParameter name: container"
Source "Microsoft.Practices.Unity" string
What am I doing wrong? Any help will be greatly appreciated!

Based on the error message that you get, most probably the value of unityContainer is null. Make sure that you initialize it correctly.

Related

.NET CORE dependency injection passing parameter to constructor

I'm trying to register a class as defined below with DI:
public class MyService
{
private string _serviceAddress;
public MyService(string serviceAddress)
{
_serviceAddress = serviceAddress;
}
public void DoWork()
{
// do work
}
}
In the program.cs, register it with DI:
builder.Services.AddSingleton<MyService>(new MyService(serviceAddress));
And in the razor component, inject it:
[Inject]
MyService myService { get; set; }
public WeatherForecast()
{
myService.DoWork(); // <- error points to this line
}
And when accessing the page, got NullReferenceException, pointing to the DoWork line above:
Unhandled exception rendering component: Exception has been thrown by the target of an invocation.
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.NullReferenceException: Object reference not set to an instance of an object.
Any advice is appreciated.
You can't use [Inject] services in the component constructors. That property/service hasn't been initialized yet. You should be doing that work in component initialization:
[Inject]
MyService myService { get; set; }
public WeatherForecast()
{
// myService is null here. It hasn't been initialized.
// How could it be? We are currently constructing this object!
}
protected override Task OnInitializedAsync()
{
// myService has been initialized by this point.
// You can safely use it now.
myService.DoWork();
return base.OnInitializedAsync();
}
To back up Andy's answer:
The Renderer manages the lifecycle of components. Services are injected into the component instance by the Renderer after it has instantiated an instance of the component. It will throw an exception if it doesn't find a matching service.
The normal way to declare an injected property in a nullable environment is:
[Inject] MyService myService { get; set; } = default!;
If you use #inject in a Razor file it turns off the nullable warnings for the specific declaration.

How can I configure Unity-Container to register a class by providing that class a string value?

I have an ASP.NET MVC 5 based app. I am trying to use Unity.Mvc container to help me with dependency injection.
I have the following DbContext class
public class MainContext : DbContext
{
public DbSet<User> Users { get; set; }
// .....
public MainContext(string connectionName)
: base(connectionName)
{
Database.SetInitializer<MainContext>(null);
}
}
The production value I want to use when constructing the MainContext class is DefaultConnection. I want to register the MainContext class into the container and tell Unity to provide the DefaultConnection string to the constructor when using resolving it.
I tried the following
container.RegisterType<MainContext>("DefaultConnection", new PerRequestLifetimeManager(), new InjectionConstructor(new ResolvedParameter<string>("DefaultConnection")));
Also tried this
container.RegisterType<MainContext>("DefaultConnection", new PerRequestLifetimeManager(), new InjectionConstructor("DefaultConnection"));
But I keep getting the following error
Resolution of the dependency failed, type = 'System.Web.Mvc.IController', name = 'MyProject.Controllers.HomeController'.
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The type String cannot be constructed. You must configure the container to supply this value.
-----------------------------------------------
At the time of the exception, the container was:
Resolving MyProject.Controllers.HomeController, MyProject.Controllers.HomeController (mapped from System.Web.Mvc.IController, MyProject.Controllers.HomeController)
Resolving parameter 'unitOfWork' of constructor MyProject.Controllers.HomeController(MyProject.Repositories.Contracts.IUnitOfWork unitOfWork)
Resolving MyProject.Repositories.UnitOfWork,(none) (mapped from MyProject.Repositories.Contracts.UnitsOfWork.IUnitOfWork, (none))
Resolving parameter 'context' of constructor MyProject.Repositories.UnitOfWork(MyProject.Contexts.MainContext context)
Resolving MyProject.Contexts.MainContext,(none)
Resolving parameter 'connectionName' of constructor MyProject.Contexts.MainContext(System.String connectionName)
Resolving System.String,(none)
A workaround would be to change my MainContext class to this
public class MainContext : DbContext
{
public DbSet<User> Users { get; set; }
// .....
public MainContext(string connectionName)
: base(connectionName)
{
Database.SetInitializer<MainContext>(null);
}
public MainContext(string connectionName)
: this("DefaultConnection")
{
}
}
Then register my class like so
container.RegisterType<MainContext>(new PerRequestLifetimeManager(), new InjectionConstructor());
But, I don't want to couple my implementation with a specific connection-name. I want the IoC to provide the connection name to MainContext. In another words, I want to be able to swap out connection name without changing the MainContext class.
How can I correctly tell Unity-Container to register the MainContext class and use a the DefaultConnection when it is constructed?
This does not directly answer my question but gave me a flexible workaround.
I created the following interface
public interface IDatabaseConnection
{
string NameOrConnectionString { get; }
}
Then I created the following implementations of this class
public class DefaultDatabaseConnection: IDatabaseConnection
{
public string Name { get; private set; }
public DefaultDatabaseConnection()
{
NameOrConnectionString = "DefaultConnection";
}
public DefaultDatabaseConnection(string connectionName)
{
NameOrConnectionString = connectionName;
}
}
Then I changed my MainContext class to this
public class MainContext : DbContext
{
public DbSet<User> Users { get; set; }
// .....
public MainContext(IDatabaseConnection connection)
: base(connection.NameOrConnectionString)
{
Database.SetInitializer<MainContext>(null);
}
}
Finally, I registered my classes like so
container.RegisterType<IDatabaseConnection, DefaultDatabaseConnection>("DefaultDatabaseConnection", new InjectionConstructor());
container.RegisterType<MainCompanyContext>(new PerRequestLifetimeManager(), new InjectionConstructor(new ResolvedParameter<IDatabaseConnection>("DefaultDatabaseConnection")));
I will accept other answers over mine if a better answer is presented, so please guide me if there is simpler way or if there is a way to provide a raw string to the InjectionConstructor class.
Static Value
If you want to hardcode a string to be passed to the constructor, you can simply do:
container.RegisterType<IMyInterface, MyClass>(
new InjectionConstructor(
"ThisIsAHardCopedString",
new ResolvedParameter<IOtherInput>()));
Parameterized Value
However, if you want to use a string from the configuration file, for example, you can do this:
container.RegisterType<IMyInterface, MyClass>(
new InjectionConstructor(
new ResolvedParameter<string>("TheNameOfMyString"),
new ResolvedParameter<IOtherInput>()));
And in your main project, you register the string:
container.RegisterInstance<string>("TheNameOfMyString", Settings.Default.ParameterName);
It looks like you want solution 1, but I'd suggest solution 2, to make it easier to change in the future.
Note: You can have LifetimeManagers coexisting with the solution, it's just not relevant for the solution.

Error using unity in mapping objects in MVC

I am seeing an issue in using of unity in controller constructor. Here are the details -
In unit configuration (unity.config)– here is what I am doing –
container.RegisterType<ISessionWrapper, SessionWrapper>()
In the Controller constructor
public OnboardingController( ISessionWrapper sessionwrapper )
{
SessionWrapper = sessionwrapper;
}
SessionWrapper
public interface ISessionWrapper
{
string Brand { get; set; }
//string CurrenSessionCulture { get; set; }
}
public class SessionWrapper : ISessionWrapper
{
public string Brand
{
get;
set;
}
}
Error occuring in doing this
No parameterless constructor defined for this object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.MissingMethodException: No parameterless constructor defined for this object.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.****
When I change the Controller Constructor definition like this it is all working fine.
public OnboardingController()
: this(new SessionWrapper())
{
//
}
You need to use a custom ControllerFactory using Unity to resolve instances of your controller classes. The default ControllerFactory used by MVC requires that the controller classes have a parameterless constructor.
A custom ControllerFactory using Unity looks like
public class UnityControllerFactory : DefaultControllerFactory {
private readonly IUnityContainer _container;
public UnityControllerFactory (IUnityContainer container) {
_container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) {
if (controllerType != null) {
return _container.Resolve(controllerType) as IController;
}
else {
return base.GetControllerInstance(requestContext, controllerType);
}
}
}
On application start (normally in the global.asax) you register your ControllerFactory in the MVC Runtime using the following code
var container = // initialize your unity container
var factory = new UnityControllerFactory(container);
ControllerBuilder.Current.SetControllerFactory(factory);

InstancePerApiControllerType not working

I am attempting to configure a web service with Autofac so that I can map a different connection context for each controller:
// database connections
container.Register(c => new DocumentControllerActivator()).As<IHttpControllerActivator>().InstancePerApiControllerType(typeof(DocumentController));
container.Register(c => new WorkflowControllerActivator()).As<IHttpControllerActivator>().InstancePerApiControllerType(typeof(WorkflowController));
and:
public class WorkflowControllerActivator : IHttpControllerActivator
{
// snip...
var connectionString = "workflow connection string";
var container = new ContainerBuilder();
container.Register(c =>
{
var newConnectionContext = new SqlServerConnectionContext(connectionString) {ProductID = productId};
newConnectionContext.Open();
return newConnectionContext;
}).As<ISqlServerConnectionContext>().As<IConnectionContext>().InstancePerApiRequest();
var dr = (AutofacWebApiDependencyResolver)GlobalConfiguration.Configuration.DependencyResolver;
container.Update(dr.Container.ComponentRegistry);
return (IHttpController)request.GetDependencyScope().GetService(typeof(WorkflowController));
}
The DocumentControllerActivator differs only in the connection string the the return object type.
[AutofacControllerConfiguration]
public class WorkflowController : ApiController
When I attempt to access the service, the DocumentController throws an error saying that "Unable to cast object of type 'SearchService.Controllers.WorkflowController' to type 'SearchService.Controllers.DocumentController'." It's as if the second InstancePerApiControllerType registration is overwriting the first (i.e. it is doing it for all controllers).
Any suggestions where I've gone wrong? Or, an alternate solution? (Other than a service locator pattern in each controller.)
Not sure why the ControllerActivator approach isn't working, but a simpler and less web api stack specific alternative could be:
public interface ISqlServerConnectionContextFactory
{
ISqlServerConnectionContext Create();
}
// Register this with your ContainerBuilder
public class SqlServerConnectionContextFactory : ISqlServerConnectionContextFactory
{
private string _connectionString;
public SqlServerConnectionContextFactory(string connectionString)
{
_connectionString = connectionString;
}
public ISqlServerConnectionContext Create()
{
var connectionContext = new SqlServerConnectionContext(_connectionString);
connectionContext.Open();
return connectionContext;
}
}
public class MyController : ApiController
{
private ISqlServerConnectionContext _sqlServerConnectionContext;
public MyController(Func<string, ISqlServerConnectionContextFactory> connectionFactory)
{
_sqlServerConnectionContext = connectionFactory("MyConnectionString");
}
}
See http://nblumhardt.com/2010/01/the-relationship-zoo/ for more information about AutoFac relationships and auto generated factories
In this case, when the AutoFac Container sees the Func parameter, it passes in a delegate that acts as a factory method that returns a ISqlServerConnectionContextFactory and passes the string through to its constructor. AutoFac really is rather clever!

ServiceStack - Error trying to resolve Service {X} or one of its autowired dependencies

I am using servicestack and having problems with auto wiring.
Error trying to resolve Service '{Service}' or one of its autowired dependencies (see inner exception for details)
I don't need help figuring how exactly what the problem is. What I actually want is a way to see the inner exception. The inner exception should tell me the except problem without me having to figure it out but it not displayed in either the exception returned, or in the logs.
Setting DebugMode doesn't help either, it just includes the stack track of the topmost exception.
So basically, how do I stop servicestack from hiding the inner exception details?
I ran into this same issue and it ended up being that there was an exception being thrown inside of the constructor that I had created for the particular endpoint class. Example...
public class PartnerService : Service
{
private PartnerManagementService _partnerManagementService;
public PartnerService()
{
var configuration = new Configuration();
_partnerManagementService = new PartnerManagementService(configuration);
}
public object Get(PartnerGet partner)
{
try
{
var partners = _partnerManagementService.getPartners();
if (!partners.Any())
{
return new HttpError(HttpStatusCode.NotFound, "Partners Could not be found");
}
return partners;
}
catch (Exception e)
{
return new HttpError(HttpStatusCode.InternalServerError, e);
}
}
If it so happens that an exception is thrown inside of the constructor, ServiceStack will not be able to resolve the service or one of its dependencies, in this case that dependency being the constructor for the class.
If you put a try/catch in the constructor for the class you could get an exception that actually makes sense.
ServiceStack should already return the inner Exception, i.e. here's the source of the error:
private Exception CreateResolveException<TService>(Exception ex)
{
var errMsg = "Error trying to resolve Service '{0}' or one of its autowired dependencies (see inner exception for details).".Fmt(typeof(TService).FullName);
return new Exception(errMsg, ex);
}
Basically there was a problem with your IOC configuration and that one of the dependencies caused an error.
You can change ServiceStack to serialize the Inner Exception with:
SetConfig(new EndpointHostConfig {
ReturnsInnerException = true,
});
But this already defaults to true.
So the exception should already contain the Inner Exception, are you referring to what Exception gets serialized or the exception thrown in code?
One option could be to grab the actual source code from Github and add it as a project to your solution, as opposed to using a compiled DLL, then you could step through the actual code and see exactly where the exception is raised and why.
I have exactly the same exception.
In my case, it happens once migrated to ServiceStack v4. With v3, all works perfectly.
IoC configuration
public class AppHost : AppHostBase
{
public AppHost() : base("Northwind web services", typeof(CustomersService).Assembly)
{ }
public override void Configure( Container container )
{
SetConfig(new HostConfig
{
DebugMode = true,
ReturnsInnerException = true,
});
var dbFactory = new OrmLiteConnectionFactory("~/Northwind.sqlite".MapHostAbsolutePath(), SqliteDialect.Provider);
container.Register(dbFactory);
// Dependencies
container.RegisterAs<CustomerEntityRepository, ICustomerEntityRepository>();
container.RegisterAutoWired<CustomersService>();
}
}
Base class
public abstract class Repository<TEntity> : IRepository<TEntity> where TEntity : IEntity, new()
{
protected IDbConnectionFactory dbFactory { get; set; }
public Repository( IDbConnectionFactory factory )
{
dbFactory = factory;
}
}
Inherited class
public class CustomerEntityRepository : Repository<CustomerEntity>, ICustomerEntityRepository
{
public CustomerEntityRepository( IDbConnectionFactory dbFactory )
: base(dbFactory)
{
}
}
}
Only solution I've found is:
container.RegisterAs<ICustomerEntityRepository>(c => new CustomerEntityRepository(dbFactury));
Here's full exception message returned http://pastebin.com/jJntNN5p

Categories