Question ASP.NET web API Unity TransientLifetimeManager how to dispose Dbcontext?

raysefo

Well-known member
Joined
Feb 22, 2019
Messages
362
Programming Experience
10+
Hello,

I am using a unit of work, generic repo and Unity as DI. My problem is TransientLifetimeManager can't dispose Dbcontext so I have to do it somehow. Could you please check my code and help me? I couldn't find a way to dispose.

Here is my controller:
C#:
namespace Game.Controllers
{
    [System.Web.Http.RoutePrefix("api/v2/game")]
    public class GameController : ApiController
    {
        private readonly IGameServices _gameServices;
     

        #region Public Constructor

        /// <summary>
        /// Public constructor to initialize game service instance
        /// </summary>
        public GameController(IGameServices gameServices)
        {
            _gameServices = gameServices;
        }

       
        #endregion


        // POST: api/Game
        //[RequireHttps] For Prod Only

        [HttpPost, Route("purchase")]
        public async Task<IHttpActionResult> PurchaseGame(RequestDto game)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            //Call Services
            var gameConfirmResponse = await _gameServices.GamePurchase(game);
            switch (gameConfirmResponse.StatusCode)
            {
                case HttpStatusCode.NotFound:
                {
                    return NotFound();
                }
                case HttpStatusCode.InternalServerError:
                {
                    return InternalServerError();
                }
                case HttpStatusCode.OK:
                {
                    if (gameConfirmResponse.Content == null)
                    {
                        return new System.Web.Http.Results.ResponseMessageResult(
                            Request.CreateErrorResponse((HttpStatusCode) 222, new HttpError("No Results Found")));
                    }

                    var responseStream = await gameConfirmResponse.Content.ReadAsStringAsync();

                    var resultResponse = JsonConvert.DeserializeObject<GameConfirmResponse>(responseStream);
                    if (resultResponse.coupons == null)
                    {
                        return new System.Web.Http.Results.ResponseMessageResult(
                            Request.CreateErrorResponse((HttpStatusCode) 222,
                                new HttpError("No Coupons Available for this Game")));
                    }

                    //Transform GameConfirmResponse into DTO for returning result
                    var config = new MapperConfiguration(cfg =>
                    {
                        cfg.CreateMap<GameConfirmResponse, GameConfirmResponseDto>();
                        cfg.CreateMap<Coupon, CouponDto>();
                    });
                    var iMapper = config.CreateMapper();
                    var resultDto = iMapper.Map<GameConfirmResponse, GameConfirmResponseDto>(resultResponse);
                    return Ok(resultDto);
                }
                case HttpStatusCode.Unauthorized:
                {
                    return Unauthorized();
                }
                case HttpStatusCode.RequestTimeout:
                {
                    return InternalServerError();
                }
            }

            return Ok(gameConfirmResponse);
        }

       

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                ???
            }
            base.Dispose(disposing);
        }
    }
}

Here is my Service:
C#:
namespace BusinessService
{
    public class GameServices : IGameServices
    {
        private readonly UnitOfWork _unitOfWork;

        /// <summary>
        /// Public constructor.
        /// </summary>
        public GameServices(UnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }
       
        /// <summary>
        /// Creates a product
        /// </summary>
        /// <param name="requestDto"></param>
        /// <returns></returns>
        public async Task<HttpResponseMessage> GamePurchase(RequestDto requestDto)
        {
            HttpResponseMessage response = null;

            response = await CallGameNew(requestDto) ?? await CallRazerService(requestDto);

            return response;
        }

      

