Access Servicstack.net session in validator

旧时模样 提交于 2019-12-01 08:09:06

I assume you are just using the ValidationFeature plugin, as most do. If that's the case, then I don't think it is possible. Ultimately the ValidationFeature is a plugin which uses a RequestFilter.

I wanted to do something similar before too, then realised it wasn't possible.

The RequestFilter is run before the ServiceRunner. See the order of operations guide here.

What this means to you is your populated request DTO reaches your service, and the validation feature's request filter will try validate your request, before it has even created the ServiceRunner.

The ServiceRunner is where an instance of your service class becomes active. It is your service class instance that will be injected with your UserSession object.

So effectively you can't do any validation that relies on the session at this point.

Overcomplicated ?:

It is possible to do validation in your service method, and you could create a custom object that would allow you pass the session along with the object you want to validate. (See next section). But I would ask yourself, are you overcomplicating your validation?

For a simple check of the request UserId matching the session's UserId, presumably you are doing this so the user can only make changes to their own records; Why not check in the service's action method and throw an Exception? I am guessing people shouldn't be changing this Id, so it's not so much a validation issue, but more a security exception. But like I say, maybe your scenario is different.

public class SomeService : Service
{
    public object Post(UserSettingsRequest request) // Match to your own request
    {
        if(request.UserId != Session.UserId)
            throw new Exception("Invalid UserId");
    }
}

Validation in the Service Action:

You should read up on using Fluent Validators. You can call the custom validator yourself in your service method.

// This class allows you to add pass in your session and your object
public class WithSession<T>
{
    public UserSession Session { get; set; }
    public T Object { get; set; }
}

public interface IUserAccessValidator
{
    bool ValidUser(UserSession session);
}

public class UserAccessValidator : IUserAccessValidator
{
    public bool ValidUser(UserSession session)
    {
        // Your validation logic here
        // session.UserId
        return true;
    }
}

public class UserSettingsValidator : AbstractValidator<WithSession<UserSettingsRequest>>
{
    public IUserAccessValidator UserAccessValidator { get; set; }

    public UserSettingsValidator()
    {
        // Notice check now uses .Object to access the object within
        RuleFor(x => x.Object.UserId)
            .SetValidator(new PositiveIntegerValidator());

        // Custom User Access Validator check, passing the session
        RuleFor(x => x.Session).Must(x => UserAccessValidator.ValidUser(x)); 
    }
}

Then to actually use the validator in your service:

public class SomeService : Service
{
    // Validator with be injected, you need to registered it in the IoC container.
    public IValidator<WithSession<UserSettingsRequest>> { get; set; }

    public object Post(UserSettingsRequest request) // Match to your own request
    {
        // Combine the request with the current session instance
        var requestWithSession = new WithSession<UserSettingsRequest> {
            Session = this.Session,
            Object = request
        };

        // Validate the request
        ValidationResult result = this.Validator.Validate(requestWithSession);
        if(!result.IsValid)
        {
            throw result.ToException();
        }

        // Request is valid
        // ... more logic here
        return result;
    }
}

I hope this helps. Note: code is untested

It appears that after reading from a bunch of people experiencing similar problems, then many hours of playing with several solutions based on the SS4 Cookbook etc, this is a problem that is already solved:

https://forums.servicestack.net/t/blaz-miheljak-355-feb-3-2015/176/2

Implement the IRequiresRequest interface on your validator, and voila.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!