StructureMap Conditional use - c#

I hawe all day strugle my head and i canot find any solution to my case so i nead help. Hear is my problem: I hawe two classes that implement one interface
public interface ICacheObject
{
string Get();
}
public class WebCacheObject : ICacheObject
{
public string Get()
{
return "Web";
}
}
public class SysteCacheObject : ICacheObject
{
public string Get()
{
return "System";
}
}
So in some other clase For Example in Class Test I nead to inject the WebCacheObject and in Test2 clase i nead to inject SystemCacheObject. I did this in Initialize:
ObjectFactory.Initialize(c =>{ c.For<IMessage>().Use<Message>();
c.For<ICacheObject>().ConditionallyUse(t =>{t.If(g => g.RequestedName == "HTTP")
.ThenIt.Is.ConstructedBy(
() =>
new WebCacheObject());
t.If(g =>g.RequestedName =="OtherCache")
.ThenIt.Is.ConstructedBy(
() =>
new SysteCacheObject
());
});
But I dont know how to Call Test-s clase-s so if I call so the condition is true (or how to change condition so this will work)
ObjectFactory.GetInstance<'ITest>()
the Test Clase will hawe WebCache in other case SystemCache???
Sorry for my bad English.

I think you should avoid the conditional construction syntax with if - if there is a simpler alternative. In your case I think that this will do:
For<ICacheStorage>().Use<NullObjectCache>();
For<Test>().Use<Test>.Ctor<ICacheStorage>().Is<HttpContextCacheAdapter>();
For<Test2>().Use<Test2>.Ctor<ICacheStorage>().Is<HttpContextCacheAdapter>();

Thanks i did find the solution if eny one of you neade hear is it (i did change some thing in condition and is working ):
x.For<ICacheStorage>().ConditionallyUse(c =>
{
c.If(t => t.ParentType == typeof(Test) ||
t.ParentType == typeof(Test2))
.ThenIt
.Is.ConstructedBy(
by => new HttpContextCacheAdapter());
c.TheDefault.Is.ConstructedBy(
by => new NullObjectCache());
});
Sorry for my bad English

Related

How can I customize the non-generic class names in generated Swagger files?

I faced with problem with swagger generation of generic type names.
For example I have the following code:
public class BulkRequest<T1, T2>
{
public IEnumerable<Operation<T1, T2>> Operations { get; set; }
}
[ProducesResponseType(typeof(BulkRequest<ClassA, ClassB>), StatusCodes.Status200OK)]
And after Swagger generates some ugly names like: ClassAClassBBulkRequest and ClassAClassBOperation.
I don't want to change BulkRequest class because it used in multiple places in our system.
So do we have any way to generate readable class names with Swagger?
Finally I used CustomSchemaId to solve this issue. Maybe it will be useful for someone who is facing a similar problem.
Credit to an opened issue, which pointed me in this direction.
I just added the following CustomSchemaIds in Swagger settings:
services.AddSwaggerGen(c =>
{
// ...
c.CustomSchemaIds(i => {
var typeName = type.Name;
if (!type.GetTypeInfo().IsGenericType) {
return typeName;
}
var genericArgumentIds = type.GetGenericArguments()
.Select(t => t.Name)
.ToArray();
return new StringBuilder(typeName)
.Replace($"`{genericArgumentIds.Count()}", string.Empty)
.Append($"<{string.Join(",", genericArgumentIds).TrimEnd(',')}>")
.ToString();
});
});
And after this, I got type in format that I was looking for:
BulkRequest<ClassA,ClassB>

How to setup Moq for the same method where return value depends on input?

I'd like to test a method called multiple times during test, in a way where the tested method output depends on its input. I checked Moq's documentation and the following example seems to what I need.
// matching Func<int>, lazy evaluated
mock.Setup(foo => foo.Add(It.Is<int>(i => i % 2 == 0))).Returns(true);
The tested method looks like this:
Task<DimensionStructure> GetDimensionStructureByIdAsync(DimensionStructure dimensionStructure);
The DimensionStructure class looks like this, it is simplified as on the Id is important.
public class DimensionStructure
{
public long Id { get; set; }
}
But when I put together the mock I need, example below, when it is called it returns always null.
_masterDataWebApiClientMock.Setup(m => m.GetDimensionStructureByIdAsync(
It.Is<DimensionStructure>(
structure => structure.Id == 101)
))
.ReturnsAsync(addedToRoot);
_masterDataWebApiClientMock.Setup(m => m.GetDimensionStructureByIdAsync(
It.Is<DimensionStructure>(
structure => structure.Id == 201 )
))
.ReturnsAsync(addedToFirstLevel);
The point os that the method gets different parameter and returns different objects.
In both cases, it returns null. According to the doc, it should return what is in the ReturnAsync which is not null.
It works perfectly in another test where the Id property value of the object doesn't matter.
_masterDataWebApiClientMock.Setup(m => m.GetDimensionStructureByIdAsync(It.IsAny<DimensionStructure>()))
.ReturnsAsync(addedDimensionStructure);
The question is, how to solve this?
Update - 02/29/2020
When I do not specify the call parameter then it is just working fine. It makes a bit tricky to test the method, but solvable.
_masterDataWebApiClientMock
.Setup(m => m.GetDimensionStructureByIdAsync(
It.IsAny<DimensionStructure>()
))
.ReturnsAsync(addedToRoot);
On the other hand I reported this case a special, possible bug case to Moq folks.
Having put together a test bench as follows I can see it returns correct values.
It seems either my assumptions about IClassUnderTest are wrong or you might need to ensure addedToRoot and addedToFirstLevel are defined when you call your mocked method.
This probably doesn't answer your question per se, I'm however hoping this will either point you in the right direction or will prompt for more information.
using System;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq; //I'm running Moq 4.13
namespace UnitTestProject1
{
public class DimensionStructure
{
public long Id { get; set; }
}
public interface ITest
{
Task<DimensionStructure> GetDimensionStructureByIdAsync(DimensionStructure dimensionStructure);
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var addedToRoot = new DimensionStructure { Id = 1 };
var addedToFirstLevel = new DimensionStructure { Id = 2 };
var _masterDataWebApiClientMock = new Mock<ITest>();
_masterDataWebApiClientMock.Setup(m => m.GetDimensionStructureByIdAsync(
It.Is<DimensionStructure>(
structure => structure.Id == 101)
))
.ReturnsAsync(addedToRoot);
_masterDataWebApiClientMock.Setup(m => m.GetDimensionStructureByIdAsync(
It.Is<DimensionStructure>(
structure => structure.Id == 201)
))
.ReturnsAsync(addedToFirstLevel);
Assert.AreEqual(1, _masterDataWebApiClientMock.Object.GetDimensionStructureByIdAsync(new DimensionStructure { Id = 101 }).Result.Id);
Assert.AreEqual(2, _masterDataWebApiClientMock.Object.GetDimensionStructureByIdAsync(new DimensionStructure { Id = 201 }).Result.Id);
}
}
}

Best practice to validate properties based on other properties

Imagine you have a class like :
public enum Kind { Kind1, Kind2 }
public class MyForm
{
public string Kind { get; set; }
public ACustomClass1 Custom1 { get; set; }
public ACustomClass2 Custom2 { get; set; }
}
And you want to validate Custom1 with Custom1Validator when Kind == Kind1 (and Custom2 with Custom2Validator when Kind == Kind2, obviously)
What is the best way to proceed with version 8.6.0 ?
At the moment, I've done like this (but I find it is awkward):
public class MyFormValidator : AbstractValidator<MyForm>
{
public MyFormValidator (IStringLocalizer<Strings> localizer, Custom1Validator validator1, Custom2Validator validator2)
{
//validate Kind and then, in function of Kind, use correct validator
RuleFor(x => x).Custom((f, context) => {
if (!Enum.TryParse<Kind>(f.Kind, out var kind))
{
context.AddFailure(localizer["Invalid Kind"]);
return;
}
switch (kind)
{
case Kind.Kind1:
if (f.Custom1 == null)
{
context.AddFailure(localizer["Invalid Kind"]);
}
else if (! validator1.Validate(f.Custom1, out var firstError))
{
context.AddFailure(firstError);
}
break;
case Kind.Kind2:
if (f.Custom2 == null)
{
context.AddFailure(localizer["Invalid Kind"]);
}
else if (!validator2.Validate(f.Custom2, out var firstError))
{
context.AddFailure(firstError);
}
break;
}
});
}
}
Note that I am using asp.net core with dependency injection (this is why there is IStringLocalizer and I can not use SetValidator for Custom1 and Custom2)
What I'd like instead is something like
RuleFor(x => x.Kind).NotEmpty().IsEnumName(typeof(Kind)).withMessage(_ => localizer["Invalid Kind"]);
RuleFor(x => x.Custom1).NotEmptyWhen(f => f.Kind == Kind.Custom1.ToString()).withMessage(_ => localizer["Invalid Kind"])
RuleFor(x => x.Custom1).SetValidator(validator1); //would be executed only when custom1 is not null
//same for custom2
The problem is that I do not see how to do code the NotEmptyWhen method
Restructure?
By the looks of your posted code snippets, I presume that MyForm will never have a populated Custom1 and Custom2 property in the same request. So, instead of having a parent model that holds both payload kinds, I would encourage you to directly use the model that represents the payload being validated. Then you won't run into this nasty pattern of checking the kind wherever necessary.
One of your form endpoints accepts a Custom1, which has an associated Custom1Validator. Another one of your form endpoints accepts a Custom2, which has an associated Custom2Validator. They are decoupled. You can safely change one without affecting the other.
Use Fluent Validation Conditions (When/Unless)
If you're dead set on having one model responsible for representing the payload of multiple requests (please don't), you can use the When() method provided by the library. Take a look at their documentation on conditional rules.

