How to implement IConvertible - c#

I have some test code to check if 2 sides are equal.
public void GetCompanies_WithCorrectCompanyRequest_ReturnCompanyDtos()
{
// Arrange
var companyRequset = new CompanyRequest();
// Act
var companyDtos = _datlinqServiceMock.GetCompanies(companyRequset);
// Assert
Assert.IsTrue(companyDtos != null && companyDtos.Any());
Assert.AreEqual(DatlinqServiceMock.CompanyName, companyDtos.FirstOrDefault().Name);
}
That calls this.
public class DatlinqServiceMock: DatlinqService
{
public static string CompanyName = "Company_Test";
public override T GetApi<Q,T>(string apiMethod, Q request)
{
var companyList = new List<Company>()
{
new Company(){ Name = CompanyName}
};
return (T)Convert.ChangeType(companyList, typeof(T));
}
}
GetCompanies:
public List<Company> GetCompanies(CompanyRequest request)
{
if (request == null)
{
return new List<Company>();
}
var searchCompany = new SearchCompanyRequest();
searchCompany.Query = request.Name;
searchCompany.DatlinqKey = ConfigurationManager.AppSettings["Datlinq_Key"];
var searchCompanyResponse = GetApi<SearchCompanyRequest,SearchCompanyResponse>(DatlinqApiMethod.SearchCompany, searchCompany);
var companies = searchCompanyResponse.Result
.Select(c => new Company { Id = c.Id, Name = c.Name })
.ToList();
return companies;
}
GetApi:
public virtual T GetApi<Q,T>(string apiMethod, Q request)
{
var result = default(T);
try
{
var url = String.Format("{0}{1}", _apiUrl, apiMethod);
if (request != null)
{
url = QueryHelpers.AddQueryString(url, request.ToDictionary());
}
var apiResponse = _httpClient.GetAsync(url).Result;
if (apiResponse.IsSuccessStatusCode)
{
string apiResponseString = apiResponse.Content.ReadAsStringAsync().Result;
if (!string.IsNullOrEmpty(apiResponseString))
{
result = JsonConvert.DeserializeObject<T>(apiResponseString);
}
}
}
catch (Exception)
{
// do something
}
return result;
}
And I get an error when I execute the first test
Message: 
Test method Lavazza.ContractTool.Datlinq.Tests.Services.DatlinqServiceTests.GetCompanies_WithCorrectCompanyRequest_ReturnCompanyDtos threw exception:
System.InvalidCastException: Object must implement IConvertible.
Stack Trace: 
Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
Convert.ChangeType(Object value, Type conversionType)
DatlinqServiceMock.GetApi[Q,T](String apiMethod, Q request) line 79
DatlinqService.GetCompanies(CompanyRequest request) line 23
DatlinqServiceTests.GetCompanies_WithCorrectCompanyRequest_ReturnCompanyDtos() line 32
I hope this is enough code to know what the problem/solution is if not let me know what you need.
To answer some question asked below.
Dai: I am trying to find what this is and why I need it because it came up in the error but the microsoft docs don't make it clear for me.
Jeroen: It is kind of a legacy project so I can't/won't add extra dependencies.

The "issue" here is that your GetApi method is designed to return a sort of generic response - in this specific case SearchCompanyResponse - but you're trying to override it to return a List<Company> which is wrong because that is what your GetCompanies method does (ie turn a SearchCompanyResponse to a List<Company>).
Suffice it to say this has nothing to do with implementing IConvertable.
What you would be better off doing is serializing a SearchCommpanyResponse that you wish to use for testing to a file, and using that file-based response for your testing.
That way your overridden "Mock" would be
public override T GetApi<Q,T>(string apiMethod, Q request)
{
return JsonConvert.DeserializeObject<T>(File.ReadAllText("mytestfile.json"));
}

Related

Recursion is causing double results

