2

I have written custom ServiceRunner and overridden the HandleException method. As I can see, in case of an unhandled exception within a service the object returned by the HandleException method becomes the service response. I wish to return the same responseDTO type that the service returns in case of success. Is there any way I can access inside HandleException, the responseDTO type of the service which encountered the exception?

EDIT: As per received answer I implemented the services(which are in F#) with DTO/service types defined as follows :

type CS()=
    interface IReturn<Op<list<Y>,list<E>>>
    member val key = List<int>() with get,set

type CSService() = 
    interface IService
    member this.Get(request: CS)=
        //service code here returning Op<list<Y>,seq<E>> type

Hence the type I expect to receive in HandleException is Op<list<Y>,list<E>> (Y and E are known types which are defined in dlls available in bin folder)

As per suggestion I tried the following two options since WebRequestUtils was available in both namespaces:

Type test1 = ServiceStack.WebRequestUtils.GetErrorResponseDtoType(request.GetType());//error
        Type test2 = ServiceStack.ServiceClient.Web.WebRequestUtils.GetErrorResponseDtoType(request.GetType());

For test1 I receive following exception:

Could not load type 'ServiceStack.ErrorResponse' from assembly 'ServiceStack.Interfaces, Version=3.9.71.0, Culture=neutral, PublicKeyToken=null'.

Stack Trace:

at ServiceStack.WebRequestUtils.GetErrorResponseDtoType(Type requestType)
at M.ServiceStackWebAPP.MyCustomServiceRunner`1.HandleException(IRequestContext requestContext, TRequest request, Exception ex) in d:\Projects\ServiceStack\M.WebService\MyCustomServiceRunner.cs:line 167
at ServiceStack.ServiceHost.ServiceRunner`1.Execute(IRequestContext requestContext, Object instance, TRequest request)
at ServiceStack.ServiceHost.ServiceRunner`1.Process(IRequestContext requestContext, Object instance, Object request)
at ServiceStack.ServiceHost.NServiceExec`1.Execute(IRequestContext requestContext, Object instance, Object request, String requestName)
at ServiceStack.ServiceHost.NServiceRequestExec`2.Execute(IRequestContext requestContext, Object instance, Object request)
at ServiceStack.ServiceHost.ServiceController.<>c__DisplayClass15.<>c__DisplayClass17.<RegisterNServiceExecutor>b__14(IRequestContext reqCtx, Object req)
at ServiceStack.ServiceHost.ServiceController.ManagedServiceExec(ServiceExecFn serviceExec, Object service, IRequestContext requestContext, Object dto)
at ServiceStack.ServiceHost.ServiceController.<>c__DisplayClass15.<RegisterNServiceExecutor>b__13(IRequestContext requestContext, Object dto)
at ServiceStack.ServiceHost.ServiceController.Execute(Object request, IRequestContext requestContext)
at ServiceStack.WebHost.Endpoints.EndpointHost.ExecuteService(Object request, EndpointAttributes endpointAttributes, IHttpRequest httpReq, IHttpResponse httpRes)
at ServiceStack.WebHost.Endpoints.Support.EndpointHandlerBase.ExecuteService(Object request, EndpointAttributes endpointAttributes, IHttpRequest httpReq, IHttpResponse httpRes)
at ServiceStack.WebHost.Endpoints.RestHandler.GetResponse(IHttpRequest httpReq, IHttpResponse httpRes, Object request)
at ServiceStack.WebHost.Endpoints.RestHandler.ProcessRequest(IHttpRequest httpReq, IHttpResponse httpRes, String operationName)

Call for test2 is successful but I receive ErrorResponse type as return value instead of expected Op<list<Y>,list<E>>.

Am I still missing something?

ronilk
  • 303
  • 2
  • 4
  • 14

1 Answers1

1

As ServiceStack Services lets you return any Response Type it's ultimately impossible to know exactly what the Service would've returned if the Exception had not occurred as that would be dependent on the runtime Service implementation logic executed after the Exception is thrown, e.g:

public object Any(Request request)
{
    throw new Exception(); //No way of knowing what Service would've returned

    if (SomeCustomLogic(request))
        return new Response1();

    return new Response2();
}

Although if you follow ServiceStack's Recommendation of marking your Request DTOs with the return Type, e.g:

public class MyRequest : IReturn<MyResponse> { ... }

Or ServiceStack's convention of having the Response DTO named after the Request DTO with a Response suffix, e.g:

public class GetCustomers { ... } 
public class GetCustomersResponse { ... } 

Then you can use WebRequestUtils.GetErrorResponseDtoType(requestType) retrieve the Response Type from the Request DTO Type, e.g:

public override object HandleException(IRequest request, T requestDto, Exception ex)
{
    var responseType = WebRequestUtils.GetErrorResponseDtoType(requestDto.GetType());
}

If ServiceStack couldn't infer the Response Type (i.e. not using recommended conventions above) this will return the generic ErrorResponse Type.

Also note that you can use the more useful DtoUtils.CreateErrorResponse() to return a populated error Response DTO which will have the ResponseStatus property of the response DTO populated with the Exception, e.g:

public override object HandleException(IRequest request, T requestDto, Exception ex)
{
    var errorResponse = DtoUtils.CreateErrorResponse(requestDto, ex);
}
mythz
  • 141,670
  • 29
  • 246
  • 390
  • Thanks for the quick response. I am still unable to receive the responseDTO type. I have given additional information based on your answer. Please let me know if more information is required. – ronilk Oct 06 '16 at 08:16
  • @ronilk the errors you're getting is because you're using old v3 of ServiceStack with new packages. All ServiceStack packages must be of the same version which you can check by looking in your NuGet /packages folder. If you're question is on v3 of ServiceStack please tag your questions **servicestack-bsd** not **servicestack**. – mythz Oct 08 '16 at 16:41
  • I went through the GetErrorResponseDtoType method in WebRequestUtils.cs source code. For me the method returns ErrorResponse instead of Response type because hasResponseStatus variable becomes false. So wanted to ask here whether ResponseStatus is important in any scenario other than checking error details? If I am not consuming ResponseStatus anywhere then can I safely ignore this part and call the method GetTypeWithGenericTypeDefinitionOf directly? Calling GetTypeWithGenericTypeDefinitionOf directly inside HandleException does the work for me. – ronilk Oct 12 '16 at 13:31