First of all thanks a lot for all your effort on this matter: we really appreciate it.
Your last checkin really helps a lot.
The decision / remedy cannot be based on a specific DTO: should work for any serialization exception. In order to accomplish this I made those changes
// my service serviceException handler
private object serviceExceptionHandler(IRequest httpReq, object request, Exception exception)
{
IHasResponseStatus dto = null;
var errorResponseDto = DtoUtils.CreateErrorResponse(request, exception);
var httpError = errorResponseDto as IHttpError;
if (httpError != null)
{
dto = httpError.Response as IHasResponseStatus;
if (dto != null)
{
// no worries about next call: I use it to customize my response DTO.ResponseStatus property
FillResponseStatus(dto);
}
}
// Deserialization error after the service completed successfully
if (httpReq.Response.Dto != null && dto != null)
{
return dto.ResponseStatus;
}
return errorResponseDto;
}
// ServiceStackHost.Runtime.cs -> WriteSoapMessage
// MyAppHostBase
public override void WriteSoapMessage(IRequest req, System.ServiceModel.Channels.Message message, Stream outputStream)
{
try
{
using (var writer = XmlWriter.Create(outputStream, Config.XmlWriterSettings))
{
message.WriteMessage(writer);
}
}
catch (Exception ex)
{
// my serviceException handler does not return, in this scenario, the response DTO related to the incoming request
// but a generic DTO such as ResponseStatus
var response = OnServiceException(req, req.Dto, ex);
if (response == null || !outputStream.CanSeek)
return;
outputStream.Position = 0;
try
{
//message = SoapHandler.CreateResponseMessage(response, message.Version, req.Dto.GetType(),
message = SoapHandler.CreateResponseMessage(response, message.Version, response.GetType(),
req.GetSoapMessage().Headers.Action == null);
using (var writer = XmlWriter.Create(outputStream, Config.XmlWriterSettings))
{
message.WriteMessage(writer);
}
}
catch (Exception exc)
{
Console.WriteLine(exc);
}
}
finally
{
//HostContext.CompleteRequest(req);
OnEndRequest(req);
// Did you test your code with a IIS hosted scenario?
// If I do not add following check/flush, self-hosted scenario(self hosted test) works with no problem
// but under IIS response is empty...
if (req is AspNetRequest)
{
req.Response.Flush();
}
}
}
In order to be generic, I use buffered stream for any soap request
// MyAppHostBase
public override void Configure(Container container)
{
...
GlobalRequestFilters.Add((req, res, dto) =>
{
// https://github.com/ServiceStack/ServiceStack/commit/d412dc9840e8c667b921818be5ba4ca00791c336
if (req.ContentType != null && req.ContentType.ToLower().Contains("soap"))
{
req.Response.UseBufferedStream = true;
}
});
}