How to write method in automapper class c#

I am trying to write method in AutoMapper class. My situation is as below.
ClinicListVm = AutoMapperConfig.mapper
.Map<GetClinicsByUserName_Result, ClinicListViewModel>(c);
I already map ClinicListViewModel with GetClinicsByUserName_Result now I want to manipulate one attribute my destination model as below.
ClinicListVm.ProgressBarCssClass = string.Empty;
if (ClinicListVm.PercentComplete == 100)
{
ClinicListVm.ProgressBarCssClass = "progress-bar-success";
}
else if (DateTime.Now.Subtract(ClinicListVm.BillerStartDateTime ?? DateTime.Now).TotalDays > MaxDaysInDataEntry)
{
// partial is a warning color
ClinicListVm.ProgressBarCssClass = "progress-bar-partial";
}
So, How I can include this code it self in automapper class.
Thanks
I personally think #Rajmond Burgaj's anwer is a good one. Using a ResolveUsing(), or a custom resolver, is in this case a good way to go.
However, I just want to share a more pragmatic alternative that may result in the same and might help you in the future. You may want to consider abstracting the conditional if...then... logic to a seperate function. For example:
private string DetermineProgressBarState(SourceClass source)
{
if (source.PercentComplete == 100) return "progress-bar-success";
var MaxDaysInDataEntry = 42; // missing in your sample
return DateTime.Now.Subtract(source.BillerStartDateTime ?? DateTime.Now).TotalDays > MaxDaysInDataEntry
? "progress-bar-partial"
: null;
}
With that, you can easily map it in your configuration, like so:
Mapper.Initialize((config =>
{
config.CreateMap<SourceClass, TargetClass>()
.ForMember(
dest => dest.ProgressBarCssClass,
opt => opt.MapFrom(src => DetermineProgressBarState(src))
);
}));
This runs exactly as you'd expect. Here is the full sample, as a XUnit test (but you'll get the picture):
public class SourceClass
{
public int PercentComplete { get; set; }
public DateTime? BillerStartDateTime { get; set; }
}
public class TargetClass
{
public string ProgressBarCssClass { get; set; }
}
public class UnitTest1
{
[Fact]
public void Test1()
{
// arrange - configure the automapper
Mapper.Initialize((config =>
{
config.CreateMap<SourceClass, TargetClass>()
.ForMember(
dest => dest.ProgressBarCssClass,
opt => opt.MapFrom(src => DetermineProgressBarState(src))
);
}));
// arrange - create a
var source = new SourceClass() { PercentComplete = 100 };
// act - map source to target
var target = Mapper.Map<TargetClass>(source);
// assert - verify the result
target.ProgressBarCssClass.Should().Be("progress-bar-success");
}
private string DetermineProgressBarState(SourceClass source)
{
if (source.PercentComplete == 100) return "progress-bar-success";
var MaxDaysInDataEntry = 42; // missing in your sample
return DateTime.Now.Subtract(source.BillerStartDateTime ?? DateTime.Now).TotalDays > MaxDaysInDataEntry
? "progress-bar-partial"
: null;
}
}
But... I totally agree with the comment that AutoMapper is not the place to put this logic in. The reason is that you're actually defining markup logic (html/css data) in your mapping logic. This is better placed inside your view, presumably your .cshtml.
With that in mind, should you choose to refactor this somehow "the proper way" in the future, the DetermineProgressBarState() function will still be helpful. You'll just move the code from your AutoMapper config to your controller (or .cshtml helper).
If you want to execute another function while mapping you can use ResolveUsing method and put your logic in there.
CreateMap<GetClinicsByUserName_Result, ClinicListViewModel>()
.ForMember(d => d.ProgressBarCssClass , o => o.ResolveUsing(s =>
{
//Do your custom logic here.
}))
.AfterMap((src, dest) =>
{
//Do your logical after mapping has been done
dest.ProgressBarCssClass = string.Empty;
if (dest.PercentComplete == 100)
{
dest.ProgressBarCssClass = "progress-bar-success";
}
else if (DateTime.Now.Subtract(dest.BillerStartDateTime ??
DateTime.Now).TotalDays > MaxDaysInDataEntry)
{
// partial is a warning color
dest.ProgressBarCssClass = "progress-bar-partial";
}
});
Not quite sure where that MaxDaysInDataEntry is coming from but if it can be retrieved inside this method your are good to go this way otherwise if MaxDaysInDataEntry is a variable generated from business logic elsewhere then it is a problem!
Anyway let me know if it help and where that variable is coming from!

