locked
ASP.Net EntityFramework SaveChanges central RRS feed

  • Question

  • Hey

    I have a question relating to ASP.NET (MVC) and EntityFramework

    This is my first ASP.NET application I am writing, in the past I wrote for WinForms. - There I always had a central "Shared" class, which I called, when there was data to save.

    Now, in ASP.NET, I read, that Shared shouldn't be used, because you never can say, who is calling it. (Makes sense for me)

    But, has anybody of you a way, to manage the Try/Catch, Error handling and logging in a central class with ASP.NET?

    I don't want to write each time, when I save data:

    Using myBaseDataContext As New Base.BaseDataContext
                    
                    myDataContext.Database.Log = AddressOf myLogging.LogDatabase
                    Try
                         myDataContext.SaveChanges()
                    Catch ex as Exception
                         myLogging.LogException(ex)
                         ' Give back the error to the user
                    End Catch
    
    End Using

    This would be redundant Code, and we all know, that we shouldn't do that .... ;)

    THX a lot

    Friday, April 8, 2016 3:23 PM

Answers

  • In an WinForms program I can create a "Shared" class, which can be reached from everywhere in the Code. And there I check, if an error occurs, I log the changes and so on.

    I suggest that you understand an Abstract base class that's like in the C# example of a MVC controller that inherits from the BaseController. It's the BaseController that has the single try/catch and logging using Log4net.

    In your case, you would have a BasePage that all Webpages inherit from the BasePage that inherits from WebPage.  

    Of course, you could use the same approach in Windows forms based solution too.

    The MVC controller like a ASP.NET UI Web form or even a Window UI form is the highest point in the solution. So, you have a single try/catch in the base class and exceptions thrown below the base class bubble up to the base class where they are caught. You don't need try/catches all of over the place, just the single try/catch at the highest point and let the exception bubble up to the base class and log the exception.

    namespace CEEPRebatePortal.Controllers
    {
        public abstract class BaseWebController : Controller
        {
            #region "Dependencies"
    
            public ILogger Logger { get; set; }
    
            #endregion
    
            /// <summary>
            /// Handle errors by showing error page and redirecting to Error page
            /// </summary>
            /// <param name="filterContext"></param>
            protected override void OnException(ExceptionContext filterContext)
            {
                // see if we need to find the "Real Exception"
                Exception actualException = filterContext.Exception;
                while ( ((actualException is HttpException) || (actualException is HttpUnhandledException)) &&
                          (actualException.InnerException != null) ) 
                {
                    actualException = actualException.InnerException;
                }
    
                if (Logger != null)
                {
                    // Logger should always be non-null, but don't risk it
                    Logger.Error(string.Format(
                        "Exception on request \"{0}\" with referrer \"{1}\"", Request.Url, Request.UrlReferrer),
                        actualException);
    
                    // For database validation exceptions, report details
                    if (actualException is DbEntityValidationException)
                    {
                        foreach (var err in
                            ((DbEntityValidationException)actualException).EntityValidationErrors.SelectMany(errs => errs.ValidationErrors))
                        {
                            Logger.Error(string.Format("Validation failed on property {0}: {1}", err.PropertyName, err.ErrorMessage));
                        }
                    }
                }
    
                // base exception handler will redirect us to Error page, depending on CustomErrors setting in web.config
                base.OnException(filterContext);
            }
        }
    }

    namespace CEEPRebatePortal.Controllers
    {
        [Authorize(Roles="Submitter")]
        public class RebateWizardController : BaseWebController
        {
            #region "Dependencies"
            public IRequestsDalMgr requestsDalMgr { get; set; }
            #endregion
    
            private const string ADDMODELSESSIONKEY = "addmodel";
    
            private const string ERRORMESSAGE = "Please fix the following errors:";
    
            [HttpGet]
            public ActionResult Index()

    • Marked as answer by Zero-G. _ Saturday, April 9, 2016 1:23 PM
    Saturday, April 9, 2016 10:53 AM

All replies

  • Hello,

    Have you considered asking your question in the ASP.NET Forums.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    • Proposed as answer by Cor Ligthert Friday, April 8, 2016 5:45 PM
    Friday, April 8, 2016 5:35 PM
  • I don't see what is wrong with your approach, the error is logged on the server, exactly where it should be. 

    However, the knowledge about ASP.Net has declined in this forum, therefore it is better to follow the advice of Karen.


    Success
    Cor

    Friday, April 8, 2016 5:45 PM
  • But, has anybody of you a way, to manage the Try/Catch, Error handling and logging in a central class with ASP.NET?

    No one would do what you are doing in an ASP.NET solution. They would use a logging tool like Log4net. If the DB goes down, then what are you going to do?

    http://www.codeproject.com/Articles/42276/How-to-Use-Log-Net-with-VB-NET-A-Simple-Step-By-St

    Friday, April 8, 2016 9:20 PM
  • Override the SaveChanges method of the generated context with your own partial class and then you can execute your logging logic from within the context, regardless of where or when the context is used.

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Friday, April 8, 2016 10:03 PM
  • Hey

    First of all, thanks for your Reply

    Second, I will ask my question in ASP.NET again

    Third. I think there was a missunderstanding of my question

    I asked about central saving. The logging was just to clarify, that there will be a big amount of Code, which is redundant everytime a "SaveChanges" is called.

    @DA924x -> I use a professional logging tool and there it will be done, like in the Code I have posted.

    But this doesn't matter at all.

    Again, I try to clarify:

    In an WinForms program I can create a "Shared" class, which can be reached from everywhere in the Code. And there I check, if an error occurs, I log the changes and so on.

    The question was, how to solve something like this in an ASP.NET application.

    THX

    Saturday, April 9, 2016 9:22 AM
  • In an WinForms program I can create a "Shared" class, which can be reached from everywhere in the Code. And there I check, if an error occurs, I log the changes and so on.

    I suggest that you understand an Abstract base class that's like in the C# example of a MVC controller that inherits from the BaseController. It's the BaseController that has the single try/catch and logging using Log4net.

    In your case, you would have a BasePage that all Webpages inherit from the BasePage that inherits from WebPage.  

    Of course, you could use the same approach in Windows forms based solution too.

    The MVC controller like a ASP.NET UI Web form or even a Window UI form is the highest point in the solution. So, you have a single try/catch in the base class and exceptions thrown below the base class bubble up to the base class where they are caught. You don't need try/catches all of over the place, just the single try/catch at the highest point and let the exception bubble up to the base class and log the exception.

    namespace CEEPRebatePortal.Controllers
    {
        public abstract class BaseWebController : Controller
        {
            #region "Dependencies"
    
            public ILogger Logger { get; set; }
    
            #endregion
    
            /// <summary>
            /// Handle errors by showing error page and redirecting to Error page
            /// </summary>
            /// <param name="filterContext"></param>
            protected override void OnException(ExceptionContext filterContext)
            {
                // see if we need to find the "Real Exception"
                Exception actualException = filterContext.Exception;
                while ( ((actualException is HttpException) || (actualException is HttpUnhandledException)) &&
                          (actualException.InnerException != null) ) 
                {
                    actualException = actualException.InnerException;
                }
    
                if (Logger != null)
                {
                    // Logger should always be non-null, but don't risk it
                    Logger.Error(string.Format(
                        "Exception on request \"{0}\" with referrer \"{1}\"", Request.Url, Request.UrlReferrer),
                        actualException);
    
                    // For database validation exceptions, report details
                    if (actualException is DbEntityValidationException)
                    {
                        foreach (var err in
                            ((DbEntityValidationException)actualException).EntityValidationErrors.SelectMany(errs => errs.ValidationErrors))
                        {
                            Logger.Error(string.Format("Validation failed on property {0}: {1}", err.PropertyName, err.ErrorMessage));
                        }
                    }
                }
    
                // base exception handler will redirect us to Error page, depending on CustomErrors setting in web.config
                base.OnException(filterContext);
            }
        }
    }

    namespace CEEPRebatePortal.Controllers
    {
        [Authorize(Roles="Submitter")]
        public class RebateWizardController : BaseWebController
        {
            #region "Dependencies"
            public IRequestsDalMgr requestsDalMgr { get; set; }
            #endregion
    
            private const string ADDMODELSESSIONKEY = "addmodel";
    
            private const string ERRORMESSAGE = "Please fix the following errors:";
    
            [HttpGet]
            public ActionResult Index()

    • Marked as answer by Zero-G. _ Saturday, April 9, 2016 1:23 PM
    Saturday, April 9, 2016 10:53 AM
  • Hey DA924x

    THX for this aproach.

    I will give it a try

    Saturday, April 9, 2016 1:23 PM