Search code examples
c#asp.net-mvcasp.net-web-apidependency-injectionasp.net-identity

N-tier web API application with autofac


I develop aspnet webapi app using dependency injection with Autofac and i've got one trouble.

I created model Order, repository for it and Unit of Work.

public class Order
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        public string UserId { get; set; }
        public int ServiceId { get; set; }
        public string Header { get; set; }
        public string Description { get; set; }
        public string City { get; set; }
        public string Address { get; set; }
        public int Price { get; set; }
        public string Name { get; set; }
        public string PhoneNumber { get; set; }
        public DateTime CompletedOn { get; set; }
        public DateTime CreatedAt { get; set; }
        public DateTime UpdatedAt { get; set; }
    }

OrderRepository.cs

public class OrderRepository : IRepository<Order>
    {
        private ApplicationContext database;

        public OrderRepository(ApplicationContext database)
        {
            this.database = database;
        }

        public void Create(Order item)
        {
            database.Orders.Add(item);
        }

        public void Delete(int id)
        {
            var order = database.Orders.Find(id);
            if (order != null)
            {
                database.Orders.Remove(order);
            }
        }

        public Order Get(int id)
        {
            return database.Orders.Find(id);
        }

        public IEnumerable<Order> GetList()
        {
            return database.Orders;
        }

        public void Update(Order item)
        {
            database.Entry(item).State = EntityState.Modified;
        }
    }

UnitOfWork.cs

public class UnitOfWork : IUnitOfWork
    {
        private ApplicationContext database;
        private OrderRepository orderRepository;

        private bool disposed = false;

        public IRepository<Order> Orders
        {
            get
            {
                if (orderRepository == null)
                {
                    orderRepository = new OrderRepository(database);
                }

                return orderRepository;
            }
        }

        public UnitOfWork(ApplicationContext database)
        {
            this.database = database;
        }

        public async Task SaveAsync()
        {
            await database.SaveChangesAsync();
        }

        public virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    database.Dispose();
                }
                this.disposed = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }

Then i made OrderManager

public class OrderManager : IOrderManager
    {
        IUnitOfWork database;

        public OrderManager(IUnitOfWork database)
        {
            this.database = database;
        }

        public void CreateOrder(OrderViewModel order)
        {
            database.Orders.Create(new Order
            {
                UserId = order.UserId,
                Header = order.Header,
                Description = order.Description,
                City = order.City,
                Address = order.Address,
                Price = order.Price,
                Name = order.Name,
                PhoneNumber = order.PhoneNumber,
                CompletedOn = order.CompletedOn,
                CreatedAt = order.CreatedAt,
                UpdatedAt = order.UpdatedAt
            });
        }

        public Order GetOrder(int id)
        {
            return database.Orders.Get(id);
        }

        public IEnumerable<Order> GetOrders()
        {
            return database.Orders.GetList();
        }
    }

Then i tried to make inject and i think somewhere here error because i writing this.

public static void ConfigureContainer()
        {
            var builder = new ContainerBuilder();

            builder.RegisterControllers(typeof(User).Assembly);

            builder.RegisterType<ApplicationContext>().AsSelf().InstancePerRequest().WithParameter("connectionString", "DefaultConnection");
            builder.RegisterType<ApplicationUserManager>().AsSelf().InstancePerRequest();
            builder.Register(c => new UnitOfWork(c.Resolve<ApplicationContext>())).AsImplementedInterfaces().InstancePerRequest();
            builder.RegisterType<OrderManager>().AsSelf().InstancePerRequest();
            //builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().WithParameter("database", new ApplicationContext("DefaultConnection")); ;
            builder.RegisterType<UserStore<User>>().As<IUserStore<User>>().InstancePerLifetimeScope();
            builder.Register(c => new UserStore<User>(c.Resolve<ApplicationContext>())).AsImplementedInterfaces().InstancePerRequest();
            builder.RegisterType<RoleStore<IdentityRole>>().As<IRoleStore<IdentityRole, string>>().InstancePerLifetimeScope();
            //builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).As<IAuthenticationManager>();

            builder.Register(c => new IdentityFactoryOptions<ApplicationUserManager>
            {
                DataProtectionProvider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("ASP.NET Identity​")
            });

            var container = builder.Build();

            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        }

