Search code examples
c#model-view-controllerinversion-of-controlfluentvalidationlight-inject

FluentValidation in Lightinject


I'm using fluentvalidation and lightinject

Here is my code to insert a blog article;

public OperationResultDto Add(BlogArticleDto blogArticleDto) { OperationResultDto result = new OperationResultDto();

    ValidationResult validationResult = 
        _blogArticleModelValidator.Validate(blogArticleDto);

    if (!validationResult.IsValid)
    {
        result.IsOk = false;

        ValidationFailure firstValidationFailer = 
            validationResult.Errors.FirstOrDefault();

        if (firstValidationFailer != null)
        {
            result.Message = firstValidationFailer.ErrorMessage;
        }

        return result;
    }

    BlogArticle blogArticle = new BlogArticle {
        Title = blogArticleDto.Title,
        ShortBody = blogArticleDto.ShortBody,
        Body = blogArticleDto.Body,
        IsOnline = blogArticleDto.IsOnline,
        CategoryName = blogArticleDto.CategoryName,
        PublishedBy = blogArticleDto.PublishedBy,
        PublishDate = blogArticleDto.PublishDate,
        Tags = new List<string>(), //TODO parse, model's tags in one string.
        CreateDate = DateTime.Now,
        MainPhotoPath = blogArticleDto.MainPhotoPath,
    };

    _blogArticleRepository.Add(blogArticle);

    return result;
}

As you can see, "validation section" is huge and I don't want to validate my dto parameters in my service(business) layer. I want to validate "arguments" in my ioc (lightinject).

Here is my ioc code to proceed that;

public class ServiceInterceptor : IInterceptor
{
    public object Invoke(IInvocationInfo invocationInfo)
    {
        Log.Instance.Debug("Class: ServiceInterceptor -> Method: Invoke started.");

        string reflectedTypeFullname = String.Empty;
        string methodName = String.Empty;

        if (invocationInfo.Arguments.Any())
        {
            //TODO Validate method parameters here..

            foreach (object argument in invocationInfo.Arguments)
            {
            }
        }

        if (invocationInfo.Method.ReflectedType != null)
        {
            reflectedTypeFullname = invocationInfo.Method.ReflectedType.FullName;
            methodName = invocationInfo.Method.Name;
        }

        ... ...

Now, I can take all arguments of a method to give them to my fluentvalidator. So I know I need to define typeOf argument here but after that how can I call fluent validation's related validation object* to validate argument ?


Solution

  • I am the author of LightInject and maybe you could see if this example works out for you.

    class Program
    {
        static void Main(string[] args)
        {
            var container = new ServiceContainer();
            container.Register<AbstractValidator<Foo>, FooValidator>();    
            container.Register<IFooService, FooService>();
            container.Intercept(sr => sr.ServiceType.Name.EndsWith("Service"), factory => new ServiceInterceptior(factory));
            var service = container.GetInstance<IFooService>();
            service.Add(new Foo());
        }
    }
    
    public interface IFooService
    {
        void Add(Foo foo);
    }
    
    public class FooService : IFooService
    {
        public void Add(Foo foo)
        {
        }
    }
    
    public class Foo
    {
    }
    
    public class FooValidator : AbstractValidator<Foo>
    {
    }
    
    public class ServiceInterceptior : IInterceptor
    {
        private readonly IServiceFactory factory;
    
        public ServiceInterceptior(IServiceFactory factory)
        {
            this.factory = factory;
        }
    
        public object Invoke(IInvocationInfo invocationInfo)
        {
            foreach (var argument in invocationInfo.Arguments)
            {
                Type argumentType = argument.GetType();
                Type validatorType = typeof (AbstractValidator<>).MakeGenericType(argumentType);
                var validator = factory.TryGetInstance(validatorType);
                if (validator != null)
                {
                    var validateMethod = validatorType.GetMethod("Validate", new Type[] { argumentType });
                    var result = (ValidationResult)validateMethod.Invoke(validator, new object[] { argument });
                    if (!result.IsValid)
                    {
                        //Throw an exception, log or any other action
                    }
                }                
            }
    
            //if ok, proceed to the actual service.
            return invocationInfo.Proceed();
        }
    }