        private async Task<HttpResponseMessage> CallRazerService(RequestDto requestDto)
        {
            HttpResponseMessage response = null;

            using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
               


                #region Call Razer initiate/confirm

                //Call Razer for initiation
                response = await Utilities.CallRazer(gameRequest, "purchaseinitiation");

                //Read response
                var htmlResponse = await response.Content.ReadAsStringAsync();
                var gameResponse = JsonConvert.DeserializeObject<GameResponse>(htmlResponse);

                //Adding initiation response into database
                _unitOfWork.GameResponseRepository.Insert(gameResponse);

                if (gameResponse.initiationResultCode == "00")
                {
                    gameRequestDto = iMapper.Map<GameRequest, GameRequestDto>(gameRequest);
                    gameRequestDto.validatedToken = gameResponse.validatedToken;
                    //Create signature
                    var gameConfirmRequest = Utilities.CreateSignature(gameRequestDto, RequestType.Confirm);

                    //Transform DTO into GameRequest for calling Razer Initiate
                    var gameConfirmRequests = iMapper.Map<GameRequest, GameConfirmRequest>(gameConfirmRequest);

                    //Add confirm request into database
                    _unitOfWork.GameConfirmRequestRepository.Insert(gameConfirmRequests);

                    //Call Razer for confirm
                    response = await Utilities.CallRazer(gameConfirmRequest, "purchaseconfirmation");

                    //Read response
                    htmlResponse = await response.Content.ReadAsStringAsync();
                    var gameConfirmResponse = JsonConvert.DeserializeObject<GameConfirmResponse>(htmlResponse);

                    //Set service
                    gameConfirmResponse.service = "RAZER";
                    //Add confirm response into database
                    _unitOfWork.GameConfirmResponseRepository.Insert(gameConfirmResponse);
                }

                #endregion

                await _unitOfWork.SaveAsync();
                scope.Complete();
            }

            return response;
        }


        }

    }
}

Here is UOW:
C#:
namespace DataModels
{
    public class UnitOfWork : IDisposable
    {
        private readonly GameContext _context;
        private readonly GenericRepository<GameRequest> gameRequestRepository;
      

        public UnitOfWork(GameContext context)
        {
            _context = context;
        }

        public GenericRepository<GameRequest> GameRepository
        {
            get
            {
                return this.gameRequestRepository ?? new GenericRepository<GameRequest>(_context);
            }
        }
      

        public void Save()
        {
            _context.SaveChanges();
        }

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

        private bool disposed = false;

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

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

Here is Unity config:
C#:
namespace Game
{
    /// <summary>
    /// Specifies the Unity configuration for the main container.
    /// </summary>
    public static class UnityConfig
    {
        #region Unity Container
        private static Lazy<IUnityContainer> container =
          new Lazy<IUnityContainer>(() =>
          {
              var container = new UnityContainer();
              RegisterTypes(container);
              return container;
          });

        /// <summary>
        /// Configured Unity Container.
        /// </summary>
        public static IUnityContainer Container => container.Value;
        #endregion

       
        public static void RegisterTypes(IUnityContainer container)
        {
            // Default empty Time manager!
            container.RegisterType<IGameServices, GameServices>().RegisterType<UnitOfWork>(new TransientLifetimeManager());
            container.RegisterType<IUserValidate, UserValidate>(new TransientLifetimeManager());
           
        }
    }
}
 
WTF?!?!? Did I just read that right?
C#:
namespace DataModels
{
    public class UnitOfWork : IDisposable
    {
        private readonly GameContext _context;

        :

        public UnitOfWork(GameContext context)
        {
            _context = context;
        }

        :

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

In general, when using dependency injection, it is not the responsibility of the class that receives a dependency to dispose of the dependency.

Why? Because you are breaking the encapsulation. The class now knows enough about it's outside environment to know that it can safely delete something that was handed to it.

What if later down the road you instantiate two of these UnitOfWork objects, but have only one GameContext? How do you tell one of the two units of work to not dispose that game context that you gave it? Now you are again breaking encapsulation the Law of Demeter because now the outside enviroment knows about the inner workings of the object.
 
WTF?!?!?! What's the point of using an inversion of control tool like Unity if you are not going to use it?
C#:
        public GenericRepository<GameRequest> GameRepository
        {
            get
            {
                return this.gameRequestRepository ?? new GenericRepository<GameRequest>(_context);
            }
        }
}
Why are instantiating a GenericRepository here when a generic repository should be injected into whatever object needs it?

And on another tack regarding this same code, why is it the job of the unit of work to return a generic repository (new or otherwise)? WTF?!?!?!?!
 
Anyway, to answer your original question of how do you get your DI to dispose of your database context, the answer is that you register the database context type with your DI. The DI's job is to take care of the lifetime of the instances of the objects, and ensuring that the instances get injected over into the types that have them as a dependency.

I'm getting the distinct feeling that you've taken the buzzwords like Unit Of Work, Repository, and Dependency Injection and are trying to mash them all into this project, but haven't fully taken time to learn how to use them independent of each other. Now you are on a very steep learning curve while you throw them all together without really a good understanding of the why you would use them. For example, your Unit of Work class above seems like a thin layer around the a game context and not really adding any real value.
 
Yes, you are right, this is my first time trying to implement web API. I read articles and down the road confused many times. Any suggestions (especially samples) to improve the code?

Anyway, to answer your original question of how do you get your DI to dispose of your database context, the answer is that you register the database context type with your DI. The DI's job is to take care of the lifetime of the instances of the objects, and ensuring that the instances get injected over into the types that have them as a dependency.

I read that transient lifetime does not automatically dispose of dbcontext so somehow I should take care of it. This is my main issue right now besides your comments above.
 
Does it solve my issue if I add dispose of into Service? What do you think?

C#:
namespace BusinessService
{
    public class GameServices : IGameServices
    {
        private readonly UnitOfWork _unitOfWork;

        /// <summary>
        /// Public constructor.
        /// </summary>
        public GameServices(UnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }
        

        /// <summary>
        /// Creates a product
        /// </summary>
        /// <param name="requestDto"></param>
        /// <returns></returns>
        public async Task<HttpResponseMessage> GamePurchase(RequestDto requestDto)
        {
            HttpResponseMessage response = null;

            response = await CallGameNew(requestDto) ?? await CallRazerService(requestDto);

            return response;
        }

      

        private async Task<HttpResponseMessage> CallGameNew(RequestDto requestDto)
        {
            HttpResponseMessage response = null;
            using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
                //Transform DTO into GameRequest for calling Game Initiate
                var config = new MapperConfiguration(cfg =>
                {
                    cfg.CreateMap<RequestDto, GameRequest>();
                    cfg.CreateMap<GameRequest, GameConfirmRequest>();
                    cfg.CreateMap<GameBank, GameConfirmResponse>();
                    cfg.CreateMap<GameBankPin, Coupon>();
                    cfg.CreateMap<GameRequest, GameRequestDto>();
                });
                var iMapper = config.CreateMapper();
                var gameRequest = iMapper.Map<RequestDto, GameRequest>(requestDto);
                //Unique reference ID
                gameRequest.referenceId = Guid.NewGuid();
                
                var gameRequestDto = iMapper.Map<GameRequest, GameRequestDto>(gameRequest);
                //Create signature
                gameRequest = Utilities.CreateSignature(gameRequestDto, RequestType.Initiate);

                //Set service
                gameRequest.service = "OUR";

                //Add initiation request into database
                _unitOfWork.GameRepository.Insert(gameRequest);

                //Query GameBank database
                var gameBankResult = await _unitOfWork.GameBankRepository.GetGamesAsync(g =>
                    g.productCode == requestDto.productCode && g.referenceId == Guid.Empty);

                
                if (gameBankResult.Count() >= requestDto.quantity)
                {
                    var k = requestDto.quantity - 1;
                    for (var i = k; i >= 0; --i)
                    {
                        gameBankResult[i].referenceId = gameRequest.referenceId;
                        gameBankResult[i].requestDateTime = DateTime.Now;
                        gameBankResult[i].responseDateTime = DateTime.Now;
                        
                    }

                    //Update GameBank
                    _unitOfWork.GameBankRepository.Update(gameBankResult[k]);

                    var gameBankConfirmResponse =
                        iMapper.Map<IList<GameBank>, IList<GameConfirmResponse>>(gameBankResult);

                  
                    if (requestDto.quantity == 1)
                    {
                        gameBankConfirmResponse[k].purchaseStatusDate = DateTime.Now;

                        var resultResponse = JsonConvert.SerializeObject(gameBankConfirmResponse[k],
                            Formatting.Indented,
                            new JsonSerializerSettings()
                            {
                                ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
                            });
                        response = new HttpResponseMessage
                        {
                            StatusCode = System.Net.HttpStatusCode.OK,
                            Content = new StringContent(resultResponse, System.Text.Encoding.UTF8, "application/json"),
                        };
                        //Set service
                        gameBankConfirmResponse[k].service = "OUR";
                        _unitOfWork.GameConfirmResponseRepository.Insert(gameBankConfirmResponse[k]);
                    }
                    else if (requestDto.quantity > 1)
                    {
                        var gameResult = new GameConfirmResponse
                        {
                            coupons = new List<Coupon>()
                        };
                        var price = 0.0;
                        var quantity = 0;

                        foreach (var item in gameBankResult)
                        {
                            price = price + item.unitPrice;
                            quantity = quantity + 1;
                            foreach (var coupons in item.coupons)
                            {
                                var gameCouponResult = new Coupon()
                                {
                                    expiryDate = coupons.expiryDate,
                                    Pin = coupons.Pin,
                                    Serial = coupons.Serial
                                };
                                //Add coupon values
                                gameResult.coupons.Add(gameCouponResult);
                            }

                        }

                        //Set summed/counted values
                        gameResult.referenceId = gameBankResult[0].referenceId;
                        gameResult.productCode = gameBankResult[0].productCode;
                        gameResult.quantity = quantity;
                        gameResult.currency = gameBankResult[0].currency;
                        gameResult.unitPrice = gameBankResult[0].unitPrice;
                        gameResult.totalPrice = price;
                        gameResult.productDescription = gameBankResult[0].productDescription;
                        gameResult.purchaseStatusDate = DateTime.Now;
                        gameResult.totalPayablePrice = price;
                        //Set service
                        gameRequest.service = "OUR";

                        //var gameBankConfirmResponse = iMapper.Map<GameBank, GameConfirmResponse>(gameResult);
                        //Add confirm response into database
                        _unitOfWork.GameConfirmResponseRepository.Insert(gameResult);
                        var resultResponse = JsonConvert.SerializeObject(
                            gameResult, Formatting.Indented,
                            new JsonSerializerSettings()
                            {
                                ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
                            });
                        response = new HttpResponseMessage
                        {
                            StatusCode = System.Net.HttpStatusCode.OK,
                            Content = new StringContent(
                                resultResponse, System.Text.Encoding.UTF8,
                                "application/json"),
                        };
                    }
                    
                }
                
                await _unitOfWork.SaveAsync();

                scope.Complete();
            }

