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?
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);
}