locked
Services layer and SuppressFinalize RRS feed

  • Question

  • User-457790453 posted

    Can someone explain why the below class should have GC.SuppressFinalize in its dispose method. The class has dependency on Repository object that holds reference to unmanaged resource (DB connection). The dependency is injected via Autofac in my scenario:

    https://github.com/EduardoPires/EquinoxProject/blob/master/src/Equinox.Application/Services/CustomerAppService.cs

    Thursday, December 21, 2017 10:01 PM

Answers

  • User753101303 posted

    Hi,

    Hummm... As basically posted by DA924 it won't have any effect anyway (and I doubt the author expects to have subclasses with finalizers) so for now I see no real reason for doing this call.

    My guess is that the author implemented Dispose to allow the use of the "using" statement and felt safer with this "SuppressFinalize" call. My personal preference would have been an empty implementation with a comment telling the purpose is to allow the use of "using".

    Please don't flame me if it doesn't help ;-)

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, December 30, 2017 4:28 PM

All replies

  • User1120430333 posted

    https://msdn.microsoft.com/en-us/library/system.gc.suppressfinalize(v=vs.110).aspx

    <copied>

    This method sets a bit in the object header of obj, which the runtime checks when calling finalizers. A finalizer, which is represented by the Object.Finalize method, is used to release unmanaged resources before an object is garbage-collected. If obj does not have a finalizer, the call to the SuppressFinalize method has no effect.

    <end>

    Saturday, December 23, 2017 10:56 AM
  • User475983607 posted

    I can use google! I need more detailed answer on my question

    Basically, it is a common pattern.

    The reference documentation explains the reason for SuppressFinalize and provides examples. 

    https://msdn.microsoft.com/en-us/library/system.gc.suppressfinalize(v=vs.110).aspx

    If there is something you do not understand in the reference docs then you'll need to explain what you do not understand.

    If you inherit from IDisposable and and allow Visual Studio to "Implement IDisposable with Design Template" the templated code contains the GC.SuppressFinalize line with comments that explain how to use the template.

     public class TestDisposable : IDisposable
        {
            #region IDisposable Support
            private bool disposedValue = false; // To detect redundant calls
    
            protected virtual void Dispose(bool disposing)
            {
                if (!disposedValue)
                {
                    if (disposing)
                    {
                        // TODO: dispose managed state (managed objects).
                    }
    
                    // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
                    // TODO: set large fields to null.
    
                    disposedValue = true;
                }
            }
    
            // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
            // ~TestDisposable() {
            //   // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
            //   Dispose(false);
            // }
    
            // This code added to correctly implement the disposable pattern.
            public void Dispose()
            {
                // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
                Dispose(true);
                // TODO: uncomment the following line if the finalizer is overridden above.
                // GC.SuppressFinalize(this);
            }
            #endregion
        }

    If you need help with understanding the reason why the origainl author used athis pattern you'll need to ask the author or read the open source code. 

    Keep in mind that the repository pattern is not recommened when using EF in ASP Core.

    Wednesday, December 27, 2017 11:16 PM
  • User-457790453 posted

    @mgebhard

    The pattern  is understood. 

    My question is specifically around the example I sent, if you check it, the Dispose method doesn't release any un-managed-resources because it is injected (repository)  and then its the responsibility of the injector to release them. In my case it will be the DI container.

    However I believe the call for JUST GC.SuppressFinalize() is just to tell the CLR simply don't send this object for the Finalizer queue? But is this something truly needed in objects that doesn't own the un-managed resource?. Again my question is not about the Dispose pattern.

    mgebhard

    Keep in mind that the repository pattern is not recommened when using EF in ASP Core.

    Could you please explain or refer to something on that? And which pattern is recommended then?

    Friday, December 29, 2017 9:24 AM
  • User1120430333 posted

    mgebhard

    Keep in mind that the repository pattern is not recommened when using EF in ASP Core.

    Could you please explain or refer to something on that? And which pattern is recommended then?

    It's a combination of two patterns and not using a generic Repository over EF. But instead,  one uses the non-generic Repository pattern with the DAO pattern with EF  being used in the DAO in the DAL.

    http://blog.sapiensworks.com/post/2012/11/01/Repository-vs-DAO.aspx

    <copied>

    A repository sits at a higher level. It deals with data too and hides queries and all that but, a repository deals with** business/domain objects**. That’s the difference. A repository will use a DAO to get the data from the storage and uses that data to restore a business object. Or it will take a business object and extract the data that will be persisted. If you have an anemic domain, the repository will be just a DAO. Also when dealing with querying stuff, most of the time a specialized query repository is just a DAO sending DTOs to a higher layer.

    <end>

    https://www.tutorialspoint.com/design_pattern/data_access_object_pattern.htm

    https://en.wikipedia.org/wiki/Data_access_object

    using System;
    using System.Collections.Generic;
    using Entities;
    
    namespace Repository
    {
        public interface IStudentRepo
        {
            DTOStudent GetStudentById(Int32 id);
            List<DTOStudent> GetStudents();
            void CreateStudent(DTOStudent dto);
            void UpdateStudent(DTOStudent dto);
            void DeleteStudent(Int32 id);
        }
    }
    ---------------------------------------------------------
    using System;
    using System.Collections.Generic;
    using Entities;
    using DAL.DAO;
    
    namespace Repository
    {    public class StudentRepo : IStudentRepo
        {
            private IDAOStudent _daoStudent;
    
            public StudentRepo(IDAOStudent daoStudent)
            {
                _daoStudent = daoStudent;
            }
            public DTOStudent GetStudentById(int id)
            {
               return _daoStudent.GetStudentById(id);
            }
            public List<DTOStudent> GetStudents()
            {
                return _daoStudent.GetStudents();
            }
            public void CreateStudent(DTOStudent dto)
            {
                _daoStudent.CreateStudent(dto);
            }
            public void UpdateStudent(DTOStudent dto)
            {
                _daoStudent.UpdateStudent(dto);
            }
            public void DeleteStudent(int id)
            {
                _daoStudent.DeleteStudent(id);
            }
        }
    }
    ---------------------------------------------------------
    using System;
    using System.Collections.Generic;
    using Entities;
    
    namespace DAL.DAO
    {
        public interface IDAOStudent
        {
            DTOStudent GetStudentById(Int32 id);
            List<DTOStudent> GetStudents();
            void CreateStudent(DTOStudent dto);
            void UpdateStudent(DTOStudent dto);
            void DeleteStudent(Int32 id);
        }
    }
    --------------------------------------------------
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Data.Entity;
    using System.Data.Entity.Core.EntityClient;
    using System.Data.Entity.Core.Objects;
    using System.Data.Entity.Infrastructure;
    using System.Data.SqlClient;
    using Entities;
    using DAL.Model;
    
    namespace DAL.DAO
    {
        public class DAOStudent : IDAOStudent
        {
            public DTOStudent GetStudentById(Int32 id)
            {
                var dto = new DTOStudent();
                using (var context = new CUDataEntities())
                {
                    var student = (context.Students.Where(a => a.StudentID == id)).SingleOrDefault();
    
                    if (student != null)
                    {
                        dto.StudentID = student.StudentID;
                        dto.FirstName = student.FirstName;
                        dto.LastName = student.LastName;
                        dto.EnrollmentDate = student.EnrollmentDate;
    
                        var enrolllments =  new DAOEnrollment().GetEntrollmentsByStudentId(id).ToList();
                        var courses = new DAOCourse().GetCoursesByStudentCourseId(student.StudentID).ToList();
    
                        dto.EnrollsandCourses = (from a in enrolllments
                                      join b in courses on a.CourseID equals b.CourseID
                        select new  DTOEnrollandCourse()
                         { Title = b.Title, Credits = b.Credits, Grade = a.Grade }).ToList();
                    }
                }
    
                return dto;
            }
            public void CreateStudent(DTOStudent dto)
            {
                using (var context = new CUDataEntities())
                {
                    var student = new Student
                    {
                        FirstName = dto.FirstName,
                        LastName = dto.LastName,
                        EnrollmentDate = dto.EnrollmentDate
                    };
    
                    context.Students.Add(student);
                    context.SaveChanges();
                }
            }
    
            public void DeleteStudent(int id)
            {
                Student student;
                using (var context = new CUDataEntities())
                {
                    student = (context.Students.Where(a => a.StudentID == id)).SingleOrDefault();
                }
    
                using (var newContext = new CUDataEntities())
                {
                    newContext.Entry(student).State = System.Data.Entity.EntityState.Deleted;
                    newContext.SaveChanges();
                }
            }
    
            public List<DTOStudent> GetStudents()
            {
               
                var dtos = new List<DTOStudent>();
    
                using (var context = new CUDataEntities())
                {
                    //var adapter = (IObjectContextAdapter)context;
                    //var objectContext = adapter.ObjectContext;
                    
                    //var entityConn = objectContext.Connection as EntityConnection;
                    //var dbConn = entityConn.StoreConnection as SqlConnection;
    
                    //dbConn.Open();
    
                    var students = context.Students.ToList();
    
                    foreach(var stud in students)
                    {
                        var dto = new DTOStudent
                        {
                            StudentID = stud.StudentID,
                            FirstName = stud.FirstName,
                            LastName = stud.LastName,
                            EnrollmentDate = stud.EnrollmentDate
                        };
    
                        dtos.Add(dto);
                    }
                }
    
                return dtos;
            }
    
            public void UpdateStudent(DTOStudent dto)
            {
                var student = new Student();
    
                using (var context = new CUDataEntities())
                {
                    student = (context.Students.Where(a => a.StudentID == dto.StudentID)).SingleOrDefault();
                }
    
                if (student != null)
                {
                    student.FirstName = dto.FirstName;
                    student.LastName = dto.LastName;
                    student.EnrollmentDate = dto.EnrollmentDate;
                } 
    
                using (var dbcontext = new CUDataEntities())
                {
                    if (student != null)
                    {
                        dbcontext.Entry(student).State = EntityState.Modified;
                        dbcontext.SaveChanges();
                    }
                }
            }
        }
    }
    
    Saturday, December 30, 2017 6:22 AM
  • User475983607 posted

    @mgebhard

    The pattern  is understood. 

    My question is specifically around the example I sent, if you check it, the Dispose method doesn't release any un-managed-resources because it is injected (repository)  and then its the responsibility of the injector to release them. In my case it will be the DI container.

    However I believe the call for JUST GC.SuppressFinalize() is just to tell the CLR simply don't send this object for the Finalizer queue? But is this something truly needed in objects that doesn't own the un-managed resource?. Again my question is not about the Dispose pattern.

    It looks like a stub where you can place code to dispose managed resources if needed. The ICustomerAppService explicitly implements IDisposable therefore so must the CustomerAppService. 

    Could you please explain or refer to something on that? And which pattern is recommended then?

    The DBContext is a repository and Unit of Work pattern.  https://docs.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/advanced-entity-framework-scenarios-for-an-mvc-web-application

    Repository and unit of work patterns

    Many developers write code to implement the repository and unit of work patterns as a wrapper around code that works with the Entity Framework. These patterns are intended to create an abstraction layer between the data access layer and the business logic layer of an application. Implementing these patterns can help insulate your application from changes in the data store and can facilitate automated unit testing or test-driven development (TDD). However, writing additional code to implement these patterns is not always the best choice for applications that use EF, for several reasons:

    • The EF context class itself insulates your code from data-store-specific code.
    • The EF context class can act as a unit-of-work class for database updates that you do using EF.
    • Features introduced in Entity Framework 6 make it easier to implement TDD without writing repository code.

    Saturday, December 30, 2017 2:43 PM
  • User753101303 posted

    Hi,

    Hummm... As basically posted by DA924 it won't have any effect anyway (and I doubt the author expects to have subclasses with finalizers) so for now I see no real reason for doing this call.

    My guess is that the author implemented Dispose to allow the use of the "using" statement and felt safer with this "SuppressFinalize" call. My personal preference would have been an empty implementation with a comment telling the purpose is to allow the use of "using".

    Please don't flame me if it doesn't help ;-)

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, December 30, 2017 4:28 PM