            return response;
        }

    
...

        public void Dispose()
        {
            _unitOfWork.Dispose();
        }

    }
}
 
Does it solve my issue if I add dispose of into Service?
Does your class inherited Idisposable?

If you want to make reusable code, you need to implement reusable methods with reusable code, which is why I told you early on about the use of using blocks. When a using statement is completed executing an object which inherited Idisposable, it will run the self-disposing method itself (after execution) to clean up the objects its resources has used.

somehow I should take care of it. This is my main issue right now besides your comments above.
Your priorities are wrong in my opinion.
 
If you want to make reusable code, you need to implement reusable methods with reusable code, which is why I told you early on about the use of using blocks. When a using statement is completed executing an object which inherited Idisposable, it will run the self-disposing method itself (after execution) to clean up the objects its resources has used.

You are totally right but in my situation, how could I use using? Can you please tell me? Have you checked my source code?

And yes, it is now inherited from IDisposable.
C#:
namespace BusinessService
{
    public class GameServices : IGameServices, IDisposable
    {
        private readonly UnitOfWork _unitOfWork;

        /// <summary>
        /// Public constructor.
        /// </summary>
        public GameServices(UnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }
        ...
        //Some code here

        public void Dispose()
        {
            _unitOfWork.Dispose();
            
        }

    }
}
 
Last edited:
Strictly pseudo, not to be taken as is ::

C#:
namespace TestCSharpApp
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            FooClass FC = new FooClass();
            using (FC)
            {
                Console.WriteLine(FC.foo);
            }
        }
    }
    public class FooClass : IDisposable
    {
        public int foo;
        public void Dispose()
        {
            Console.WriteLine(0);
        }
    }
}
Put a break point on line 12, and when you press F11 and it completes the using cycle, you will notice that the FooClass dispose method will fire. Because I instantiate a new instance of the class on line 8, I want to use it in such a way that what I do with it, and inside it will be exposed of correctly and consistently when the cycle has finished using. If you didn't know already, using blocks are self-disposing, and I'd personally encourage using them at every opportunity where applicable. As aside, I'm betting this is likely why you are getting all those blocked up connections in your connection pool but since we can't see all of your code, I am only surmising.
 
To be honest, there are so many changes in your code I'd make, and I am sorry but I don't have the spare time to sit here doing it for you.
 
As aside, I'm betting this is likely why you are getting all those blocked up connections in your connection pool but since we can't see all of your code, I am only surmising.

