Skip to content

Instantly share code, notes, and snippets.

@scottmcarthur
Last active January 4, 2016 02:39
Show Gist options
  • Save scottmcarthur/8557022 to your computer and use it in GitHub Desktop.
Save scottmcarthur/8557022 to your computer and use it in GitHub Desktop.
Deferred Validation Example. This example uses a custom validator plugin that is a substitute for the ServiceStack standard ValidationFeature plugin. When a custom attribute of `MyRoleAttribute` is applied to the request DTO, then the validation will not be run, allowing the MyRoleAttribute to run the validation checks once it has completed. Req…
using System;
using System.Linq;
using ServiceStack.ServiceInterface;
using ServiceStack.ServiceHost;
using ServiceStack.WebHost.Endpoints;
using ServiceStack.Common.Web;
using ServiceStack.Logging;
using ServiceStack.FluentValidation.Results;
using ServiceStack.Text;
using ServiceStack.ServiceInterface.Validation;
namespace Testv3
{
class MainClass
{
public static void Main()
{
// Very basic console host
var appHost = new AppHost();
appHost.Init();
appHost.Start("http://*:8082/");
Console.ReadKey();
}
}
public class AppHost : AppHostHttpListenerBase
{
public AppHost() : base("Test Service", typeof(TestApp).Assembly) {}
public override void Configure(Funq.Container container)
{
// Configure to use our custom Validation Feature (MyValidationFeature)
Plugins.Add(new MyValidationFeature());
}
}
public static class TestApp
{
#region DTOs
[Route("/HaveChristmas", "GET")]
[MyRole("Santa","Rudolph","MrsClaus")]
public class HaveChristmasRequest {}
[Route("/EasterEgg", "GET")]
[MyRole("Easterbunny")]
public class GetEasterEggRequest {}
[Route("/EinsteinsBirthday", "GET")]
public class EinsteinsBirthdayRequest {}
#endregion
#region Service
public class TestController : Service
{
// Roles: Santa, Rudolph, MrsClaus
public object Get(HaveChristmasRequest request)
{
return new { Presents = "Toy Car, Teddy Bear, Xbox" };
}
// Roles: Easterbunny
public object Get(GetEasterEggRequest request)
{
return new { EasterEgg = "Chocolate" };
}
// No roles required
public object Get(EinsteinsBirthdayRequest request)
{
return new { Birthdate = new DateTime(1879, 3, 14) };
}
}
#endregion
}
public class MyRoleAttribute : RequestFilterAttribute
{
readonly string[] _roles;
public MyRoleAttribute(params string[] roles)
{
_roles = roles;
}
#region implemented abstract members of RequestFilterAttribute
public override void Execute(IHttpRequest req, IHttpResponse res, object requestDto)
{
Console.WriteLine("Checking for required role");
// Replace with your actual role checking code
var role = req.GetParam("role");
if(role == null || !_roles.Contains(role))
throw HttpError.Unauthorized("You don't have the correct role");
Console.WriteLine("Has required role");
// Perform the deferred validation
Console.WriteLine("Running Validation");
ValidationFilters.RequestFilter(req, res, requestDto);
}
#endregion
}
public class MyValidationFeature : IPlugin
{
static readonly ILog Log = LogManager.GetLogger(typeof(MyValidationFeature));
public Func<ValidationResult, object, object> ErrorResponseFilter { get; set; }
public void Register(IAppHost appHost)
{
// Registers to use your custom validation filter instead of the standard one.
if(!appHost.RequestFilters.Contains(MyValidationFilters.RequestFilter))
appHost.RequestFilters.Add(MyValidationFilters.RequestFilter);
}
}
public static class MyValidationFilters
{
public static void RequestFilter(IHttpRequest req, IHttpResponse res, object requestDto)
{
// Determine if the Request DTO type has a MyRoleAttribute.
// If it does not, run the validation normally. Otherwise defer doing that, it will happen after MyRoleAttribute.
if(!requestDto.GetType().HasAttribute<MyRoleAttribute>()){
Console.WriteLine("Running Validation");
ValidationFilters.RequestFilter(req, res, requestDto);
return;
}
Console.WriteLine("Deferring Validation until Roles are checked");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment