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

How to propagate exceptions after a lock is in place? #38

Open
rliberoff opened this issue Mar 6, 2019 · 9 comments
Open

How to propagate exceptions after a lock is in place? #38

rliberoff opened this issue Mar 6, 2019 · 9 comments

Comments

@rliberoff
Copy link

Hi,

We are facing an issue in our project, when We need to throw and exception during a PutAsync action that is called just after the LockAsync action. However, even when the exception is bubbled up and it is a type not handled by the WebDavExceptionFilter, the consumer or client of the WebDav server does not receives the exception. By the way, the UnlockAsync action is always called, regardless the exception we are throwing.

On the other hand, if the exception is throw during the PutAsync action but before the LockAsync, then the consumer receives the exception.

Can you please tell us how could we propagate the the caller or consumer an exception type thrown from an action just after the lock?

Thank you very much in advance.

Regards,

Rodrigo

@fubar-coder
Copy link
Collaborator

fubar-coder commented Mar 7, 2019

Sorry, I'm not really sure what you mean. There are either exceptions handled by ASP.NET Core itself and those handled by the custom IExceptionFilter implementation (WebDavExceptionFilter), which handles the following exceptions:

  • NotImplementedException resulting in a HTTP 501 response
  • NotSupportedException resulting in a HTTP 501 response
  • WebDavException resulting in either:
    • HTTP 304 response
    • WebDAV status code + multistatus response
  • UnauthorizedAccessException resulting in a WebDAV status code + multistatus response

I suggest that you implement your own IExceptionFilter to handle all other kinds of exceptions by returning a multistatus response and the correct HTTP status code.

EDIT: Clarification

@rliberoff
Copy link
Author

Hi,

It's OK.

The issue we are facing is that we are throwing an exception in the PutAsync action that is called just after the LockAsync action; but this exception is not catch by the application that interacts with the WebDav, it assumes that the action happened correctly. However, Windows shows us a dialog that looks like this:

image

Any idea of how could we circunvent the windows dialog and catch the exception on the consumer application of the WebDav?

Thank you.

Kind regards,

Rodrigo

@fubar-coder
Copy link
Collaborator

What kind of exception do you get?

@rliberoff
Copy link
Author

Hi,

That's the point. The consumer application of the WebDav is not catching any exception; it continues as if the WebDav has successfully added/copied the file it is sending, however the dialog I copied in my previous message appears due to the exception that is being thrown from the PutAsync.

We throw this exception on purpose, and We would like to have it being capture by the consumer application of the WebDav, but so far it has not been possible, and the only thing that tells us that it actually happen (beyond knowing its existence because we code it) is that dialog from the operative system.

The exception type We're throwing on purpose from the PutAsync is a System.IO.IOException.

Thank you.

Kind regards,

Rodrigo

@fubar-coder
Copy link
Collaborator

Aha, so it's an IOException, that was the missing piece. Then I suggest that you implement and register your own IExceptionFilter and return the correct HTTP status code and the corresponding multistatus response.

@rliberoff
Copy link
Author

We tried that, and it didn't work.

Our suspicion is that the operative system (Windows) is swallowing the exception and showing the dialog form a previous comment, and that is why the consumer application is not catching it.

But it is a suspicion, and would like another opinion, specially from the creator of the library and your experience with the WebDav protocol.

@rliberoff
Copy link
Author

Hi,

Do you have an example on how to wrap an exception within a multistatus (HTTP 207) response to get a message more or less like this one? -->

<?xml version="1.0"?>
<a:multistatus
  xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/"
  xmlns:a="DAV:">
 <a:response>
   <a:href>http://server/public/test2/item1.txt</a:href>
   <a:propstat>
    <a:status>HTTP/1.1 500 Server Error</a:status>
       <a:prop>
        <a:getcontenttype>text/plain</a:getcontenttype>
        <a:getcontentlength b:dt="int">33</a:getcontentlength>
       </a:prop>
   </a:propstat>
 </a:response>
</a:multistatus>

Thank you.

Kind regards,

Rodrigo

@rliberoff
Copy link
Author

Hi again,

Well, I think We found the way to create the multistatus but it didn't work either.

This is our custom IExceptionFilter:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using FubarDev.WebDavServer;
using FubarDev.WebDavServer.AspNetCore;
using FubarDev.WebDavServer.Model;

using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

using Microsoft.Extensions.DependencyInjection;

namespace TestWebDav
{
    public class TestWebDavExceptionFilter : IExceptionFilter
    {
        public void OnException(ExceptionContext context)
        {
            if (context.ExceptionHandled)
            {
                return;
            }

            if (context.Exception is WebDavException webDavException)
            {
                return;
            }

            context.Result = BuildResultForStatusCode(context, WebDavStatusCode.BadGateway, context.Exception.Message);
        }

        private static IActionResult BuildResultForStatusCode(ExceptionContext context, WebDavStatusCode statusCode, string message)
        {
            var result = new WebDavResult<multistatus>(
                statusCode,
                new multistatus()
                {
                    response = new[]
                    {
                        new response()
                        {
                            href = context.HttpContext.Request.GetEncodedUrl(),
                            ItemsElementName = new[] { ItemsChoiceType2.status, },
                            Items = new object[] { new Status(context.HttpContext.Request.Protocol, statusCode, message).ToString() },
                        },
                    },
                });

            var dispatcher = context.HttpContext.RequestServices.GetService<IWebDavDispatcher>();

            return new WebDavIndirectResult(dispatcher, result, null);
        }
    }
}

This works as expected, however Windows still shows us the same dialog.

In any case, thanks for the help.

Kind regards,

Rodrigo

fubar-coder added a commit that referenced this issue Nov 22, 2021
Ensures that - in the sample server - all exceptions are returned as multi-status responses.

Incorporates the changes from #38. Maybe we need to return the error element too?
@fubar-coder
Copy link
Collaborator

The changes you made are also available in the release/2.0 branch, but I used an ExceptionFilterAttribute instead of the IExceptionFilter.

I'll leave this ticket open, because maybe we need to return the error element too, together with an element that's a Microsoft WebDAV extension?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants