Reputation: 436
I was trying to use the DBContextScopeFactory and running into an issue.
public class VendorRepository : IVendorRepository
{
private readonly IDbContextScopeFactory _dbContextScopeFactory;
public VendorRepository(IDbContextScopeFactory dbContextScopeFactory)
{
if (dbContextScopeFactory == null)
{
throw new ArgumentNullException("dbContextScopeFactory");
}
_dbContextScopeFactory = dbContextScopeFactory;
}
public IList<MyVendor> GetMyVendors(int requestorId)
{
IList<MyVendor> vndrsList = null;
using (var dbContextScope = _dbContextScopeFactory.CreateReadOnly())
{
var dbContext = dbContextScope.DbContexts.Get<VendorMgmtContext>();
var vndrs = (from a in dbContext.sp_GetVendorByRequestor(requestorId)
select new MyVendor
{
VendorId = a.VendorId,
VendorName = a.VendorName,
CreatedByUserId = a.CreatedByUserId,
CreatedDate = a.CreatedDate
});
vndrsList = vndrs.ToList();
}
return vndrsList;
}
}
Unit Testing works great since it was similar to the Demo Application project. (in other words, I was not registering it in the UnityConfig.cs file.
[TestMethod]
public void GetMyVendors()
{
// Arrange
var dbContextScope = new DbContextScopeFactory();
var db = new VendorMgmtContext();
VendorRepository repository = new VendorRepository(dbContextScope);
IEnumerable<MyVendor> myVendor = null;
// Act
myVendor = repository.GetMyVendors(3);
// Assert
Assert.IsNotNull(myVendor);
}
So now I'm not quite sure how to register this in the UnityConfig.cs file I tried:
container.RegisterType<IAmbientDbContextLocator, AmbientDbContextLocator>();
container.RegisterType<IDbContextScopeFactory, DbContextScopeFactory>();
container.RegisterType<VendorMgmtContext, VendorMgmtContext>(new PerResolveLifetimeManager(), new InjectionConstructor());
container.RegisterType<IVendorRepository, VendorRepository>(new PerResolveLifetimeManager());
container.RegisterType<IVendorService, VendorService>(new PerResolveLifetimeManager());
But I received a server error: "The type IDbContextFactory does not have an accessible constructor. "
I also tried:
container.RegisterType<IAmbientDbContextLocator, AmbientDbContextLocator>();
container.RegisterType<IDbContextScopeFactory, DbContextScopeFactory>(new InjectionFactory((a) => new DbContextScopeFactory()));
and also received errors. I'm pretty sure it's the way I'm registering this new implementation. Thank you in advance for your help.
Update: Error with registering:
container.RegisterType<IDbContextScopeFactory, DbContextScopeFactory>(new InjectionFactory((a) => new DbContextScopeFactory()));
Message: "An error occurred when trying to create a controller of type 'VendorController'. Make sure that the controller has a parameterless public constructor"
ExceptionType: System.InvalidOperationException
StackTrace:
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()
InnerException:
Message: "Type 'Portal.Controllers.Api.VendorController' does not have a default constructor"
ExceptionType: System.ArgumentException
StackTrace:
at System.Linq.Expressions.Expression.New(Type type)
at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
Update #2 - updated 'Unity.AspNet.WebApi 3.5.1404.0' & Updated Unity from 'Unity 3.0.1304.1' to 'Unity 3.5.1404.0' I also moved all the registration from the WebApiConfig.cs to the UnityConfig.cs file. Lastly, I modified the Global.asax.cs from
UnityConfig.RegisterComponents();
to
UnityWebApiActivator.Start();
Finally my webAPI is working. Yet, I am still getting the same exception on the MVC side.
[MissingMethodException: No parameterless constructor defined for this object.] System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0 System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +119 System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +232 System.Activator.CreateInstance(Type type, Boolean nonPublic) +83 System.Activator.CreateInstance(Type type) +11 System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +110
[InvalidOperationException: An error occurred when trying to create a controller of type 'Portal.Controllers.VendorController'. Make sure that the controller has a parameterless public constructor.] System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +247 System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +437 System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +257 System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +326 System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +157 System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +88 System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +50 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +103 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155
I do have a constructor
public class VendorController : Controller
{
IVendorService _VendorService;
public VendorController(IVendorService VendorSvc)
{
_VendorService = VendorSvc;
}
// GET: Vendor
public ActionResult Index()
{
return View();
}
}
Upvotes: 3
Views: 1795
Reputation: 22655
Based on your posted stack trace it looks like you are trying to invoke a Web API controller and not an ASP.NET Mvc controller (as the question's tag would imply). Also, the error is not occurring during registration but during instantiation of the controller.
Web API tries to instantiate the controller using the default constructor which you don't have (because you are anticipating injecting dependencies into the constructor). You'll need to set Unity as your dependency resolver to wire up the controller dependencies. You can add the Unity bootstrapper for ASP.NET Web API from NuGet. This will register for you a UnityDependencyResolver (in UnityWebApiActivator.cs):
var resolver = new Microsoft.Practices.Unity.WebApi.UnityDependencyResolver(UnityConfig.GetConfiguredContainer());
GlobalConfiguration.Configuration.DependencyResolver = resolver;
You would also move all your registration code into UnityConfig.cs.
I see you are using a PerResolveLifetimeManager -- you might want to consider changing to use a PerRequestLifetimeManager which is installed with the Unity bootstrapper for ASP.NET MVC. PerRequestLifetimeManager will give automatic Disposing of IDisposable objects at the end of the web request.
Upvotes: 1
Reputation: 56859
The error message clearly states what the problem is. You haven't setup your IControllerFactory
or IDependencyResolver
correctly to resolve instances with Unity. It has nothing to do with your registration.
ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container));
OR
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
Note that you can either build one of these yourself or use a stock implementation from somewhere. But also note that using IControllerFactory
is considered the "correct" approach to DI.
Upvotes: 0