Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] exception not catched into the modal component #270

Closed
adrienbarde opened this issue Dec 15, 2020 · 6 comments
Closed

[Bug] exception not catched into the modal component #270

adrienbarde opened this issue Dec 15, 2020 · 6 comments
Labels
Bug Something isn't working Resolved: Won't Fix The reported behaviour will not be changed.

Comments

@adrienbarde
Copy link

adrienbarde commented Dec 15, 2020

Describe the bug

I use a ilogger global exception handler and I call services from my component which is in my modal.
when a service throws an exception I can't catch it from my global handler.

it works fine all the application except for the exceptions of the services called by my component in the modal

Is there a way to catch the exception that thrown inside the modal? Is it a different thread? A cascading problem?

** Code **

My Ilogger

    public interface IUnhandledExceptionSender
    {
        event EventHandler<Exception> UnhandledExceptionThrown;
    }

    public class UnhandledExceptionSender : ILogger, IUnhandledExceptionSender
    {

        public event EventHandler<Exception> UnhandledExceptionThrown;

        public IDisposable BeginScope<TState>(TState state)
        {
            return null;
        }

        public bool IsEnabled(LogLevel logLevel)
        {
            return true;
        }

        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state,
            Exception exception, Func<TState, Exception, string> formatter)
        {
            if (exception != null)
            {
                UnhandledExceptionThrown?.Invoke(this, exception);
            }
        }
    }

    public class UnhandledExceptionProvider : ILoggerProvider
    {
        UnhandledExceptionSender _unhandledExceptionSender;
        private ITechnicalLogger _technicalLogger;
        private IToastService _toastService;

        public UnhandledExceptionProvider(UnhandledExceptionSender unhandledExceptionSender, ITechnicalLogger technicalLogger, IToastService toastService)
        {
            _unhandledExceptionSender = unhandledExceptionSender;
            _technicalLogger = technicalLogger;
            _toastService = toastService;
        }

        public ILogger CreateLogger(string categoryName)
        {
            return new UnhandledExceptionLogger(categoryName, _unhandledExceptionSender, _technicalLogger, _toastService);
        }

        public void Dispose()
        {
        }

        public class UnhandledExceptionLogger : ILogger
        {
            private readonly string _categoryName;
            private readonly UnhandledExceptionSender _unhandeledExceptionSender;
            private ITechnicalLogger _technicalLogger;
            private IToastService _toastService;

            public UnhandledExceptionLogger(string categoryName, UnhandledExceptionSender unhandledExceptionSender, ITechnicalLogger technicalLogger, IToastService toastService)
            {
                _unhandeledExceptionSender = unhandledExceptionSender;
                _categoryName = categoryName;
                _technicalLogger = technicalLogger;
                _toastService = toastService;
            }

            public bool IsEnabled(LogLevel logLevel)
            {
                return true;
            }

            public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
            {
                if (exception != null)
                {
                   //All exceptions catched here except from my modal component
                    _technicalLogger.Error("Error occurred", exception);
                }
            }

            public IDisposable BeginScope<TState>(TState state)
            {
                return new NoopDisposable();
            }

            private class NoopDisposable : IDisposable
            {
                public void Dispose()
                {
                }
            }
}

Program init

var unhandledExceptionSender = new UnhandledExceptionSender();
            var unhandledExceptionProvider = new UnhandledExceptionProvider(unhandledExceptionSender, technicalLogger, null);
            builder.Logging.AddProvider(unhandledExceptionProvider);
            builder.Services.AddSingleton<IUnhandledExceptionSender>(unhandledExceptionSender);

App.razor

<CascadingBlazoredModal>
    <Router AppAssembly="typeof(Program).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)" />
        </Found>
        <NotFound>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
</CascadingBlazoredModal>

Method to open the modal

public async Task Edit(int id)
        {
            var parameters = new ModalParameters();
            parameters.Add(nameof(AgencyEdit.AgencyId), id);
            var editModal = Modal.Show<AgencyEdit>("Edit", parameters, new ModalOptions
            {
                Animation = ModalAnimation.FadeIn(1)
            });

            var result = await editModal.Result;
            if (!result.Cancelled)
            {
                await RefreshList();
            }
        }

My Edit component into the modal

public partial class AgencyEdit : ComponentBase
{
        [Inject]
        private IAgencyService _agencyService { get; set; }

        [Inject]
        private IToastService _toastService { get; set; }

        [CascadingParameter] BlazoredModalInstance BlazoredModal { get; set; }

        [Parameter]
        public int AgencyId { get; set; }

        public AgencyViewModel Agency { get; set; }

        protected override async Task OnInitializedAsync()
        {
            await base.OnInitializedAsync();
            Agency = new AgencyViewModel();
        }

        protected override async Task OnParametersSetAsync()
        {
            if (AgencyId > 0)
            {
                Agency = await _agencyService.GetAgency(AgencyId);
            }
        }

        public async void HandleValidSubmit()
        {
              // This method throws an exception !
                await _agencyService.AddAgency(Agency))
        }
}
@adrienbarde adrienbarde added Bug Something isn't working Triage Issue needs to be triaged labels Dec 15, 2020
@chrissainty
Copy link
Member

I can't think of how the modal is blocking you getting exceptions in your handler. We don't have any try.. catch blocks in our code which could swallow the exception and threads are not an issue as there is only one thread in the browser.

I've not done any work with logging in Blazor so I'm not familiar with the patterns or any pitfalls/shortcomings. This is something I will be looking into but I'm afraid I don't have the capacity to do it right now.

@larsk2009 do you have any ideas on this one?

@larsk2009
Copy link
Collaborator

Not really. I don't have much experience with this either. I guess the easiest way to see the issue is if we have an actual project which shows this issue. Then we can debug that project and probably find what is going on?

@adrienbarde
Copy link
Author

adrienbarde commented Dec 15, 2020

Not really. I don't have much experience with this either. I guess the easiest way to see the issue is if we have an actual project which shows this issue. Then we can debug that project and probably find what is going on?

Thank you, here an example of my project => https://github.com/adrienbarde/UnhandledExceptionWithBlazoredModal

where the exception must be caught
Line 72 File => Common\UnhandledExceptionSender.cs

Into this file, there are two examples
=> \Services\AgencyService.cs
1- method "DeleteAgency" is called directly from the page
2- method "UpdateAgency" is called from the modal component

both throw exceptions

the exception coming from "DeleteAgency" is caught
the exception coming from "UpdateAgency" is NOT caught

** how to test **
1- Add a break point Line 72 File => Common\UnhandledExceptionSender.cs
2- launch the project
3- click on Agency menu link
4- click on a "Delete" button to try "DeleteAgency" method
5- Click on "Details" button then click on on "Save" to try the "UpdateAgency"

@larsk2009
Copy link
Collaborator

Hi @adrienbarde

I can reproduce your issue with that project. I don't immediately see the issue, but have you had a look at this. It seems logging/exception handling/catching in Blazor is not very mature yet, so maybe something is just going wrong there?

@adrienbarde
Copy link
Author

Hi @adrienbarde

I can reproduce your issue with that project. I don't immediately see the issue, but have you had a look at this. It seems logging/exception handling/catching in Blazor is not very mature yet, so maybe something is just going wrong there?

ok thank your help, i will migrate to 5.0.0-preview2, it seems to be resolve my issue

@larsk2009 larsk2009 added Resolved: Closed The issue has been closed due to inactivity or that the request is not something we will work on Resolved: Won't Fix The reported behaviour will not be changed. and removed Triage Issue needs to be triaged Resolved: Closed The issue has been closed due to inactivity or that the request is not something we will work on labels Dec 19, 2020
@larsk2009
Copy link
Collaborator

It seems like this has been solved, so I will close this issue. If it isn't fixed yet, let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something isn't working Resolved: Won't Fix The reported behaviour will not be changed.
Projects
None yet
Development

No branches or pull requests

3 participants