I have 2 methods.
Method 1 calls a google drive service which returns an array of an object of files.
Method 2 calls the first method to get the returned list, which calls the google drive service which activates the method you see below for a "second" time.
I may be wrong but I think the recursion is causing my final list results to be doubled. Or it may be because I have declared files outside of this method. Once the line files.AddRange(....) is called by the second method it technically already contains the files from the first method. I am not quite sure how to solve my issue.
readonly Stack myStack = new Stack();
readonly HashSet<BFile> files = new Hashset<BFile>();
readonly HashSet<BFile> pushedList = new HashSet<BFile>();
public async Task<(BFile[]? files, string? error)> GetFiles(string parentId, bool includePermissions)
{
var service = service..
if (service != null)
{
var listRequest = service.Files.List();
do
{
var response = await listRequest.ExecuteAsync();
var folders = response.Files.Where(f => f.MimeType == "application/vnd.google-apps.folder");
var allOtherFiles = response.Files.Where(f => f.MimeType != "application/vnd.google-apps.folder");
files.AddRange(folders.Where(f => f.Name != "$ExclaimerSignatures").Select(f => mapFile(f)));
files.AddRange(allOtherFiles.Select(f => mapFile(f)));
var missingFiles = files.Where(f => !pushedList.Contains(f)).ToList();
missingFiles.ForEach(myStack.Push);
pushedList.UnionWith(missingFiles);
while (myStack.Count != 0)
{
var temp = (BFile)myStack.Peek();
myStack.Pop();
await GetFiles(temp.Id, true);
}
listRequest.PageToken = response.NextPageToken;
} while (listRequest.PageToken != null);
return (files.ToArray(), null);
}
else
return (null, "Something went wrong");
}
edit: to answer a question from below the only reason why I have stack with recursion tree walking is I use the stack to keep track of stuff that has been visited. I am not sure if that is bad or not, it was just simply what I came up with upon initially writing this code
I think the issue is that HashSet is not determinating BFiles like unique, and it is a reason why HashSet<BFile> files have duplicated values.
To fix it, you can override Equals and GetHashCode in your class BFile. If BFile is not your class, check if maybe it has already it implemented. If not, you can do it with the IEqualityComparer interface. Here is a simple example:
var files = new HashSet<BFile>(new Comparer());
var items = Enumerable.Empty<BFile>(); //Can be any collection
files.UnionWith(items);
class Comparer : EqualityComparer<BFile>
{
public override bool Equals(BFile? x, BFile? y) => x.Id == y.Id;
public override int GetHashCode(BFile obj) => obj.Id.GetHashCode();
}
class BFile
{
public string Id { get; set; }
public string Name { get; set; }
public byte[] Content { get; set; }
}
I hope it will help you.

Fluent Validation changing CustomAsync to MustAsync

