none
Override of HandleException WCF Data Services doesn't work RRS feed

  • Question

  • I have included an overriden HandleException code as detailed in Julie Lerman's article at http://msdn.microsoft.com/en-us/magazine/hh580732.aspx, but when I set a breakpoint on the first line of the HandleException method, the code does not break.
    I then only get the "An error occurred while processing this request" error message at the client.
    No detailed information is provided. I have the annotation [ServiceBehavior(IncludeExceptionDetailInFaults = true)] and
    I have included config.UseVerboseErrors - true;. What could be preventing the override of the HandleException method from running?

    I have also downloaded the sample app for the cited article and the downloaded code does not work properly because the Microsoft.Data.Service.Client 4.0 assembly is missing. 
    If the 5.0 assembly is used, the HandleException override does not work.
    This is the same problem in my application with the latest release of WCF Data Services. 
    Is there a work around?


    Al G.

    Tuesday, February 26, 2013 1:58 PM

Answers

  • I resolved the version 5.3 issue by referencing version 5.1 so I was able to continue debugging the original issue.  I was able to break at a breakpoint within the data service HandleException routine by changing to multiple startup projects and including the project that hosts the data service as a startup project.  This resolved the original issue for this posting, but when I broke into the HandleException routine, I found that the exception type being handled for a "Validation Failed" inner exception is a System.InvalidOperationException when I expected a typeof(DbEntityValidationException).  Sould I begin a new post for this issue?  I will mark this reply as the answer for the original issue.

    Al G.

    • Marked as answer by RentAPlace Saturday, March 2, 2013 6:59 PM
    Saturday, March 2, 2013 6:59 PM
  • As a follow-up, once I was able to break into the HandleException routine I dicovered the following about validation errors in WCF Data Services V3:

    1. The primary exception generated by validation errors is an InvalidOperationException.
    2. The inner exception is a System.Data.Entity.Infrastructure.DbEntityValidattionException.
    3. The message of the primary exception lists all validation errors.

    By using something like the following, you can pass the error information to the client:

                // Handle validation exceptions.
                if (args.Exception is InvalidOperationException
                    && args.Exception.InnerException != null)
                {
                    if (args.Exception.InnerException is System.Data.Entity.Infrastructure.DbEntityValidationException)
                    {
                        var errorMessage = args.Exception.Message;
                        args.Exception = new DataServiceException(500, errorMessage.ToString());
                        return;
                    }
                }


    Al G.

    Tuesday, March 5, 2013 2:09 PM

