문제

Ok, after searching Google, here and several ASP/MVC forums I am bound to have to ask what the hell I am doing wrong here.

I have a good start to my application, an ok understanding of DI, IoC and am using the Repository, Service and UnitOfWork patterns. When I attempt to load a controller that needs the DI from Unity, it's as if unity is not resolving any of the registered items, or that I have done it poorly. From all the examples I can see for this version (not the version that creates the Bootstrap.cs file that is then called from Global.asax) I am doing what others have done with no love from Unity.

My core question is: Have I setup/configured Unity to inject the items into the controller constructor as needed or not. If I have, any ideas why it's not working like examples I have seen?

I keep getting the error that the AssetController needs to have a parameterless public constructor. If I add one, then it uses it without the DI and if I don't add one, then it yells about not having it.

Thanks, code below.

UnityConfig.cs

namespace CARS.web.App_Start
{
    /// <summary>
    /// Specifies the Unity configuration for the main container.
    /// </summary>
    public class UnityConfig
    {
        #region Unity Container
        private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
        {
            var container = new UnityContainer();
            RegisterTypes(container);
            return container;
        });

        /// <summary>
        /// Gets the configured Unity container.
        /// </summary>
        public static IUnityContainer GetConfiguredContainer()
        {
            return container.Value;
        }
        #endregion

        /// <summary>Registers the type mappings with the Unity container.</summary>
        /// <param name="container">The unity container to configure.</param>
        /// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to 
        /// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
        public static void RegisterTypes(IUnityContainer container)
        {
            // NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
            // container.LoadConfiguration();

            // TODO: Register your types here
            // container.RegisterType<IProductRepository, ProductRepository>();
            container.RegisterType<IDataContext, CARSDEMOContext>(new PerRequestLifetimeManager())
                .RegisterType<IAssetService, AssetService>()
                .RegisterType<IUnitOfWork, UnitOfWork>()
                .RegisterType<IRepository<Asset>, Repository<Asset>>();
                //.RegisterType<AssetController>(new InjectionConstructor(typeof(IAssetService), typeof(IUnitOfWork)));
        }
    }
}

AssetController.cs (constructor portion where I am doing the injection params)

namespace CARS.web.Controllers
{
    public class AssetController : Controller
    {
        private readonly IAssetService _assetService;
        private readonly IUnitOfWork _unitOfWork;

        public AssetController(IAssetService assetService, IUnitOfWork unitOfWork)
        {
            _assetService = assetService;
            _unitOfWork = unitOfWork;
        }
        //other methods for CRUD etc stripped for brevity
    }
}

IAssetService.cs (first param is the assetService )

namespace CARS.service
{
    public interface IAssetService : IService<Asset>
    {
        Task<IEnumerable<Asset>> GetAsync();
        Task<Asset> FindAsync(Guid id);
        Asset Add(Asset asset);
        Asset Update(Asset asset);
        void Remove(Guid id);
    }
}

AssetService.cs (concrete implementation for IAssetService interaction)

namespace CARS.service
{


    public class AssetService : Service<Asset>, IAssetService
    {
        private readonly IRepositoryAsync<Asset> _repository;

        public AssetService(IRepositoryAsync<Asset> repository) : base(repository)
        {
            _repository = repository;
        }

        public Task<IEnumerable<Asset>> GetAsync()
        {
            //return _repository.Query().SelectAsync();
            return _repository.Query().SelectAsync();
        }

        public Task<Asset> FindAsync(Guid id)
        {
            return _repository.FindAsync(id);
        }

        public Asset Add(Asset asset)
        {
            _repository.Insert(asset);
            return asset;
        }

        public Asset Update(Asset asset)
        {
            _repository.Update(asset);
            return asset;
        }

        public void Remove(Guid id)
        {
            _repository.Delete(id);
        }
    }

}