And the place where error pops up

 protected OrderManager orderManager;

        public ValuesController()
        { }

        public ValuesController(OrderManager orderManager)
        {
            this.orderManager = orderManager;
        }

        public OrderManager OrderManager
        {
            get
            {
                return orderManager;
            }
            set
            {
                orderManager = value;
            }
        }

public OrderViewModel Get(int id)
        {
            var order = OrderManager.GetOrder(id);

            var orderViewModel = new OrderViewModel
            {
                Header = order.Header,
                Description = order.Description,
            };

            return orderViewModel;
        }

When i getting order the site drop because OrderManager is null. I suppose problem in the my DI realization but i still don't know how to fix it.

Error


Solution

  • I think your setup code is not correct. In the ConfigureCOntainer, do this

     public static void ConfigureContainer()
            {
                var builder = new ContainerBuilder();
    
                // Get your HttpConfiguration.
                var config = GlobalConfiguration.Configuration;
    
                // Register your Web API controllers.
                builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
    
                // OPTIONAL: Register the Autofac filter provider.
                builder.RegisterWebApiFilterProvider(config);
    
                // OPTIONAL: Register the Autofac model binder provider.
                builder.RegisterWebApiModelBinderProvider();
    
    
                builder.RegisterType<ApplicationContext>().AsSelf().InstancePerRequest().WithParameter("connectionString", "DefaultConnectionString");
                builder.Register(c => new UnitOfWork(c.Resolve<ApplicationContext>())).AsImplementedInterfaces().InstancePerRequest();
                builder.RegisterType<OrderManager>().AsSelf().InstancePerRequest();
    
    
    
                // Set the dependency resolver to be Autofac.
                var container = builder.Build();
                config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
            }
    

    and that method should be called before other API config code like

      public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                // Web API configuration and services
                ConfigureContainer();
    
                // Web API routes
                config.MapHttpAttributeRoutes();
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
    
            }
    
    
            public static void ConfigureContainer()
            {
                var builder = new ContainerBuilder();
    
                // Get your HttpConfiguration.
                var config = GlobalConfiguration.Configuration;
    
                // Register your Web API controllers.
                builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
    
                // OPTIONAL: Register the Autofac filter provider.
                builder.RegisterWebApiFilterProvider(config);
    
                // OPTIONAL: Register the Autofac model binder provider.
                builder.RegisterWebApiModelBinderProvider();
    
    
                builder.RegisterType<ApplicationContext>().AsSelf().InstancePerRequest().WithParameter("connectionString", "DefaultConnectionString");
                builder.Register(c => new UnitOfWork(c.Resolve<ApplicationContext>())).AsImplementedInterfaces().InstancePerRequest();
                builder.RegisterType<OrderManager>().AsSelf().InstancePerRequest();
    
    
    
                // Set the dependency resolver to be Autofac.
                var container = builder.Build();
                config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
            }
        }
    

    I can see the instance is created correctly in Web Api controller

    enter image description here

    The controller code is

    public class ValuesController : ApiController
        {
            public ValuesController(OrderManager orderManager)
            {
                this.OrderManager = orderManager;
            }
    
            public OrderManager OrderManager { get; set; }
    
    
            [Route("orders")]
            public IHttpActionResult GetAll()
            {
                return Ok("Received");
            }
    
            [Route("orders/{id}")]
            public OrderViewModel Get(int id)
            {
                var order = OrderManager.GetOrder(id);
    
                var orderViewModel = new OrderViewModel
                {
                    Header = order.Header,
                    Description = order.Description,
                };
    
                return orderViewModel;
            }