Fluent Validation rules, subsets and nesting

Given a validator class that looks like this
public class SomeValidator : AbstractValidator<SomeObject>
{
public SomeValidator(){
RuleSet("First",
() => {
RuleFor(so => so.SomeMember).SetValidator(new SomeMemberValidator())
});
RuleSet("Second",
() => ... Code Does Not Matter ... );
RuleSet("Third",
() => ... Code Does Not Matter ... );
}
}
And another to do the inner member validation
public class SomeMemberValidator: AbstractValidator<SomeMember>
{
public SomeValidator(){
RuleSet("Fourth",
() => {
... Code Does Not Matter ...
});
}
}
Question is, I want to run specific rulesets: "First", "Second", and "Fourth". I don't want "Third" to run.
Given the Validate method signature only takes a single ruleset argument I don't see any way to do this. There is "*", but I don't want to run all the rules.
Please help.
You could use validator constructor instead of RuleSet as a workaround for this problem.
Just create enum inside of validator class and then use its value when creating validator.
I this way correct rules will be activated depending on what Mode is set in constructor.
public class UserValidator : AbstractValidator<User>
{
public enum Mode
{
Create,
Edit
}
public UserValidator()
{
// Default rules...
}
public UserValidator(UserValidator.Mode mode)
: this()
{
if (mode == Mode.Edit)
{
// Rules for Edit...
RuleFor(so => so.SomeMember)
.SetValidator(
new SomeMemberValidator(SomeMemberValidator.Mode.SomeMode))
}
if (mode == Mode.Create)
{
// Rules for Create...
RuleFor(so => so.SomeMember)
.SetValidator(
new SomeMemberValidator())
}
}
}
I think it's actually more flexible method than using RuleSet.
There is only one small problem regarding FluentValidation MVC integration:
User class can't have attribute [Validator(typeof(UserValidator))] because UserValidator will be then created using default constructor, before you can do anything in controller method.
Validator must be created and called manually. Like that for example:
public class UserController : Controller
{
[HttpPost]
public ActionResult Create(User userData)
{
var validator = new UserValidator(UserValidator.Mode.Create);
if (ValidateWrapper(validator, userData, this.ModelState))
{
// Put userData in database...
}
else
{
// ValidateWrapper added errors from UserValidator to ModelState.
return View();
}
}
private static bool ValidateWrapper<T>(FluentValidation.AbstractValidator<T> validator, T data, ModelStateDictionary modelState)
{
var validationResult = validator.Validate(data);
if (!validationResult.IsValid)
{
foreach (var error in validationResult.Errors)
modelState.AddModelError(error.PropertyName, error.ErrorMessage);
return false;
}
return true;
}
}
You can execute more than one RuleSet, but I don't think you can execute the inner RuleSet.
validator.Validate(new ValidationContext<SomeObject>(person, new PropertyChain(), new RulesetValidatorSelector("First", "Second", "Fourth")));
Source
The other option is to investigate the source code and try to think a way of doing it. The third parameter of the ValidationContext is an interface, IValidatorSelector, maybe you can have some luck with a custom class.

Categories