public class MyClass : IMyClass {
internal MyClass() {
}
}
container.Resolve<IMyClass>();
How to configure DryIoc to use the constructor of MyClass in case when it is internal, protected or even private?
Specify constructor info via Made.Of:
c.Register<Something>(made:
Made.Of(typeof(Something).GetConstructorOrNull(includeNonPublic: true, args: argTypes));
Update:
Here is the custom implementation of constructor selector.
Couple of notes:
Does not support Func<..>, but support can be easily added by copying from the FactoryMethod.ConstructorWithResolvableArguments implementation
Will be supported by DryIoc when issue 313 is resolved
using System;
using System.Linq;
using System.Reflection;
using NUnit.Framework;
namespace DryIoc.IssuesTests
{
[TestFixture]
public class SO_question_How_use_implementation_with_private_constructor_in_DryIoc
{
public class A { internal A() { } }
public class B { internal B(A a) { } }
[Test]
public void Test()
{
var c = new Container();
c.RegisterMany(new[] {typeof(A), typeof(B)},
made: Made.Of(SelectMostResolvableConstructor(includeNonPublic: true)));
c.Resolve<B>();
}
private FactoryMethodSelector SelectMostResolvableConstructor(bool includeNonPublic = false)
{
return request =>
{
var implementationType = request.ImplementationType.ThrowIfNull();
var ctors = implementationType.GetAllConstructors(includeNonPublic: true).ToArrayOrSelf();
if (ctors.Length == 0)
return null; // Delegate handling of constructor absence to the Caller code.
if (ctors.Length == 1)
return FactoryMethod.Of(ctors[0]);
var ctorsWithMoreParamsFirst = ctors
.Select(c => new {Ctor = c, Params = c.GetParameters()})
.OrderByDescending(x => x.Params.Length);
var rules = request.Container.Rules;
var parameterSelector = rules.Parameters.And(request.Made.Parameters)(request);
var matchedCtor = ctorsWithMoreParamsFirst.FirstOrDefault(x =>
x.Params.All(p => IsResolvableParameter(p, parameterSelector, request)));
var ctor = matchedCtor.ThrowIfNull(Error.UnableToFindCtorWithAllResolvableArgs, request).Ctor;
return FactoryMethod.Of(ctor);
};
}
private static bool IsResolvableParameter(ParameterInfo parameter,
Func<ParameterInfo, ParameterServiceInfo> parameterSelector, Request request)
{
var parameterServiceInfo = parameterSelector(parameter) ?? ParameterServiceInfo.Of(parameter);
var parameterRequest = request.Push(parameterServiceInfo.WithDetails(ServiceDetails.IfUnresolvedReturnDefault, request));
if (parameterServiceInfo.Details.HasCustomValue)
{
var customValue = parameterServiceInfo.Details.CustomValue;
return customValue == null
|| customValue.GetType().IsAssignableTo(parameterRequest.ServiceType);
}
var parameterFactory = request.Container.ResolveFactory(parameterRequest);
return parameterFactory != null && parameterFactory.GetExpressionOrDefault(parameterRequest) != null;
}
}
}
Related
I have a property on a class which is implemented by an interface. Now I want to get all attributes from a specific type declared on that property and their interface Pendants.
In order to regard multi implementation with implicit and explicit members I wrote an test-class (with xUnit).
[DebuggerDisplay("{Tooltip}")]
[AttributeUsage(AttributeTargets.Property)]
public class TooltipAttribute : Attribute
{
public TooltipAttribute(string tooltip)
{
Tooltip = tooltip;
}
public string Tooltip { get; set; }
}
public interface IAmGood
{
[Tooltip("GOOD: I am a very generic description.")]
int Length { get; }
}
public interface IAmBad
{
[Tooltip("BAD: This description is not wanted to be shown.")]
int Length { get; }
}
public class DemoClassImplicit : IAmGood, IAmBad
{
[Tooltip("GOOD: Implicit")]
public int Length => throw new NotImplementedException();
[Tooltip("BAD: Explicit")]
int IAmBad.Length => throw new NotImplementedException();
}
public class DemoClassExplicit : IAmGood, IAmBad
{
[Tooltip("GOOD: Explicit")]
int IAmGood.Length => throw new NotImplementedException();
[Tooltip("BAD: Implicit")]
public int Length => throw new NotImplementedException();
}
public class DemoClassImplicitForBoth : IAmGood, IAmBad
{
[Tooltip("I am GOOD and BAD")]
public int Length => throw new NotImplementedException();
}
public class TestClass
{
[Fact]
public void GetTooltipFromImplicit()
{
var demoClassImplicit = new DemoClassImplicit();
var propertyInfo = demoClassImplicit.GetType().GetRuntimeProperty("Length");
var tooltips = GetTooltipAttribute<TooltipAttribute>(propertyInfo);
Assert.Equal(2, tooltips.Count());
Assert.All(tooltips, o => Assert.Contains("GOOD", o.Tooltip));
}
[Fact]
public void GetTooltipFromExplicit()
{
var demoClassImplicit = new DemoClassExplicit();
var propertyInfo = demoClassImplicit.GetType().GetRuntimeProperties().First(o => o.Name.EndsWith(".Length"));
var tooltips = GetTooltipAttribute<TooltipAttribute>(propertyInfo);
Assert.Equal(2, tooltips.Count());
Assert.All(tooltips, o => Assert.Contains("GOOD", o.Tooltip));
}
[Fact]
public void GetTooltipFromImplicitForBoth()
{
var demoClassImplicit = new DemoClassImplicitForBoth();
var propertyInfo = demoClassImplicit.GetType().GetRuntimeProperty("Length");
var tooltips = GetTooltipAttribute<TooltipAttribute>(propertyInfo);
Assert.Equal(3, tooltips.Count());
}
/// <summary>
/// The core method.
/// </summary>
public IEnumerable<T_Attribute> GetTooltipAttribute<T_Attribute>(PropertyInfo propInfo)
where T_Attribute : Attribute
{
var result = new List<T_Attribute>(propInfo.GetCustomAttributes<T_Attribute>());
var declaringType = propInfo.DeclaringType;
// The get method is required for comparing without use the prop name.
var getMethodFromGivenProp = propInfo.GetGetMethod(true);
// Check for each interface if the given property is declared there
// (it is not a naming check!).
foreach (var interfaceType in declaringType.GetInterfaces())
{
var map = declaringType.GetInterfaceMap(interfaceType);
// Check if the current interface has an member for given props get method.
// Attend that compare by naming would be cause an invalid result here!
var targetMethod = map.TargetMethods.FirstOrDefault(o => o.Equals(getMethodFromGivenProp));
if (targetMethod != null)
{
// Get the equivalent get method on interface side.
// ERROR: The error line!
var interfaceMethod = map.InterfaceMethods.FirstOrDefault(o => o.Name == targetMethod.Name);
if (interfaceMethod != null)
{
// The get method does not help to get the attribute so the property is required.
// In order to get the property we must look which one has the found get method.
var property = interfaceType.GetProperties().FirstOrDefault(o => o.GetGetMethod() == interfaceMethod);
if (property != null)
{
var attributes = property.GetCustomAttributes<T_Attribute>();
if (attributes != null)
{
result.AddRange(attributes);
}
}
}
}
}
return result;
}
}
The test method 'GetTooltipFromExplicit' fails because in the core method is a comparison by name. I marked the line above with // ERROR: The error line!.
I have no idea how to find the method-pendant inside of 'InterfaceMapping'-class.
The solution was to know that the order of the two collections in InterfaceMapping are mirrorred.
So replace the line below is the solution:
// ERROR: The error line!
var interfaceMethod = map.InterfaceMethods.FirstOrDefault(o => o.Name == targetMethod.Name);
// SOLUTION: The working line:
var interfaceMethod = map.InterfaceMethods[Array.IndexOf(map.TargetMethods, targetMethod)];
This detailed was explained on official member documentation (but not on the class itself). See:
https://learn.microsoft.com/en-us/dotnet/api/system.reflection.interfacemapping.interfacemethods?view=netcore-3.1#remarks
https://learn.microsoft.com/en-us/dotnet/api/system.reflection.interfacemapping.targetmethods?view=netcore-3.1#remarks
I've got a setup like this with a concrete class that is instantiated inside the method I want to test. I want to mock this concrete class an not have it execute the code inside. Hence, no exception should be thrown:
public class Executor
{
public bool ExecuteAction(ActionRequest request)
{
switch (request.ActionType)
{
case ActionType.Foo:
var a = new Foo();
return a.Execute(request);
case ActionType.Bar:
var b = new Bar();
return b.Execute(request);
}
return true;
}
}
public class Foo
{
public virtual bool Execute(ActionRequest request)
{
throw new NotImplementedException();
}
}
public class Bar
{
public virtual bool Execute(ActionRequest request)
{
throw new NotImplementedException();
}
}
My NUnit test looks like this:
[Test]
public void GivenARequestToFooShouldExecuteFoo()
{
var action = new Mock<Foo>();
action.Setup(x => x.Execute(It.IsAny<ActionRequest>())).Returns(true);
var sut = new Mock<Executor>();
sut.Object.ExecuteAction(new ActionRequest
{
ActionType = ActionType.Foo
});
}
[Test]
public void GivenARequestToBarShouldExecuteBar()
{
var action = new Mock<Bar>();
action.Setup(x => x.Execute(It.IsAny<ActionRequest>())).Returns(true);
var sut = new Mock<Executor>();
sut.Object.ExecuteAction(new ActionRequest
{
ActionType = ActionType.Bar
});
}
I fiddled around with CallBase, but it didn't get me anywhere. Is there anyway I can solve this easily without dependency injection of these classes and adding interfaces? Is this possible just using Moq?
The only thing I can think to do currently is move the Execute methods into the Executor class and rename them to ExecuteFoo() and ExecuteBar(), but I have a lot of code to move so they'd have to be partial classes (sub classes?).
The problem is not with the mocking of the method but with the creation of the concrete class. The creation of Foo and Bar need to be inverted out of the Executor. It is responsible for executing the action, not creating it. with that this interface was created to handle the creation.
public interface IActionCollection : IDictionary<ActionType, Func<IExecute>> {
}
think of this as a collection of factories or a collection of creation strategies.
A common interface was created for the actions.
public interface IExecute {
bool Execute(ActionRequest request);
}
public class Foo : IExecute {
public virtual bool Execute(ActionRequest request) {
throw new NotImplementedException();
}
}
public class Bar : IExecute {
public virtual bool Execute(ActionRequest request) {
throw new NotImplementedException();
}
}
And the Executor was refactored to use dependency inversion.
public class Executor {
readonly IActionCollection factories;
public Executor(IActionCollection factories) {
this.factories = factories;
}
public bool ExecuteAction(ActionRequest request) {
if (factories.ContainsKey(request.ActionType)) {
var action = factories[request.ActionType]();
return action.Execute(request);
}
return false;
}
}
With that refactor done the Executor can be tested with fake actions.
public void GivenARequestToFooShouldExecuteFoo() {
//Arrange
var expected = true;
var key = ActionType.Foo;
var action = new Mock<Foo>();
action.Setup(x => x.Execute(It.IsAny<ActionRequest>())).Returns(expected);
var actions = new Mock<IActionCollection>();
actions.Setup(_ => _[key]).Returns(() => { return () => action.Object; });
actions.Setup(_ => _.ContainsKey(key)).Returns(true);
var sut = new Executor(actions.Object);
var request = new ActionRequest {
ActionType = ActionType.Foo
};
//Act
var actual = sut.ExecuteAction(request);
//Assert
Assert.AreEqual(expected, actual);
}
A production implementation of the factory collection can look like this
public class ActionCollection : Dictionary<ActionType, Func<IExecute>>, IActionCollection {
public ActionCollection()
: base() {
}
}
and configured accordingly with your concrete types.
var factories = ActionCollection();
factories[ActionType.Foo] = () => new Foo();
factories[ActionType.Bar] = () => new Bar();
I'm using AutoFixture and I'd like to use a specific constructor.
I have the following code and I like to select the constructor with ITemplateParameterHandler.
public sealed class TemplateSegmentHandler : ITemplateSegmentHandler
{
public TemplateSegmentHandler(ITemplateIterator iterator)
: this(new TemplateParameterHandler(iterator))
{
Contract.Requires(iterator != null);
}
public TemplateSegmentHandler(ITemplateParameterHandler parameterHandler)
{
Contract.Requires(parameterHandler != null);
_parameterHandler = parameterHandler;
_parameterHandler.Ending += EndingParameter;
}
// ...
}
EDIT:
I want to inject the following fake implementation. (I'm using NSubstitute to create the fake object.)
public sealed class CustomTemplateParameter : ICustomization
{
private readonly ITemplateParameterHandler _context;
public CustomTemplateParameter()
{
_context = Substitute.For<ITemplateParameterHandler>();
}
public void Customize(IFixture fixture)
{
fixture.Customize<ITemplateParameterHandler>(c => c.FromFactory(() => _context));
}
public CustomTemplateParameter SetCatchAll(bool isCatchAll)
{
_context.IsCatchAll.Returns(isCatchAll);
return this;
}
}
Here is the way I'm trying to use it.
[Fact]
public void Should_return_true_when_the_segment_has_a_catch_all_parameter()
{
TemplateSegmentHandler segmentHandler = new Fixture().Customize(new TemplateSegmentHandlerFixture())
.Customize(new CustomTemplateParameterHandler()
.SetCatchAll(true))
.Create<TemplateSegmentHandler>();
segmentHandler.Parameter.Start();
segmentHandler.Parameter.End();
segmentHandler.HasCatchAll.Should().BeTrue();
}
But it still selects the wrong constructor and I'm getting the following error.
Ploeh.AutoFixture.ObjectCreationExceptionAutoFixture was unable to create an instance from Somia.Web.Routing.Template.ITemplateIterator, most likely because it has no public constructor, is an abstract or non-public type.
Request path:
Somia.Web.Routing.Template.TemplateSegmentHandler -->
Somia.Web.Routing.Template.ITemplateIterator iterator -->
Somia.Web.Routing.Template.ITemplateIterator
I ended up implementing IMethodQuery and select the ctor I wanted.
public sealed class SelectedFirstConstructorQuery : IMethodQuery
{
private readonly Type _type;
public SelectedFirstConstructorQuery(Type type)
{
_type = type;
}
public IEnumerable<IMethod> SelectMethods(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
return from ci in type.GetConstructors()
let parameter = ci.GetParameters().First()
where parameter.ParameterType == _type
select new ConstructorMethod(ci) as IMethod;
}
}
Usage:
fixture.Customize<TemplateSegmentHandler>(c => c.FromFactory(new MethodInvoker(new SelectedFirstConstructorQuery(typeof(ITemplateParameterHandler)))));
One possible way:
var parameterHandler = fixture.Create<ITemplateParameterHandler>();
var segmentHandler = fixture.Build<TemplateSegmentHandler>()
.FromFactory(() => new TemplateSegmentHandler(parameterHandler));
fixture.Inject(segmentHandler);
I'm working on a code base which has the purpose to format code. In some instances, I have to remove syntax tokens such as the keyword "params" inside the parameter list if I found one and it's redundant or remove some unneeded braces ( "{" "}").
The thing is, it's so hard and uneasy to remove syntax token from the syntax tree. I have tried many different solutions that you can find below, but for the life of me, I cannot succeed. I'd like a solution that could work for any syntax token U might encounter and that I need to possibly remove from the syntax tree.
In the following case, I have built an analyzer that is currently functionnal but the code fix provider is not quite working... (It's a case of redundant params keyword usage).
//UPDATE - I have provided full code of Analyzer/Code fix provider / NUnit tests
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Formatting;
namespace RefactoringEssentials.CSharp.Diagnostics
{
[ExportCodeFixProvider(LanguageNames.CSharp), System.Composition.Shared]
public class RedundantParamsCodeFixProvider : CodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds
{
get
{
return ImmutableArray.Create(CSharpDiagnosticIDs.RedundantParamsAnalyzerID);
}
}
public override FixAllProvider GetFixAllProvider()
{
return WellKnownFixAllProviders.BatchFixer;
}
public async override Task RegisterCodeFixesAsync(CodeFixContext context)
{
var document = context.Document;
var cancellationToken = context.CancellationToken;
var span = context.Span;
var diagnostics = context.Diagnostics;
var root = await document.GetSyntaxRootAsync(cancellationToken);
var diagnostic = diagnostics.First();
var node = root.FindNode(context.Span) as ParameterSyntax;
if (node == null)
return;
if (!node.Modifiers.Any(x => x.IsKind(SyntaxKind.ParamsKeyword)))
return;
var oldParameterNode = node;
var paramList = node.Parent as ParameterListSyntax;
if (paramList == null)
return;
//var newRoot = root.ReplaceNode(
// oldParameterNode.Parent as ParameterListSyntax,
// paramList.WithParameters
// (SyntaxFactory.SeparatedList(paramList.Parameters.ToArray()))
// .WithLeadingTrivia(node.GetLeadingTrivia())
// .WithTrailingTrivia(node.GetTrailingTrivia()))
// .WithAdditionalAnnotations(Formatter.Annotation);
//var paramsKeyword = (node.Modifiers.FirstOrDefault(x => x.IsKind(SyntaxKind.ParamsKeyword)));
//var indexParams = node.Modifiers.IndexOf(paramsKeyword);
//var syntaxListWithoutParams = node.Modifiers.RemoveAt(indexParams);
//node.ReplaceToken(paramsKeyword, syntaxListWithoutParams.AsEnumerable());
context.RegisterCodeFix(CodeActionFactory.Create(node.Span, diagnostic.Severity, "Remove 'params' modifier", token =>
{
var newNode = SyntaxFactory.Parameter(node.AttributeLists,node.Modifiers.Remove(SyntaxFactory.Token(SyntaxKind.ParamsKeyword)),node.Type,node.Identifier,node.Default);
var newRoot = root.ReplaceNode(node, newNode);
return Task.FromResult(document.WithSyntaxRoot(newRoot));
}), diagnostic);
//context.RegisterCodeFix(CodeActionFactory.Create(node.SKCpan, diagnostic.Severity, , document.WithSyntaxRoot(newRoot)), diagnostic);
}
}
}
This is the use cases in my situation.
using System;
using NUnit.Framework;
using RefactoringEssentials.CSharp.Diagnostics;
namespace RefactoringEssentials.Tests.CSharp.Diagnostics
{
[TestFixture]
public class RedundantParamsTests : CSharpDiagnosticTestBase
{
[Test]
public void TestBasicCase()
{
Analyze<RedundantParamsAnalyzer>(#"class FooBar
{
public virtual void Foo(string fmt, object[] args)
{
}
}
class FooBar2 : FooBar
{
public override void Foo(string fmt, $params object[] args$)
{
System.Console.WriteLine(fmt, args);
}
}", #"class FooBar
{
public virtual void Foo(string fmt, object[] args)
{
}
}
class FooBar2 : FooBar
{
public override void Foo(string fmt, object[] args)
{
System.Console.WriteLine(fmt, args);
}
}");
}
[Test]
public void TestValidCase()
{
Analyze<RedundantParamsAnalyzer>(#"class FooBar
{
public virtual void Foo(string fmt, object[] args)
{
}
}
class FooBar2 : FooBar
{
public override void Foo(string fmt, object[] args)
{
System.Console.WriteLine(fmt, args);
}
}");
}
[Test]
public void ValideParamsUsageTests()
{
Analyze<RedundantParamsAnalyzer>(#"class FooBar
{
public virtual void Foo(string fmt, params object[] args)
{
}
}
class FooBar2 : FooBar
{
public override void Foo(string fmt, params object[] args)
{
System.Console.WriteLine(fmt, args);
}
}");
}
[Test]
public void TestDisable()
{
Analyze<RedundantParamsAnalyzer>(#"class FooBar
{
public virtual void Foo(string fmt, object[] args)
{
}
}
class FooBar2 : FooBar
{
// ReSharper disable once RedundantParams
public override void Foo(string fmt, params object[] args)
{
System.Console.WriteLine(fmt, args);
}
}");
}
}
}
For those who might be interested in how I determine that the params is redundant, here's the logic:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using System.Collections.Immutable;
using System.Linq;
namespace RefactoringEssentials.CSharp.Diagnostics
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class RedundantParamsAnalyzer : DiagnosticAnalyzer
{
private static readonly DiagnosticDescriptor descriptor = new DiagnosticDescriptor(
CSharpDiagnosticIDs.RedundantParamsAnalyzerID,
GettextCatalog.GetString("'params' is ignored on overrides"),
GettextCatalog.GetString("'params' is always ignored in overrides"),
DiagnosticAnalyzerCategories.RedundanciesInDeclarations,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
helpLinkUri: HelpLink.CreateFor(CSharpDiagnosticIDs.RedundantParamsAnalyzerID),
customTags: DiagnosticCustomTags.Unnecessary
);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(descriptor);
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(
(nodeContext) =>
{
Diagnostic diagnostic;
if (TryGetParamsDiagnostic(nodeContext, out diagnostic))
{
nodeContext.ReportDiagnostic(diagnostic);
}
},
SyntaxKind.ParameterList
);
}
//I think it's a better decision to head in this direction instead of MethodDeclaration.
private static bool TryGetParamsDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic)
{
diagnostic = default(Diagnostic);
if (nodeContext.IsFromGeneratedCode())
return false;
var paramList = nodeContext.Node as ParameterListSyntax;
var declaration = paramList?.Parent as MethodDeclarationSyntax;
if (declaration == null)
return false;
if (declaration.Modifiers.Count == 0 || !declaration.Modifiers.Any(SyntaxKind.OverrideKeyword))
return false;
var lastParam = declaration.ParameterList.Parameters.LastOrDefault();
SyntaxToken? paramsModifierToken = null;
if (lastParam == null)
return false;
foreach (var x in lastParam.Modifiers)
{
if (x.IsKind(SyntaxKind.ParamsKeyword))
{
paramsModifierToken = x;
break;
}
}
if (!paramsModifierToken.HasValue ||
!paramsModifierToken.Value.IsKind(SyntaxKind.ParamsKeyword))
return false;
diagnostic = Diagnostic.Create(descriptor, lastParam.GetLocation());
return true;
}
}
In this case, you don't want to remove the whole node, rather you just want to remove the params modifier. Since SyntaxNodes are immutable, you need to create a new node with the appropriate modifiers using the WithModifiers method:
public async override Task RegisterCodeFixesAsync(CodeFixContext context)
{
var diagnostic = context.Diagnostics.First();
context.RegisterCodeFix(CodeAction.Create("Remove 'params' modifier", async token =>
{
var document = context.Document;
var root = await document.GetSyntaxRootAsync(token);
var fullParameterNode = root.FindNode(diagnostic.Location.SourceSpan, false) as ParameterSyntax;
// Keep all modifiers except the params
var newModifiers = fullParameterNode.Modifiers.Where(m => !m.IsKind(SyntaxKind.ParamsKeyword));
var syntaxModifiers = SyntaxTokenList.Create(new SyntaxToken());
syntaxModifiers.AddRange(newModifiers);
var updatedParameterNode = fullParameterNode.WithModifiers(syntaxModifiers);
var newDoc = document.WithSyntaxRoot(root.ReplaceNode(fullParameterNode, updatedParameterNode));
return newDoc;
}, "KEY"), diagnostic);
}
As for a generic remove option for syntax, I don't know of one that is easy to use. The Node.ReplaceSyntax is a rather complicated method and I usually find it easier to work with the ReplaceNode or RemoveNode methods.
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 ?
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();
}
}