IUnitOfWork.cs (this is from Long Le's Generic UofW and Repository - http://genericunitofworkandrepositories.codeplex.com/)

namespace Repository.Pattern.UnitOfWork
{
    public interface IUnitOfWork : IDisposable
    {
        int SaveChanges();
        Task<int> SaveChangesAsync();
        void Dispose(bool disposing);
        IRepository<TEntity> Repository<TEntity>() where TEntity : IObjectState;
        void BeginTransaction();
        bool Commit();
        void Rollback();
    }
}

UnitOfWork.cs (again from Long Le's framework)

namespace Repository.Pattern.Ef6
{
    public class UnitOfWork : IUnitOfWork, IUnitOfWorkAsync
    {
        #region Private Fields

        private readonly IDataContextAsync _dataContext;
        private bool _disposed;
        private ObjectContext _objectContext;
        private Dictionary<string, object> _repositories;
        private DbTransaction _transaction;

        #endregion Private Fields

        #region Constuctor/Dispose

        public UnitOfWork(IDataContextAsync dataContext)
        {
            _dataContext = dataContext;
        }

        public void Dispose()
        {
            if (_objectContext != null && _objectContext.Connection.State == ConnectionState.Open)
                _objectContext.Connection.Close();

            Dispose(true);
            GC.SuppressFinalize(this);
        }

        public virtual void Dispose(bool disposing)
        {
            if (!_disposed && disposing)
                _dataContext.Dispose();
            _disposed = true;
        }

        #endregion Constuctor/Dispose

        public int SaveChanges()
        {
            return _dataContext.SaveChanges();
        }

        public IRepository<TEntity> Repository<TEntity>() where TEntity : IObjectState
        {
            return RepositoryAsync<TEntity>();
        }

        public Task<int> SaveChangesAsync()
        {
            return _dataContext.SaveChangesAsync();
        }

        public Task<int> SaveChangesAsync(CancellationToken cancellationToken)
        {
            return _dataContext.SaveChangesAsync(cancellationToken);
        }

        public IRepositoryAsync<TEntity> RepositoryAsync<TEntity>() where TEntity : IObjectState
        {
            if (_repositories == null)
                _repositories = new Dictionary<string, object>();

            var type = typeof (TEntity).Name;

            if (_repositories.ContainsKey(type))
                return (IRepositoryAsync<TEntity>) _repositories[type];

            var repositoryType = typeof (Repository<>);
            _repositories.Add(type, Activator.CreateInstance(repositoryType.MakeGenericType(typeof (TEntity)), _dataContext, this));

            return (IRepositoryAsync<TEntity>) _repositories[type];
        }

        #region Unit of Work Transactions

        public void BeginTransaction()
        {
            _objectContext = ((IObjectContextAdapter) _dataContext).ObjectContext;
            if (_objectContext.Connection.State != ConnectionState.Open)
            {
                _objectContext.Connection.Open();
                _transaction = _objectContext.Connection.BeginTransaction();
            }
        }

        public bool Commit()
        {
            _transaction.Commit();
            return true;
        }

        public void Rollback()
        {
            _transaction.Rollback();
            ((DataContext)_dataContext).SyncObjectsStatePostCommit();
        }

        #endregion

        // Uncomment, if rather have IRepositoryAsync<TEntity> IoC vs. Reflection Activation
        //public IRepositoryAsync<TEntity> RepositoryAsync<TEntity>() where TEntity : EntityBase
        //{
        //    return ServiceLocator.Current.GetInstance<IRepositoryAsync<TEntity>>();
        //}
    }
} 

Updated to include the SetResolver info from UnityMvcActivator.cs

using System.Linq;
using System.Web.Mvc;
using Microsoft.Practices.Unity.Mvc;

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(CARS.web.App_Start.UnityWebActivator), "Start")]

namespace CARS.web.App_Start
{
    /// <summary>Provides the bootstrapping for integrating Unity with ASP.NET MVC.</summary>
    public static class UnityWebActivator
    {
        /// <summary>Integrates Unity when the application starts.</summary>
        public static void Start() 
        {
            var container = UnityConfig.GetConfiguredContainer();

            FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
            FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));

            DependencyResolver.SetResolver(new UnityDependencyResolver(container));

            // TODO: Uncomment if you want to use PerRequestLifetimeManager
             Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
        }
    }
}

I have read/tried the following info/data and nothing has fixed it:

The type IUserStore`1 does not have an accessible constructor

How to add MVC 5 authentication to Unity IoC?

Types not resolving with Unity [MVC 5]

I have ready where one must write a ControllerFactory for Unity to be able to do this, but that seems quite a bit of work when all the examples I have found simply have the config registered, and the injection apparently happening on the controllers and other classes as need.

And finally the error:

The following server error was encountered: 
An error occurred when trying to create a controller of type           'CARS.web.Controllers.AssetController'. Make sure that the controller has a parameterless     public constructor.Details are: 
at     System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext    requestContext, Type controllerType) at    System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext,     String controllerName) at System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase     httpContext, IController& controller, IControllerFactory& factory) at     System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback     callback, Object state) at     System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionSte    p.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean&     completedSynchronously)

Thanks

도움이 되었습니까?

해결책

You need to set the DependencyResolver. I cant see the code in the example you provided where this is done.

Once setting up your UnityContainer and registering your types, you need to set the System.Web.MVC.DependencyResolver.

 DependencyResolver.SetResolver(new UnityDependencyResolver(container));

다른 팁

You may have missed (like I did) to register the async types in UnityConfig.cs
Check if you have this:

container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager())
            .RegisterType<IUnitOfWorkAsync, UnitOfWork>(new PerRequestLifetimeManager())
            .RegisterType<IDataContextAsync, SomeDBContext>(new PerRequestLifetimeManager())
            .RegisterType<IDataContext, SomeDBContext>(new PerRequestLifetimeManager())
            .RegisterType<ISomeService, SomeService>(new PerRequestLifetimeManager())
            .RegisterType<IRepositoryAsync<Some>, Repository<Some>>(new PerRequestLifetimeManager());

1: Uncomment in file UnityMvcActivator this line:

Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));

2: Basic registration with Unity + UnitOfwork + Repository this must exists in file: UnityConfig:

container.RegisterType<IDataContextAsync, KlussendirectContext>(new PerRequestLifetimeManager());
container.RegisterType<IDataContext, KlussendirectContext>(new PerRequestLifetimeManager());
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager());
container.RegisterType<IUnitOfWorkAsync, UnitOfWork>(new PerRequestLifetimeManager());

3: When you use Dependency Injection in a controller(api) then a parameter less constructor should exists: e.g.

 public MyNameController() : base(){}

If followed those steps, it should work (Edit, Insert, Delete, etc..)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top