ServiceStack marker Attribute not found in Collection

Viewed 45

I have a custom attribute and I want to check via a GlobalFilter, if the methods I'm calling has this marker attribute. I can't find a way, to get the information that the called method where my request aims to has the Attribute. I've found already another post, which recommends to use FilterAttributeCache.GetRequestFilterAttributes(request.GetType()) but this and also other methods are retuning just no elements.

Could you please help me in what I'm missing here?

Following the example code:

CustomAttribute:

using ServiceStack;
using ServiceStack.Web;

namespace MyProject.Web
{
    public class CustomAttribute : RequestFilterAttribute
    {
        public string ServiceName;
        public string ServiceClass;
        public string ServiceMethod;

        public JwtAuthAttribute(string serviceName, string serviceClass, string serviceMethod)
        {
            ServiceName = serviceName;
            ServiceClass = serviceClass;
            ServiceMethod = serviceMethod;
        }

        public override void Execute(IRequest req, IResponse res, object requestDto)
        {
            //Nothing in here
        }
    }
}

Filter:

using System;
using System.Linq;
using ServiceStack.Support.WebHost;
using ServiceStack.Web;

namespace MyProject.Web
{
    public class CustomFilter
    {
        private readonly ICustomManager _customManager;

        public CustomFilter(ICustomManager customManager)
        {
            _customManager= customManager;
        }

        public void Execute(IRequest request)
        {
            var customHeader = request.Headers.GetValues("CustomHeader");

            if (customHeader == null)
            {
                return;
            }

            var customAttribute = FilterAttributeCache.GetRequestFilterAttributes(request.GetType())
                .OfType<CustomAttribute>().FirstOrDefault();

            if (customAttribute == null)
            {
                return;
            }

            // Do other things here
        }
    }
}

Registration of GlobalFilter in Global.asax:

public override void Configure(Container container)
{
    //other configurations
    
    GlobalRequestFilters.Add((req, res, dto) => req.ResponseContentType = MimeTypes.Json);
    GlobalRequestFilters.Add((req, res, dto) =>
    {
        var customFilter = new CustomFilter(request.TryResolve<ICustomManager>());
        customFilter.Execute(req);
    });
}

Method with marker CustomAttribute:

namespace MyProject.Web
{
    [Authenticate]
    [RequiredRole("CustomUser")]
    public class CustomService : Service
    {
        [Custom("Service", "ServiceClass", "ServiceMethod")]
        public object Get(CustomRequest request)
        {
            //Additional code
        }   
    }
}
2 Answers

I'd recommend adding attributes on the Request DTO which is much easier to access since the Request DTO is available everywhere throughout ServiceStack request pipeline, e.g. dto.GetType() in global filters or IRequest.Dto.GetType() everywhere else.

To access ServiceStack actions, you'd need to access the service Type then its actions, e.g:

GlobalRequestFilters.Add((req, res, dto) =>
{
    var serviceType = HostContext.AppHost.Metadata.GetServiceTypeByRequest(dto.GetType());
    var action = serviceType.GetActions().First(x => x.RequestType == dto.GetType());
    var attrs = action.AllAttributes<CustomAttribute>();
});

After the answer from mythz I was able to fix the issue. I've extented the "Execute" method of "CustomFilter" by requestDto, which was provided by the GobalRequestFilter registration.

Unfortunately I was not able to access the Property "RequestType", maybe because I'm using an older version (ServiceStack 5.9.2, .Net Framework 4.7.2), so I had to go over the MethodParameters.

Here is the final code, which gave me the access to the "CustomAttribute"

var serviceTypeDto = HostContext.AppHost.Metadata.GetServiceTypeByRequest(requestDto.GetType());
var methodInfo = serviceTypeDto.GetDeclaredMethods().FirstOrDefault(x =>
                x.GetParameters().FirstOrDefault(y => y.ParameterType == requestDto.GetType()) != null && x.IsPublic);

var customAttribute = methodInfo.AllAttributes<CustomAttribute>().FirstOrDefault();
Related