All replies

  • It would be helpful if we can get the full stack of the issue. Can you perhaps monitor the request using Fiddler to see how the server is responding to your client request. Can you copy and paste that information into here? Also include the type of request you are making on the client as well.

    Thanks,

    Chris Robinson - WCF Data Services


    This posting is provided "AS IS" with no warranties, and confers no rights.

    Tuesday, February 26, 2013 11:23 PM
    Moderator
  • here is the TextView info from Fiddler2:

    <?xml version="1.0" encoding="utf-8"?><m:error xmlns:m="<m:code">http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><m:code /><m:message xml:lang="en-US">This is a test message</m:message><m:innererror><m:message>Exception has been thrown by the target of an invocation.</m:message><m:type>System.Reflection.TargetInvocationException</m:type><m:stacktrace>   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)&#xD;
       at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)&#xD;
       at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)&#xD;
       at System.Data.Services.Providers.BaseServiceProvider.InvokeServiceOperation(ServiceOperation serviceOperation, Object[] parameters)</m:stacktrace><m:internalexception><m:message>This is a test message</m:message><m:type>System.Data.Services.DataServiceException</m:type><m:stacktrace>   at RAP.Data.EntityFramework.Host.RapDataService.ChkAvailabilityOk(Int32 propertyId, String arrivalDate, String departureDate) in c:\Development\Rent A Place v0.1\Data\RAP.Data.EntityFramework.Host\RapDataService.svc.cs:line 49</m:stacktrace></m:internalexception></m:innererror></m:error>

    This was generated by calling the following service operation in which I have thrown a data service exception:

            [WebGet]
            public Boolean ChkAvailabilityOk
                (
                Int32 propertyId
                ,
                string arrivalDate,
                string departureDate
                )
            {
                throw new DataServiceException(400, "This is a test message");
            }

     The code for the override:

            // Override to manage returned exceptions.
            protected override void HandleException(HandleExceptionArgs args)
            {
                // Handle validation exceptions.
                if (args.Exception.GetType() == typeof(DbEntityValidationException))
                {
                    var ex = args.Exception as DbEntityValidationException;
                    var errors = ex.EntityValidationErrors.First().ValidationErrors.ToList();
                    var errorMessage = new StringBuilder();
                    foreach (var e in errors)
                    {
                        errorMessage.AppendLine(e.ErrorMessage);
                    }
                    args.Exception = new DataServiceException(500, errorMessage.ToString());
                    return;
                }

                // Handle exceptions raised in service operations.
                if (args.Exception is TargetInvocationException 
                    && args.Exception.InnerException != null)
                {
                    if (args.Exception.InnerException is DataServiceException)
                    {
                        // Unpack the DataServiceException.
                        args.Exception = args.Exception.InnerException;
                    }
                    else
                    {
                        // Return a new DataServiceException as "400: bad request."
                        args.Exception =
                            new DataServiceException(400,
                                args.Exception.InnerException.Message);
                    }
                }
            }


    Al G.

    Wednesday, February 27, 2013 8:58 PM
  • Hey Al,

    I'm guessing you were following the advise from here

    http://blogs.msdn.com/b/writingdata_services/archive/2011/03/06/interesting-behavior-for-service-operation-exceptions.aspx

    Which version of WCF Data Services are you using? Is it the latest, 5.3? Or an earlier version? I just wanted to know which version so I can investigate this further.

    Thanks,

    Chris Robinson - WCF Data Services


    This posting is provided "AS IS" with no warranties, and confers no rights.

    Friday, March 1, 2013 6:31 PM
    Moderator
  • I am using version 5.1.  I will try to get version 5.3.

    Al G.

    Friday, March 1, 2013 7:04 PM
  • I am using .Net Framework 4.5.  Could this be the problem?  I didn't see it mentioned for WCF Data Services 5.3.

    Al G.

    Friday, March 1, 2013 7:18 PM
  • Ok, what I'm trying to figure is if we made a change and inadvertently changed this behavior. Whatever behavior there is for 5.1, likely that is the behavior on 5.2 or 5.3. I will try this behavior out on 5.0 or 4.0 to see what it does there.

    .net 4.5 shouldn't have any affect on this.

    Thanks,

    Chris


    This posting is provided "AS IS" with no warranties, and confers no rights.


    Friday, March 1, 2013 10:13 PM
    Moderator
  • I've validated the behavior you want works as expected in WCF Data Services 5.0 and 5.3 so I think things work.

    There was a small issue with your code snippet above. If you are returning a single value you need to add the additional attribute[SingleResult] on the method as well. The other thing that I did was for simplicity for a repro I removed the parameters so I can just call the method from the browsers without providing parameters.

    I did the same procedure in 5.3, and I did this on a .net 4.5 box as well. I added one parameter with an incorrect parameter and with one and it still worked. I did this with a Reflection based provider. Are you building on top of EF?

    Below is the code that I used to test this.

    public class WcfDataService1 : DataService<WebApplication1.WcfDataService1.Context>
        {
            // This method is called only once to initialize service-wide policies.
            public static void InitializeService(DataServiceConfiguration config)
            {
                // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
                // Examples:
                config.SetEntitySetAccessRule("*", EntitySetRights.All);
                config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
                config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
            }

            [WebGet]
            [SingleResult]
            public Boolean ChkAvailabilityOk(int param1)
            {
                 throw new DataServiceException(400, "This is a test message");
            }
           
            // Override to manage returned exceptions.
            protected override void HandleException(HandleExceptionArgs args)
            {
                // Handle exceptions raised in service operations.
                if (args.Exception is TargetInvocationException 
                    && args.Exception.InnerException != null)
                {
                    if (args.Exception.InnerException is DataServiceException)
                    {
                        // Unpack the DataServiceException.
                        args.Exception = args.Exception.InnerException;
                    }
                    else
                    {
                        // Return a new DataServiceException as "400: bad request."
                        args.Exception =
                            new DataServiceException(400,
                                args.Exception.InnerException.Message);
                    }
                }
            }

            public class Context
            {
                public IQueryable<Customer> Customers
                {
                    get
                    {
                        return new Customer[]{}.AsQueryable();
                    }
                }
            }

            public class Customer
            {
                public int ID {get; set;}
            }
        }

    Perhaps you can identify how ours were different.

    Thanks,

    Chris Robinson - WCF Data Services.


    This posting is provided "AS IS" with no warranties, and confers no rights.


    Friday, March 1, 2013 11:25 PM
    Moderator
  • I have another problem that has occurred because I tried to update to version 5.3 using NuGet. I can build the solution using the 5.3 dll's and I can update the service reference for the console application that I use for testing the data service, but when I run the app it fails with a "manifest definition does not match the assembly reference" error. After I do this, if I try to update the service reference, I get the same  "does not match the assembly reference" error.  After I rebuild, I can update the service reference, but running the app causes the errors again.  I can't test util I ge this resolved.

    Al G.

    • Marked as answer by RentAPlace Saturday, March 2, 2013 6:50 PM
    • Unmarked as answer by RentAPlace Saturday, March 2, 2013 6:50 PM
    Saturday, March 2, 2013 12:39 AM
  • I resolved the version 5.3 issue by referencing version 5.1 so I was able to continue debugging the original issue.  I was able to break at a breakpoint within the data service HandleException routine by changing to multiple startup projects and including the project that hosts the data service as a startup project.  This resolved the original issue for this posting, but when I broke into the HandleException routine, I found that the exception type being handled for a "Validation Failed" inner exception is a System.InvalidOperationException when I expected a typeof(DbEntityValidationException).  Sould I begin a new post for this issue?  I will mark this reply as the answer for the original issue.

    Al G.

    • Marked as answer by RentAPlace Saturday, March 2, 2013 6:59 PM
    Saturday, March 2, 2013 6:59 PM
  • As a follow-up, once I was able to break into the HandleException routine I dicovered the following about validation errors in WCF Data Services V3:

    1. The primary exception generated by validation errors is an InvalidOperationException.
    2. The inner exception is a System.Data.Entity.Infrastructure.DbEntityValidattionException.
    3. The message of the primary exception lists all validation errors.

    By using something like the following, you can pass the error information to the client:

                // Handle validation exceptions.
                if (args.Exception is InvalidOperationException
                    && args.Exception.InnerException != null)
                {
                    if (args.Exception.InnerException is System.Data.Entity.Infrastructure.DbEntityValidationException)
                    {
                        var errorMessage = args.Exception.Message;
                        args.Exception = new DataServiceException(500, errorMessage.ToString());
                        return;
                    }
                }


    Al G.

    Tuesday, March 5, 2013 2:09 PM