C'mon, your example was basic. I posted my code many times. The point is, do you really want to help?

I think according to your sample, this basically might work.
C#:
private async Task<HttpResponseMessage> CallGameNew(RequestDto requestDto)
        {
            HttpResponseMessage response = null;
            using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
                using(_unitOfWork)
                {
               
                    //some code here

                //Add initiation request into database
                _unitOfWork.GameRepository.Insert(gameRequest);

                //Query GameBank database
                var gameBankResult = await _unitOfWork.GameBankRepository.GetGamesAsync(g =>
                    g.productCode == requestDto.productCode && g.referenceId == Guid.Empty);

             
                    //some code there
                   
                        //Add confirm response into database
                        _unitOfWork.GameConfirmResponseRepository.Insert(gameResult);
                       
                    }
                   
                }
               
                await _unitOfWork.SaveAsync();
   }

                scope.Complete();
            }

            return response;
        }
 
Last edited:
My example may have been basic, but its a perfect example of what you asked for : how could I use using? Can you please tell me?

If you can't bother to look at your own code to see where you are instantiating IDisposable objects to apply the necessary alterations, neither can i. And I am sorry if that seems harsh. I am not here to spoon feed you. I am currently working on my own projects, both personal and customers work. What I or anyone else does on these forums is totally obligatory and based upon how much time they can or wish to contribute themselves. I don't have the time, as I have to write Linq/SQL queries, along with a whole class on URI rewriting, so which do you think takes precedence?

I should also point out, you are bordering on gimi tah codez, which is frowned upon. And of course we want to help you, but you need to show commitment too. From the looks of things, you don't seem to be taking any of what Skydiver said on the chin; in either this or your other topics. Take charge.
 
When I added the disposal into GameService (in my 8th thread), I got this error when I try to load test with 350 users with 10 ramp-up time. Actually there is an improvement, before changing the code, I can successfully load test less than 150 users.

I used "using" for all the transactions.
C#:
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {

//code
}


System.Transactions.TransactionException: The operation is not valid for the state of the transaction. ---> System.TimeoutException: Transaction Timeout. The underlying provider failed on Open.


Any ideas how to fix this one?
 
Last edited:
System.TimeoutException: Transaction Timeout. The underlying provider failed on Open.
Seems like a problem with your connections not being closed. My theory is that you are using more than one connection. Check for explicitly opened connections and check once a transaction executes, that the connection is also closing afterwards.

Each user is commonly allowed one connection and inside that connection, a user can execute multiple queries in a given scope. If you open more than one connection, your second connection will block your queries from running. You can only run transactions on the instance of which opened your first connection. If you are creating a new instance of your connections, then don't. Use the same instance every time. Never create more than one instance of your connection unless you know that your previous one was correctly discarded.

I would like you to read this question and the accepted answer on StackOverflow. I don't like to often link to that site because of how much misinformation is pushed as a accepted answer when they are not often correct. None-the-less, I'm sure it'll help you in this case.

If you are using IIS Express, right click your tray icon and stop your site. This will free up, or should free up the connections your project may be blocking.
 
I will try this, hope it works.

TransactionScope and multi-threading

Update: After reviewing the documentation here, I see that Database.BeginTransaction() is the preferred EF call. However, this assumes that all of my changes will occur within the same context, which it won't. Short of creating a dummy context and passing around a transaction, I don't believe this solves my issue.

I couldn't understand what he did to solve his issue.
"Update: After reviewing the documentation here, I see that Database.BeginTransaction() is the preferred EF call. However, this assumes that all of my changes will occur within the same context, which it won't. Short of creating a dummy context and passing around a transaction, I don't believe this solves my issue. "

OR is he talking about using Dbcontext as follows instead of transaction?
C#:
using (_unitOfWork)
            {
                //some code here

                //Add initiation request into database
                _unitOfWork.GameRepository.Insert(gameRequest);

                //some code here
                    //Add confirm request into database
                    _unitOfWork.GameConfirmRequestRepository.Insert(gameConfirmRequests);

                  //some code here
                    //Add confirm response into database
                    _unitOfWork.GameConfirmResponseRepository.Insert(gameConfirmResponse);
                }

                #endregion

                await _unitOfWork.SaveAsync();
              
            }
 
Last edited:

Latest posts

Back
Top Bottom