Response filters and CompressResponse attribute

All my services return the following DTO for GET verb

    public interface IAppResponse<T>
    {
        int Count { get; set; }
        T Content { get; set; }
    }

now I need to add a Guid to each response so I’ve changed the interface to

    public interface IAppResponse<T>
    {
        int Count { get; set; }
        string Guid { get; set; }
        T Content { get; set; }
    }

I’ve implemented a GlobalResponseFilter to value the Guid property and to add a custom cookie for each response.

I’ve discovered that GlobalResponseFilter is not called if [CompressResponse] attribute has been used.
I’ve a lots of GET methods decorated with [CompressResponse], how can I intercept this responses?

I’m using SS 5.9.2 and .net framework 4.8.

Thanks.

Note: there’s no Response DTO after the [CompressResponse] Response Filter attribute is executed, i.e. the compressed bytes are written directly to the Response Stream so you would need to access the Service Response before [CompressResponse] Response Filter attribute is executed which is listed in the Order of Operations.

This does show that Global Response Filters are executed before the [CompressResponse] Response Filter attribute which I’ve tested and confirmed does happen so it’s not clear why it’s not happening for you. You could try upgrading to a recent version of ServiceStack since v5.9.2 is a very old version.

Otherwise as per the Order or Operations docs you can implement the On AfterExecute method in your Service or implement a custom service runner or you could even use a Response Filter Attribute with a Priority < 0.

After some debugging I’ve discovered the culprit is in ServiceRunner.ExecuteAsync method which looks for ResponseFilters and execute them.

...
                if (ResponseFilters != null)
                {
                    foreach (var responseFilter in ResponseFilters)
                    {
                        var attrInstance = responseFilter.Copy();
                        container.AutoWire(attrInstance);

                        if (attrInstance is IHasResponseFilter filter)
                            filter.ResponseFilter(req, res, response);
                        else if (attrInstance is IHasResponseFilterAsync filterAsync)
                            await filterAsync.ResponseFilterAsync(req, res, response);

                        AppHost.Release(attrInstance);

                        if (res.IsClosed)
                            return null;
                    }

if res.IsClosed the method returns without execute of ServiceStackHost.ApplyResponseFiltersAsync

I cannot figure out why CompressResponse attribute is in the ResponseFilters collection, it’s priority is 0 not below 0. And I don’t know why res.IsClosed is true

It could be a problem of SS 5.9.2?
Or I’m using the CompressResponse attribute in a wrong way?

This is how I use CompressResponse attribute

    [ServiceStack.Authenticate]
    public class DGruppiTestiCodificatiService : AppDizionariService
    {
        private readonly IDGruppoTestiCodificati _gruppoTestiCodificati;

        public DGruppiTestiCodificatiService(IDGruppoTestiCodificati gruppoTestiCodificati)
        {
            _gruppoTestiCodificati = gruppoTestiCodificati;
        }

        [CompressResponse]
        public async Task<DizionarioGruppiTestiCodificatiResponse> Get(DizionarioGruppiTestiCodificatiGetAll request)
        {
            (var content, int count) = await _gruppoTestiCodificati.GetAllPagedAsync(request.First, request.Rows, request.SortField, request.SortOrder);
            return new DizionarioGruppiTestiCodificatiResponse(count, content);
        }

AppDizionariService is this a base custom class for all my services which inherits from SS Service class

public abstract class AppDizionariService : Service

Action Attributes (attributes added to methods) gets executed first so you wouldn’t be able to intercept the response. You should move the [CompressResponse] Attribute so it’s on the Service or Request DTO class instead.

Great, as always!

now it works

very thanks

1 Like