Base solution for your next web application
Open Closed

How to register my own ExceptionToErrorInfoConverter ? #2007


User avatar
1
sergii created

Hi, I have this try/catch block in my app services

try
            {
                newEntity = _repository.Insert(newEntity);
                CurrentUnitOfWork.SaveChanges();
            }
            catch (DbEntityValidationException ex)
            {
                var validationErrors = ex.EntityValidationErrors?.SelectMany(e => e.ValidationErrors?.Select(v => new ValidationResult(v.ErrorMessage, new string[] { v.PropertyName }))).ToList();
                throw new AbpValidationException(FriendlyMessages.FormDataValidationFailed, validationErrors);
            }

I want to move above handler for DbEntityValidationException from App Services to some single base level and seems it can be done via implementing and registering IExceptionToErrorInfoConverter via IErrorInfoBuilder.AddExceptionConverter(IExceptionToErrorInfoConverter converter)

The question is where from I can get acces to IErrorInfoBuilder for app service ? Or maybe someone could advise another good approach to have above handler in one place and to be used by all app services by default


3 Answer(s)
  • User Avatar
    1
    hikalkan created
    Support Team

    I think a good place is to override SaveChanges and SaveChangesAsync in your dbcontext. Base base method in a try catch and do the same you are doing now.

    If you want to make it via IExceptionToErrorInfoConverter, then;

    1. create a class inherits from IExceptionToErrorInfoConverter
    2. In postinitialize of your module, use such a code:
    IocManager.Resolve<ErrorInfoBuilder>().AddExceptionConverter(new MyConverter())
    

    If you want to inject dependencies to MyConverter, you can register it to dependency injection (see <a class="postlink" href="http://www.aspnetboilerplate.com/Pages/Documents/Dependency-Injection#DocHelperInterfaces">http://www.aspnetboilerplate.com/Pages/ ... Interfaces</a>) then use the code like that:

    IocManager.Resolve<ErrorInfoBuilder>().AddExceptionConverter(IocManager.Resolve<MyConverter>())
    
  • User Avatar
    0
    sergii created

    I've decided to use SaveChanges approaches, works good, thank you.

  • User Avatar
    0
    sergii created

    Seems I found small issues with that approach and looks like it should be fixed in Abp core:

    public override int SaveChanges()
            {
                try
                {
                    return base.SaveChanges();
                }
                catch (DbEntityValidationException ex)
                {
                    this.Logger.Warn(FriendlyMessages.FormDataValidationFailed, ex);
                    var validationErrors = ex.EntityValidationErrors?.SelectMany(e => e.ValidationErrors?.Select(v => new ValidationResult(v.ErrorMessage, new string[] { v.PropertyName }))).ToList();
                    throw new AbpValidationException(FriendlyMessages.FormDataValidationFailed, validationErrors);
                }
            }
    

    Below exception rised by running seed with invalid data for entity. Ideally there should be AbpValidationException details but another SerializationException raised instead...

    System.Runtime.Serialization.SerializationException: Type is not resolved for member 'Abp.Runtime.Validation.AbpValidationException,Abp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
       at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
       at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
       at System.Data.Entity.Migrations.Design.ToolingFacade.Update(String targetMigration, Boolean force)
       at System.Data.Entity.Migrations.UpdateDatabaseCommand.<>c__DisplayClass2.<.ctor>b__0()
       at System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command)
    Type is not resolved for member 'Abp.Runtime.Validation.AbpValidationException,Abp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.