Could some one please help me to resolved this? i'm trying to change CustomAsync to MustAsync, but i couldn't make things to work. Below is my custom method
RuleFor(o => o).MustAsync(o => {
return CheckIdNumberAlreadyExist(o)
});
private static async Task<ValidationFailure> CheckIdNumberAlreadyExist(SaveProxyCommand command)
{
if (command.Id > 0)
return null;
using (IDbConnection connection = new SqlConnection(ConnectionSettings.LicensingConnectionString))
{
var param = new DynamicParameters();
param.Add("#idnumber", command.IdNumber);
var vehicle = await connection.QueryFirstOrDefaultAsync<dynamic>("new_checkDuplicateProxyIdNumber", param, commandType: CommandType.StoredProcedure);
return vehicle != null
? new ValidationFailure("IdNumber", "Id Number Already Exist")
: null;
}
}
To make it work with the latest version of the FluentValidation, I had to use the codes like below.
RuleFor(ws => ws).MustAsync((x, cancellation) => UserHasAccess(x)).WithMessage("User doesn't have access to perform this action");
Please notice the lambda expression here MustAsync((x, cancellation) => UserHasAccess(x)), without this I was always getting an error as cannot convert from 'method group' to 'Func<Worksheet, CancellationToken, Task<bool>>
Below is my custom UserHasAccess function.
private async Task <bool> UserHasAccess(Worksheet worksheet) {
var permissionObject = await _dataProviderService.GetItemAsync(worksheet.FileItemId);
if (permissionObject is null) return false;
if (EditAccess(permissionObject.Permission)) return true;
return false;
}
I'm assuming you're using a version of FluentValidation prior to version 6, as you're not passing in a Continuation Token, so I've based my answer on version 5.6.2.
Your example code does not compile, for starters, as you're missing a semi-colon in your actual rule. You are also evaluating two different properties on the SaveProxyCommand parameter.
I've built a very small POC based on some assumptions:
Given 2 classes:
public class SaveProxyCommand {
public int Id { get; set; }
}
public class ValidationFailure {
public string PropertyName { get; }
public string Message { get; }
public ValidationFailure(string propertyName, string message){
Message = message;
PropertyName = propertyName;
}
}
And a validator:
public class SaveProxyCommandValidator : AbstractValidator<SaveProxyCommand>{
public SaveProxyCommandValidator()
{
RuleFor(o => o).MustAsync(CheckIdNumberAlreadyExists)
.WithName("Id")
.WithState(o => new ValidationFailure(nameof(o.IdNumber), "Id Number Already Exist"));
}
private static async Task<bool> CheckIdNumberAlreadyExists(SaveProxyCommand command) {
if (command.Id > 0)
return true;
var existingIdNumbers = new[] {
1, 2, 3, 4
};
// This is a fudge, but you'd make your db call here
var isNewNumber = !(await Task.FromResult(existingIdNumbers.Contains(command.IdNumber)));
return isNewNumber;
}
}
I didn't include the call to the database, as that's not part of your problem. There are a couple of things of note here:
You're not setting the .WithName annotation method, but when you're setting up a validation rule for an object you have to do this, as FluentValidation expects you to specify specific properties to be validated by default, if you pass in an entire object it just doesn't know how to report errors back.
Must/MustAsync need to return a bool/Task<bool> instead of a custom object. To get around this, you can specify a custom state to be returned when failing validation.
You can then get access to this like this:
var sut = new SaveProxyCommand { Id = 0, IdNumber = 3 };
var validator = new SaveProxyCommandValidator();
var result = validator.ValidateAsync(sut).GetAwaiter().GetResult();
var ValidationFailures = result.Errors?.Select(s => s.CustomState).Cast<ValidationFailure>();
The above does not take into account empty collections, it's just an example of how to dig into the object graph to retrieve custom state.
As a suggestion, fluentvalidation works best if you set up individual rules per property, instead of validating the entire object. My take on this would be something like this:
public class SaveProxyCommandValidator : AbstractValidator<SaveProxyCommand>{
public SaveProxyCommandValidator()
{
RuleFor(o => o.IdNumber).MustAsync(CheckIdNumberAlreadyExists)
.Unless(o => o.Id > 0)
.WithState(o => new ValidationFailure(nameof(o.IdNumber), "Id Number Already Exist"));
}
private static async Task<bool> CheckIdNumberAlreadyExists(int numberToEvaluate) {
var existingIdNumbers = new[] {
1, 2, 3, 4
};
// This is a fudge, but you'd make your db call here
var isNewNumber = !(await Task.FromResult(existingIdNumbers.Contains(numberToEvaluate)));
return isNewNumber;
}
}
This read more like a narrative, it uses the .Unless construct to only run the rule if Id is not more than 0, and does not require the evaluation of the entire object.

One Method Accepting Two Different Objects

I have two methods, one to check-in internal users and another to check-in external users. The method is the same except for the object (see code). I was wondering if it's possible to have one method that would accept both objects. I want to pass a parameter that says if it's internal or external, and based on that I want to call the respective object and save it. Not sure if it's possible.
public JsonResult CheckInInternal(int ID)
{
var e = EventInternal.Get(ID, EventInternal.FetchType.ID);
if (e.ID == 0)
{
throw new Exception("Registration ID not found.");
}
if (DateTime.Now.Date > e.EventDetail.StartTime.Date)
{
throw new Exception("Check-in has been closed for this class!");
}
e.CheckedIn = true;
e.Save();
return Json(new { success = true, message = "Success!" });
}
public JsonResult CheckInExternal(int ID)
{
var e = EventExternal.Get(ID, EventExternal.FetchType.ID);
if (e.ID == 0)
{
throw new Exception("Registration ID not found.");
}
if (DateTime.Now.Date > e.EventDetail.StartTime.Date)
{
throw new Exception("Check-in has been closed for this class!");
}
e.CheckedIn = true;
e.Save();
return Json(new { success = true, message = "Success!" });
}
Not saying this is the best way, but you can use Reflection
public enum CallType
{
Internal, External
}
public JsonResult CheckInInternalOrExternal(int ID, CallType type)
{
object e = type == CallType.Internal? EventInternal.Get(ID, EventInternal.FetchType.ID) as object : EventExternal.Get(ID, EventExternal.FetchType.ID) as object;
var idProperty = e.GetType().GetProperty("ID");
var idValue = Convert.ToInt32(IdProperty.GetValue(e));
if (idValue == 0)
{
throw new Exception("Registration ID not found.");
}
if (DateTime.Now.Date > e.EventDetail.StartTime.Date)
{
throw new Exception("Check-in has been closed for this class!");
}
var checkedInProperty = e.GetType().GetProperty("CheckedIn");
checkedInProperty.SetValue(e, true);
var saveMethod = e.GetType().GetMethod("Save");
saveMethod.Invoke(e);
return Json(new { success = true, message = "Success!" });
}
But as some commenters are saying, Interface or Generics is the best solution. Depending on your scenario.

Faking the find method in FakeDbSet implementation

I want to unit test a controller that takes a FormCollection and has the Find method. I have successfully implemented a fake DbContext and a FakeDbSet (from here) so that I can use the fake objects in my tests.
The specific method I want to test looks like this:
//
// POST: /Order/SettleOrders
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SettleOrders(FormCollection c)
{
int i = 0;
if (ModelState.IsValid)
{
var ordersCollection = new List<Order>();
// Get values of form
var OrderIdArray = c.GetValues("item.OrderId");
var UnitPriceArray = c.GetValues("item.UnitPrice");
for (i = 0; i < OrderIdArray.Count(); i++)
{
// Find order in database and update the unitprice and isconfirmed status
Order order = db.Orders.Find(Convert.ToInt32(OrderIdArray[i]));
order.UnitPrice = Convert.ToDecimal(UnitPriceArray[i]);
order.IsConfirmed = true;
db.SetModified(order);
ordersCollection.Add(order);
}
db.SaveChanges();
}
// Return orders of this date to view
var currentDate = DateTime.Today;
var orders = db.Orders.Include(o => o.Product)
.Include(o => o.User)
.Where(o => o.Date == currentDate);
return View("Confirmation", orders.ToList().OrderBy(o => o.User.Name));
}
This is how I set up the test of my OrderController using Moq:
[TestInitialize]
public void OrderControllerTestInitialize()
{
// Arrange
var unconfirmedMemoryItems = new FakeOrderSet
{
// #TODO Tests/methods should ideally not be dependent on DateTime.Today...
new Order { OrderId = 1, UnitPrice = 1.00M, Quantity = 2, Date = DateTime.Today, IsConfirmed = false },
new Order { OrderId = 2, UnitPrice = 2.00M, Quantity = 1, Date = DateTime.Today, IsConfirmed = false }
};
// Create mock unit of work
var unconfirmedMockData = new Mock<ISeashellBrawlContext>();
unconfirmedMockData.Setup(m => m.Orders).Returns(confirmedMemoryItems);
// Setup controller
unconfirmedOrderController = new OrderController(confirmedMockData.Object);
}
Then the test goes likes this to confirm the unconfirmed orders are becoming confirmed.
[TestMethod]
public void TestSettleOrdersPost()
{
// Invoke
FormCollection form = CreatesettleOrdersPostFormCollection();
var viewResult = unconfirmedOrderController.SettleOrders(form) as ViewResult;
var ordersFromView = (IEnumerable<Order>)viewResult.Model;
// Assert
Assert.AreEqual(3, ordersFromView.ElementAt(0).Quantity,
"New item should be added to older one since it has same index and is of same date");
Assert.AreEqual(true, ordersFromView.ElementAt(0).IsConfirmed,
"The item should also be set to confirmed");
}
// Helper methods
private static FormCollection CreatesettleOrdersPostFormCollection()
{
FormCollection form = new FormCollection();
form.Add("item.OrderId", "1");
form.Add("item.UnitPrice", "2.00");
form.Add("item.OrderId", "2");
form.Add("item.UnitPrice", "3.00");
return form;
}
Unfortunately I get the following error message:
Test Name: TestSettleOrdersPost
Result Message:
System.NullReferenceException: Object reference not set to an instance
of an object. Result StackTrace: at
Controllers.OrderController.SettleOrders(FormCollection c) in
Controllers\OrderController.cs:line 121
This probably has to do with the fake Find method not doing what it is supposed to do. The find method I use looks like this:
class FakeOrderSet : FakeDbSet<Order>
{
public override Order Find(params object[] keyValues)
{
var id = Convert.ToInt32(keyValues[0]);
Order o = null;
IQueryable<Order> keyQuery = this.AsQueryable<Order>();
foreach (var order in keyQuery)
{
if (order.OrderId == id)
{
o = order;
}
}
return o;
}
}
I have no idea how to improve this code. Looking at it I am convinced it should work. Since I am a 7-day noob to unit testing this conviction is of not much worth though. I hope someone can help me out.
I think you can include Find method implementation in your generic FakeDbSet<T> class.
For example if all your entites have property Id that is mapped to primary key in database you can do following:
public class FakeDbSet<T>
{
....
public T Find(params object[] keyvalues)
{
var keyProperty = typeof(T).GetProperty(
"Id",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
var result = this.SingleOrDefault(obj =>
keyProperty.GetValue(obj).ToString() == keyValues.First().ToString());
return result;
}
}
If your key property is not Id you can try to determine some algorith how to recognize key property for the entity via reflection (for example if Order class have OrderId key property you can try to determine it by getting class name with reflection and concatenating it with "Id" string).
I have the same problem:
public override TEntity Find(params object[] keyValues)
{
if (keyValues.Length == 0)
throw new ArgumentNullException("keyValues");
return this.SingleOrDefault(GenerateKeyFilter(keyValues));
}
private Expression<Func<TEntity, bool>> GenerateKeyFilter(object[] keyValues)
{
var conditions = new List<BinaryExpression>();
var objectParam = Expression.Parameter(typeof(TEntity));
var keyFields = !!!Helper.KeyFields<TEntity>();
if (keyFields.Count != keyValues.Length)
throw new KeyNotFoundException();
for (var c = 0; c < keyFields.Count; c++)
conditions.Add(Expression.MakeBinary(
ExpressionType.Equal,
Expression.MakeMemberAccess(objectParam, keyFields[c]),
Expression.Constant(keyValues[c], keyFields[c].PropertyType)
));
var result = conditions[0];
for (var n = 1; n < conditions.Count; n++)
result = Expression.And(result, conditions[n]);
return Expression.Lambda<Func<TEntity, bool>>(result, objectParam);
}
This works well, however, to create the tests I had to reconfigure the models and manually set the keys, similar to use of EntityTypeConfiguration.

If chained - how to delete?

I'm doing an application where I have the following scenario:
I have several rules (business classes)
where they all return the client code. They are separate classes that will look for the code trial and error, if find the client code returns it and so on.
How can I use a rule without using a bunch of IFs or threaded IFs in the class that calls the others that contains the specific business rules?
For the specific classes, I used the design pattern strategy.
EX: Main Class
public abstract class Geral
{
public abstract string retornaCodigo(Arquivo cliente)
{
var codigo = ""; // logica
return codigo;
}
}
public class derivada1 : Geral
{
public override string retornaCodigo(Arquivo cliente)
{
var codigo = ""; // logica
return codigo;
}
}
public class derivada2 : Geral
{
public override string retornaCodigo(Arquivo cliente)
{
var codigo = ""; // logica 2
return codigo;
}
}
public class derivada3 : Geral
{
public override string retornaCodigo(Arquivo cliente)
{
var codigo = ""; // logica 3
return codigo ;
}
}
public class Negocio
{
public string Codigo()
{
var arquivo = new Arquivo();
var derivada1 = new derivada1().retornaCodigo(arquivo);
var derivada2 = new derivada2().retornaCodigo(arquivo);
var derivada3 = new derivada3().retornaCodigo(arquivo);
if (derivada1.Equals(null))
return derivada1;
if (derivada2.Equals(null))
return derivada2;
if (derivada3.Equals(null))
return derivada3;
return "";
}
}
what I wanted and that I did not have to use Ifs in the Business class for validation whether or not I found the code where it can fall under any condition gave example of 3 classes plus I have more than 15 conditions and can increase, case would be many Ifs.
Let's organize all derivada into a collection, say, array and then query the collection with a help of Linq
public string Codigo() {
var arquivo = new Arquivo();
Geral[] derivadas = new [] {
new derivada1(),
new derivada2(),
new derivada3();
};
//TODO: check the the condition: I guessed that you want to return first meanful codigo
foreach (var codigo in derivadas.Select(geral => geral.retornaCodigo(arquivo)))
if (!string.IsNullOrEmpty(codigo))
return codigo;
return "";
}
If you have a lot of derivada you can try using Reflection in order to create a collection:
using System.Reflection;
...
private static Geral[] s_Derivadas = AppDomain
.CurrentDomain
.GetAssemblies() // scan assemblies
.SelectMany(asm => asm.GetTypes()) // types within them
.Where(t => !t.IsAbstract) // type is not abstract
.Where(t => typeof(Geral).IsAssignableFrom(t)) // type derived from Geral
.Where(t => t.GetConstructor(Type.EmptyTypes) != null) // has default constructor
.Select(t => Activator.CreateInstance(t) as Geral) // create type's instance
.ToArray(); // materialized as array
then
public string Codigo() {
var arquivo = new Arquivo();
foreach (var codigo in s_Derivadas.Select(geral => geral.retornaCodigo(arquivo)))
if (!string.IsNullOrEmpty(codigo))
return codigo;
return "";
}
You could create a list of derivada's and then iterate over it
and if any given derivada1 equals None, you simply return it, otherwise you just continue the 'for loop'
I could write up a snippet if this doesn't make sense to you. lmk!
This would be simple with Linq:
public class Negocio
{
public string Codigo()
{
var arquivo = new Arquivo();
var derivadaList = new List<Geral>() {
new derivada1(),
new derivada2(),
new derivada3(),
};
return derivadaList.FirstOrDefault(d => d.retornaCodigo(arquivo) == null)?.retornaCodigo(arquivo) ?? "";
}
}
You can add as many Geral derived classes to the derivadaList as you want and the code will continue to function as designed.
What is happening here is that FirstOrDefault will run the Lamda expression on every element returning the first one that equals null (although I'm not sure this is what you want, it matches your example code). Since it returns a Geral object, you need to call retornaCodigo on it only if it is not null. If it is null, just return an empty string.
Another way to write this would be:
public class Negocio
{
public string Codigo()
{
var arquivo = new Arquivo();
var derivadaList = new List<Geral>() {
new derivada1(),
new derivada2(),
new derivada3(),
};
foreach (var derivada in derivadaList)
{
var result = derivada.retornaCodigo(arquivo);
if (result == null)
return result;
}
return "";
}
}
You can also use a list of derived classes and call them in Loop
public string Codigo()
{
var arquivo = new Arquivo();
List<Geral> gerals=new List<Geral>();
gerals.Add(new derivada1());
gerals.Add(new derivada2());
........
...........
foreach(Geral g in gerals)
{
var val=g.retornaCodigo(arquivo);
if(val!=null)
return val;
}
return "";
}
This is a sample implementation, However you are not using strategy correctly
A better approach will be constructor injection,
public string Codigo(Geral implementar)
{
var val=geral.retornaCodigo(arquivo);
return "";
}
Then instantiate only with the chosen strategy.
Otherwise if you want to chain multiple validations, then use CHain of responsibility pattern.

Categories

Resources