How to re-use a method in C# - c#

So, in the code below, In the last method, I want to re use the second one public static Valute GetValuteByDate(DateTime date, string valuteCharCode), but I really don't understand what parameters to give. As you can see, I successfully re-used first method in the second method. Any idea what I can do to re-use the second method in the third one? Or maybe you have some useful information?
public static class Api
{
public static ValCurs GetValCursByDate(DateTime date)
{
var client = new RestClient("http://bnm.md"); //request
var request = new RestRequest("ro/official_exchange_rates/get_xml=1&date="+date.ToString(), Method.GET); //request
var response = client.Execute<ValCurs>(request);//deserialization
if (response.ErrorException != null) { return null; } //throw exception
return response.Data;
}
public static Valute GetValuteByDate(DateTime date, string valuteCharCode)
{
var curs = GetValCursByDate(date);
Valute valuteByDate = curs.FirstOrDefault(valute => valute.CharCode.Equals(valuteCharCode));
return valuteByDate;
}
public static Valute GetMaxValuteByPeriod(DateTime startDate, DateTime endDate, string charCode)
{
var maxVal = GetValuteByDate(**?**);
}
}

public static class Api
{
public static ValCurs GetValCursByDate(DateTime date)
{
var client = new RestClient("http://bnm.md"); //request
var request = new RestRequest("ro/official_exchange_rates/get_xml=1&date="+date.ToString(), Method.GET); //request
var response = client.Execute<ValCurs>(request);//deserialization
if (response.ErrorException != null) { return null; } //throw exception
return response.Data;
}
public static Valute GetValuteByDate(DateTime date, string valuteCharCode)
{
var curs = GetValCursByDate(date);
Valute valuteByDate = curs.FirstOrDefault(valute => valute.CharCode.Equals(valuteCharCode));
return valuteByDate;
}
public static Valute GetMaxValuteByPeriod(DateTime startDate, DateTime endDate, string charCode)
{
var totalDays = (endDate-startDate).TotalDays;
List<Valute> result = new List<Valute>(totalDays);
for(int i = 0; i < totalDays; i++)
{
result.Add(GetValuteByDate(startDate.AddDays(i), charCode);
}
var maxVal = result.Max(p => p.<put here property>);
return maxVal;
}
}

The third one seems to be using a range, so you'd need to call the second one for each day in the range.
for(var day = startDate; date<= endDate; day = day.AddDays(1))
{
Valute value = GetValuteByDate(date, valuteCharCode);
//compare value to the max value and set if higher
}
Note: I didn't test this code so you might have to fiddle with it

Related

How to use C# Task libraries to download and process a sequence of data

I've been struggling with a design to maximize the parallelism of a task using C# and Task libraries. Although I have some idea of various parallel processing concepts (and also reading multiple StackOverflow questions on the topic), I am having a hard time trying to assemble everything in a coherent manner that will solve my problem.
My problem has these properties/rules:
I would like to download a time-stamped series of data from a HTTP connection in "segments" across a number of http servers/connections.
Depending on the specific HTTP service, it will provide each segment of data in a differing size. For example, on one connection it may provide an hourly segment for each request (eg. "http://server1/getdata?year=2020&month=1&day=1&hour=1"). On a different connection, it might provide the data in a monthly segment (eg. "http://server2/getdata?year=2020&month=1"). It is not possible to get hourly data from a monthly connection or vice versa.
If any one server fails or is busy with more than x connections, I would like to retry on a different server.
When a segment of data has been downloaded, it requires to be processed into a data-set result. As much as possible, this processing should be parallelized.
When the chronological first segment in the series arrives, I would like to immediately start processing it and processing each subsequent segment in chronological order (i.e. I do not want to wait for the entire series to complete downloading before responding to the caller).
Below is one of my attempts to solve this. For the sake of clarity, I have only included the stubs of some code.
public IEnumerable<object> RetrieveData(DateTime begin, DateTime end)
{
// Break the period up into the smallest segments allowed.
// In this case, we will create one segment for each hour between begin and end dates
var segments = new DataSegments(begin, end, IntervalTypeEnum.Hourly);
var cancelTokenSource = new CancellationTokenSource();
var cancelToken = cancelTokenSource.Token;
var tasks = new List<Task>();
// Start a number of tasks which are responsible for downloading segments
// until all segments are complete.
for (int i = 0; i < 3; i++)
{
var task = new Task(() =>
{
// Keep downloading segments until there are none left.
while (!segments.IsComplete && !cancelToken.IsCancellationRequested)
{
string errorMsg = string.Empty;
// Gets a list of connections available for downloading data
var connections = DataConnectionManager.GetConnectionQueue();
// Cycle through all the available connections until we successfully download
// a chunk.
Retry:
try
{
var connection = connections.Dequeue();
if (connection is MonthlyDataConnection)
{
List<Segment> list = segments.GetNext(SegmentType.Monthly);
DownloadAndProcessMonthlySegment(connection, chunk, cancelToken);
}
else if (connection is HourlyDataConnection)
{
List<Segment> list = segments.GetNext(SegmentType.Hourly);
foreach(var segment in list)
{
DownloadAndProcessHourlySegment(connection, segment, cancelToken);
}
}
}
catch
{
goto Retry;
}
}
});
task.Start();
tasks.Add(task);
}
foreach(var segment in segments)
{
segment.Wait(cancelToken);
if (chunk.Data != null && !cancelToken.IsCancellationRequested)
{
yield return chunk.Data;
}
}
Task.WaitAll(tasks.ToArray());
}
void DownloadAndProcessMonthlySegment(connection, segment, cancelToken)
{
// Download from http connection, throw exception if WebException.
// Process data if http download successful
// Mark all segments as complete/ready
}
void DownloadAndProcessHourlySegment(connection, segment, cancelToken)
{
// Download from http connection, throw exception if WebException.
// Process data if http download successful
// Mark segment as complete/ready
}
public enum SegmentType
{
NextAvailable,
Hourly,
Monthly
}
// Represents a series of data segments that need to be downloaded
// In this code example, it will have hourly segments that span the specified
// begin and end dates.
public class DataSegments: IEnumerable<DataSegment>
{
// Returns a list of segments that haven't been downloaded yet.
// Depending on the "SegmentType", it will return just one hourly segment or
// an entire month of hourly segments (SegmentType.Hourly)
public List<DataSegment> GetNext(SegmentType type = SegmentType.NextAvailable);
}
// Represents a segment of data that needs to be retrieved from the web
// and processed into "Data".
public class DataSegment
{
DateTime BeginDate { get; set; }
DateTime EndDate { get; set; }
// The processed data-set result
object Data { get; set; }
}
The code works by using a series of Tasks that operate like Threads and loop until a list of Segments are downloaded and processed. Depending on the connection type (monthly or hourly), it will download and process the data accordingly (while ensuring no other task attempts to download the same range of data).
Although the code does (mostly) work, I feel it isn't the most optimal or elegant solution. One short-coming, for example, would be that the tasks could be held waiting for HTTP requests when it could instead be processing data. Another is that the connection and error handling is not ideal. For example, there is no handling for the scenario where more than x connections have been established to a server.
Would someone have a better solution or ideas to improve on this code while properly maximizing parallelism?
EDIT:
As requested by #Enigmativity, below is a full console app example that can be compiled.
Limitations of the solution:
The number of running tasks are hard-coded.
Each task is designed more like a Thread with a continuous loop rather than a discrete operation.
Processing of segments is not parallelized as much as it could be.
No exception handling.
class Program
{
static Random random = new Random((int)DateTime.Now.Ticks);
static void Main(string[] args)
{
Connections.Instance.Enqueue(new Connection(IntervalTypeEnum.Hourly));
Connections.Instance.Enqueue(new Connection(IntervalTypeEnum.Daily));
var begin = new DateTime(2020, 1, 1);
var end = new DateTime(2020, 1, 5);
foreach (var download in Download(begin, end))
{
Console.WriteLine($"Final result: {download}");
}
Console.WriteLine("Press any key...");
Console.ReadKey();
}
public static IEnumerable<string> Download(DateTime begin, DateTime end)
{
var segments = new DataSegments(begin, end, IntervalTypeEnum.Hourly);
var cancelTokenSource = new CancellationTokenSource();
var cancelToken = cancelTokenSource.Token;
var taskList = new List<Task<object>>();
var tasks = new List<Task>();
for (int i = 0; i < 3; i++)
{
var task = new Task(() =>
{
while (!segments.IsComplete && !cancelToken.IsCancellationRequested)
{
string errorMsg = string.Empty;
var connection = Connections.GetNextAvailable();
var list = segments.GetNext(connection.IntervalType);
foreach (var segment in list)
{
GetSegment(connection, segment, cancelToken);
}
}
});
task.Start();
tasks.Add(task);
}
foreach (var segment in segments)
{
segment.Wait(cancelToken);
if (segment.Data != null && !cancelToken.IsCancellationRequested)
{
Console.WriteLine($"Yielding data: {segment.Data}");
yield return (string)segment.Data;
}
}
Task.WaitAll(tasks.ToArray());
}
static void GetSegment(Connection conn, DataSegment segment, CancellationToken token)
{
conn.WaitOne();
var result = conn.Download(segment.Begin, segment.End);
segment.Data = result;
ProcessSegment(segment, token);
conn.Release();
}
static void ProcessSegment(DataSegment segment, CancellationToken token)
{
Console.WriteLine($"Processing segment data: {segment.Data}");
for (DateTime d = segment.Begin; d < segment.End; d = d.AddHours(1))
{
for (int i = 0; i < 100; i++)
{
}
// Doing stuff..
}
segment.Status = DownloadStatusEnum.Done;
}
}
public class Connection
{
static Random random = new Random((int)DateTime.Now.Ticks);
public IntervalTypeEnum IntervalType { get; set; }
private SemaphoreSlim semaphore = new SemaphoreSlim(2);
public Connection(IntervalTypeEnum type)
{
IntervalType = type;
}
public void WaitOne()
{
semaphore.Wait();
}
public bool IsBusy
{
get
{
return semaphore.CurrentCount == 0;
}
}
public string Download(DateTime begin, DateTime end)
{
var data = $"{begin.ToString("yyyyMMdd hh:mm")} - {end.ToString("yyyyMMdd hh:mm")}";
Console.WriteLine($"Downloading {data}");
Thread.Sleep(random.Next(1000));
return data;
}
public void Release()
{
semaphore.Release();
}
}
public class Connections : Queue<Connection>
{
private static Connections instance = null;
public static Connections Instance
{
get
{
if (instance == null)
instance = new Connections();
return instance;
}
}
public static Connection GetNextAvailable()
{
Connection retVal = null;
foreach (var connection in Instance)
{
if (retVal == null) retVal = connection;
if (!connection.IsBusy)
{
retVal = connection;
break;
}
else
{
}
}
return retVal;
}
}
public enum DownloadStatusEnum
{
NeedsProcessing,
InProgress,
Done
}
public class DataSegment
{
public EventHandler OnStatusUpdate;
ManualResetEvent resetEvent = new ManualResetEvent(false);
public DataSegment(DateTime begin, DateTime end)
{
Begin = begin;
End = end;
Status = DownloadStatusEnum.NeedsProcessing;
Data = null;
}
public DateTime Begin { get; set; }
public DateTime End { get; set; }
private DownloadStatusEnum _status = DownloadStatusEnum.NeedsProcessing;
public DownloadStatusEnum Status
{
get
{
return _status;
}
set
{
_status = value;
Update();
}
}
public string Data { get; set; }
void Update()
{
// If the task is finished, then trigger anyone waiting..
if (Status == DownloadStatusEnum.Done) resetEvent.Set();
this.OnStatusUpdate?.Invoke(this, null);
}
public void Wait(CancellationToken token)
{
WaitHandle.WaitAny(
new[] { token.WaitHandle, resetEvent });
}
}
public enum ChunkType
{
NextAvailable,
Monthly
}
public enum IntervalTypeEnum
{
Hourly = 0,
Daily = 1,
}
public class DataSegments : IEnumerable<DataSegment>
{
protected List<DataSegment> chunkList = new List<DataSegment>();
protected HashSet<DataSegment> unprocessedList = new HashSet<DataSegment>();
protected HashSet<DataSegment> inProgressList = new HashSet<DataSegment>();
protected HashSet<DataSegment> completedList = new HashSet<DataSegment>();
public DataSegments(DateTime begin, DateTime end, IntervalTypeEnum intervalType)
{
BeginDate = begin;
EndDate = end;
IntervalType = intervalType;
DateTime requestDate = BeginDate;
DateTime endDate = new DateTime(EndDate.Year, EndDate.Month, EndDate.Day, EndDate.Hour,
EndDate.Minute, EndDate.Second);
DateTime finalRequestDate = EndDate;
DateTime beginPeriod = BeginDate;
DateTime endPeriod = DateTime.MinValue;
if (IntervalType == IntervalTypeEnum.Hourly)
{
beginPeriod = new DateTime(beginPeriod.Year, beginPeriod.Month, beginPeriod.Day, beginPeriod.Hour, 0, 0);
endPeriod = beginPeriod.AddHours(1);
requestDate = new DateTime(requestDate.Year, requestDate.Month, requestDate.Day, requestDate.Hour, 0, 0);
finalRequestDate = endDate.AddHours(1);
}
else if (IntervalType == IntervalTypeEnum.Daily)
{
beginPeriod = new DateTime(beginPeriod.Year, beginPeriod.Month, beginPeriod.Day, 0, 0, 0);
endPeriod = beginPeriod.AddDays(1);
requestDate = new DateTime(requestDate.Year, requestDate.Month, beginPeriod.Day, 0, 0, 0);
// Calculate the last request date as the end day of the month
finalRequestDate = new DateTime(endDate.Year, endDate.Month, beginPeriod.Day, 23, 0, 0);
}
while (endPeriod <= finalRequestDate)
{
var chunk = new DataSegment(beginPeriod < BeginDate ? BeginDate : beginPeriod, endPeriod > EndDate ? EndDate : endPeriod.AddTicks(-1));
chunk.OnStatusUpdate += OnStatusUpdated;
chunkList.Add(chunk);
unprocessedList.Add(chunk);
if (IntervalType == IntervalTypeEnum.Hourly)
{
beginPeriod = beginPeriod.AddHours(1);
endPeriod = beginPeriod.AddHours(1);
}
else if (IntervalType == IntervalTypeEnum.Daily)
{
beginPeriod = beginPeriod.AddMonths(1);
endPeriod = beginPeriod.AddMonths(1);
}
}
}
void OnStatusUpdated(object sender, EventArgs args)
{
if (sender is DataSegment)
{
var dc = (DataSegment)sender;
if (dc.Status == DownloadStatusEnum.NeedsProcessing)
{
lock (unprocessedList)
{
unprocessedList.Add(dc);
inProgressList.Remove(dc);
completedList.Remove(dc);
}
}
else if (dc.Status == DownloadStatusEnum.InProgress)
{
lock (unprocessedList)
{
unprocessedList.Remove(dc);
inProgressList.Add(dc);
completedList.Remove(dc);
}
}
else if (dc.Status == DownloadStatusEnum.Done)
{
lock (unprocessedList)
{
unprocessedList.Remove(dc);
inProgressList.Remove(dc);
completedList.Add(dc);
}
}
}
}
public IntervalTypeEnum IntervalType { get; set; }
public DateTime BeginDate { get; set; }
public DateTime EndDate { get; set; }
public int UnprocessedCount
{
get
{
lock (chunkList)
{
return unprocessedList.Count;
}
}
}
/// <summary>
/// Determines whether the
/// </summary>
public bool IsComplete
{
get
{
return chunkList.Count == completedList.Count;
}
}
public List<DataSegment> GetNext(IntervalTypeEnum type)
{
List<DataSegment> retVal = new List<DataSegment>();
lock (unprocessedList)
{
DataSegment firstSegment = null;
bool adding = false;
int watermark = -1;
foreach (var chunk in unprocessedList)
{
//if (chunk.Status == DownloadStatusEnum.NeedsProcessing)
{
// Grab the first available chunk. If we don't find anything else that suits,
// we will just return this.
if (firstSegment == null) firstSegment = chunk;
if (type == IntervalTypeEnum.Hourly)
{
Console.WriteLine("Reserving HOURLY segment for download");
break;
}
else if (type == IntervalTypeEnum.Daily)
{
// IF we are at the start of a month, then add these
// to our list until we progress to the next month.
// We take a note of the current month so we know when we have
// moved to the next.
if (!adding)
{
adding = true;
watermark = chunk.Begin.Day;
retVal.Add(chunk);
}
else if (adding && chunk.Begin.Day != watermark)
{
Console.WriteLine("Reserving DAILY segment for download");
break;
}
else
{
retVal.Add(chunk);
}
}
}
}
// If we didn't find any matching chunk, return the first one.
if (retVal.Count == 0 && firstSegment != null) retVal.Add(firstSegment);
} // lock
// Mark all the chunks as in progress
foreach (var chunk in retVal)
{
chunk.Status = DownloadStatusEnum.InProgress;
}
return retVal;
}
public IEnumerator<DataSegment> GetEnumerator()
{
return chunkList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}

mocking lambda expressions that are used in methods of the dut

I have a method like below that I want to unit test:
public string GetReferentie(string prefix)
{
IRepositoryAsync<ParameterGetal> parameterGetalRepository = _unitOfWork.RepositoryAsync<ParameterGetal>();
var dateparameterGetal = parameterGetalRepository
.Query(o => o.parameter=="Datum")
.Select()
.Single();
var ordertellerparametergetal = parameterGetalRepository
.Query(o => o.parameter == "orderteller")
.Select()
.Single();
DateTime date = DateTime.Parse(dateparameterGetal.parameterwaarde);
int orderteller=0;
if (date == DateTime.Today)
{
orderteller = int.Parse(ordertellerparametergetal.parameterwaarde);
}
else
{
dateparameterGetal.parameterwaarde = string.Format("{0:dd/MM/yyyy}", DateTime.Today);
orderteller = 0;
}
orderteller++;
ordertellerparametergetal.parameterwaarde = orderteller.ToString();
string result = string.Format("{0}{1:yyyyMMdd}.{2:00}",prefix,DateTime.Today,orderteller);
return result;
}
The thing here is that i am using 2 lambda expressions and that makes it difficult to mock since most solutions i found in stackoverflow work out a solution that is based on ignoring the lambda that is being used.
How do you go about this ?
Note, i have a solution. I will post it as an answer next.
Sometimes for unit testing one has to be pragmatic in the design of the DUT and perhaps add something to the class that is only used in the unit test.
I adapted the class from above to make the lambda expressions variabled and allow access to those expressions via a getter. This way the unit test can access the getter, and hence the mocker can really check which lambda is being passed.
Enough talk here is the code:
public class ReferentieBuilder : IReferentieBuilder
{
private readonly IUnitOfWorkAsync _unitOfWork;
private static readonly Expression<Func<ParameterGetal, bool>> _datumExpression = o => o.parameter=="Datum";
private static readonly Expression<Func<ParameterGetal, bool>> _ordertellerExpression = o => o.parameter == "orderteller";
public ReferentieBuilder(IUnitOfWorkAsync unitOfWork)
{
if (unitOfWork == null)
{
throw new ArgumentNullException("unitOfWork");
}
_unitOfWork = unitOfWork;
}
public static Expression<Func<ParameterGetal, bool>> DatumExpression
{
get { return _datumExpression;}
}
public static Expression<Func<ParameterGetal, bool>> OrderTellerExpression
{
get { return _ordertellerExpression; }
}
public string GetReferentie(string prefix)
{
IRepositoryAsync<ParameterGetal> parameterGetalRepository = _unitOfWork.RepositoryAsync<ParameterGetal>();
Debug.Assert(parameterGetalRepository!=null);
var dateparameterGetal = parameterGetalRepository
.Query(DatumExpression)
.Select()
.Single();
var ordertellerparametergetal = parameterGetalRepository
.Query(OrderTellerExpression)
.Select()
.Single();
DateTime date = DateTime.Parse(dateparameterGetal.parameterwaarde);
int orderteller=0;
if (date == DateTime.Today)
{
orderteller = int.Parse(ordertellerparametergetal.parameterwaarde);
}
else
{
dateparameterGetal.parameterwaarde = string.Format("{0:dd/MM/yyyy}", DateTime.Today);
orderteller = 0;
}
orderteller++;
ordertellerparametergetal.parameterwaarde = orderteller.ToString();
string result = string.Format("{0}{1:yyyyMMdd}.{2:00}",prefix,DateTime.Today,orderteller);
return result;
}
}
see I hadded two static readonly member variables and foreseen static readonly properties as well. DatumExpression and OrderTellerExpression.
The unit test code becomes then something like this :
[TestFixture]
class ReferentieBuilderTests
{
private IUnitOfWorkAsync _unitOfWork;
[SetUp]
public void setup()
{
List<ParameterGetal> dateParameterGetallen = new List<ParameterGetal>
{
new ParameterGetal{ID = 29, parameter = "Datum", parameterwaarde = string.Format("{0:dd/MM/yyyy}", DateTime.Today.AddDays(-1)) }
};
List<ParameterGetal> tellerParameterGetallen = new List<ParameterGetal>
{
new ParameterGetal{ID = 3, parameter = "orderteller", parameterwaarde = "4" }
};
IQueryFluent<ParameterGetal> datefluent = MockRepository.GenerateStub<IQueryFluent<ParameterGetal>>();
IQueryFluent<ParameterGetal> tellerfluent = MockRepository.GenerateStub<IQueryFluent<ParameterGetal>>();
IRepositoryAsync<ParameterGetal> parametergetalrepository = MockRepository.GenerateStub<IRepositoryAsync<ParameterGetal>>();
_unitOfWork = MockRepository.GenerateStub<IUnitOfWorkAsync>();
_unitOfWork.Stub(u => u.RepositoryAsync<ParameterGetal>())
.Return(parametergetalrepository);
parametergetalrepository.Stub(r => r.Query(ReferentieBuilder.DatumExpression))
.Return(datefluent);
parametergetalrepository.Stub(r => r.Query(ReferentieBuilder.OrderTellerExpression))
.Return(tellerfluent);
datefluent.Stub(q => q.Select())
.Return(dateParameterGetallen);
tellerfluent.Stub(q => q.Select())
.Return(tellerParameterGetallen);
}
[Test]
public void GetFirstReferentieOfDay_returnsCorrectReferentie()
{
ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);
string prefix = "P";
DateTime today = DateTime.Today;
string correctReferentie = string.Format("{0}{1:yyyyMMdd}.01", prefix, today);
Assert.AreEqual(correctReferentie,referentieBuilder.GetReferentie(prefix), "Wrong First Referentie");
}
[Test]
public void GetSecondReferentieOfDay_returnsCorrectReferentie()
{
ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);
string prefix = "P";
referentieBuilder.GetReferentie(prefix);
DateTime today = DateTime.Today;
string correctReferentie = string.Format("{0}{1:yyyyMMdd}.02", prefix, today);
Assert.AreEqual(correctReferentie,referentieBuilder.GetReferentie(prefix), "Wrong Second Referentie");
}
[Test]
public void GetThirdReferentieOfDay_returnsCorrectReferentie()
{
ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);
string prefix = "P";
referentieBuilder.GetReferentie(prefix);
referentieBuilder.GetReferentie(prefix);
DateTime today = DateTime.Today;
string correctReferentie = string.Format("{0}{1:yyyyMMdd}.03", prefix, today);
Assert.AreEqual(correctReferentie, referentieBuilder.GetReferentie(prefix), "Wrong Second Referentie");
}
}
The trick here is that the mocks is using ReferentieBuilder.DatumExpression and ReferentieBuilder.OrderTellerExpression and not passing in the same lambda expression in a hardcoded way in the unit test.
This has an extra advantage that there is no duplication.
The code is not that much extra complicated by adding the readonly properties for the lambda expressions that allow the unit test to access.
Please don't judge the logic of the code too much. It is trying to generate a running number that starts at 1 every new day. The last time the function was accessed is stored in the database, and the last number as well. This is as per requirement and i don't like it either.
Using Eugene comment following solution is also possible :
[TestFixture]
class ReferentieBuilderTests
{
private IUnitOfWorkAsync _unitOfWork;
[SetUp]
public void setup()
{
List<ParameterGetal> dateParameterGetallen = new List<ParameterGetal>
{
new ParameterGetal{ID = 29, parameter = "Datum", parameterwaarde = string.Format("{0:dd/MM/yyyy}", DateTime.Today.AddDays(-1)) }
};
List<ParameterGetal> tellerParameterGetallen = new List<ParameterGetal>
{
new ParameterGetal{ID = 3, parameter = "orderteller", parameterwaarde = "4" }
};
IQueryFluent<ParameterGetal> datefluent = MockRepository.GenerateStub<IQueryFluent<ParameterGetal>>();
IQueryFluent<ParameterGetal> tellerfluent = MockRepository.GenerateStub<IQueryFluent<ParameterGetal>>();
IRepositoryAsync<ParameterGetal> parametergetalrepository = MockRepository.GenerateStub<IRepositoryAsync<ParameterGetal>>();
_unitOfWork = MockRepository.GenerateStub<IUnitOfWorkAsync>();
_unitOfWork.Stub(u => u.RepositoryAsync<ParameterGetal>())
.Return(parametergetalrepository);
parametergetalrepository.Stub(r => r.Query(Arg<Expression<Func<ParameterGetal, bool>>>.Matches(a => LambdaCompare.Eq(a, o => o.parameter == "Datum"))))
.Return(datefluent);
parametergetalrepository.Stub(r => r.Query(Arg<Expression<Func<ParameterGetal, bool>>>.Matches(a => LambdaCompare.Eq(a, o => o.parameter == "orderteller"))))
.Return(tellerfluent);
datefluent.Stub(q => q.Select())
.Return(dateParameterGetallen);
tellerfluent.Stub(q => q.Select())
.Return(tellerParameterGetallen);
}
[Test]
public void GetFirstReferentieOfDay_returnsCorrectReferentie()
{
ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);
string prefix = "P";
DateTime today = DateTime.Today;
string correctReferentie = string.Format("{0}{1:yyyyMMdd}.01", prefix, today);
Assert.AreEqual(correctReferentie,referentieBuilder.GetReferentie(prefix), "Wrong First Referentie");
}
[Test]
public void GetSecondReferentieOfDay_returnsCorrectReferentie()
{
ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);
string prefix = "P";
referentieBuilder.GetReferentie(prefix);
DateTime today = DateTime.Today;
string correctReferentie = string.Format("{0}{1:yyyyMMdd}.02", prefix, today);
Assert.AreEqual(correctReferentie,referentieBuilder.GetReferentie(prefix), "Wrong Second Referentie");
}
[Test]
public void GetThirdReferentieOfDay_returnsCorrectReferentie()
{
ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);
string prefix = "P";
referentieBuilder.GetReferentie(prefix);
referentieBuilder.GetReferentie(prefix);
DateTime today = DateTime.Today;
string correctReferentie = string.Format("{0}{1:yyyyMMdd}.03", prefix, today);
Assert.AreEqual(correctReferentie, referentieBuilder.GetReferentie(prefix), "Wrong Second Referentie");
}
}
the lambda expression comparer can be found here :
Most efficient way to test equality of lambda expressions
use the update of the link.
Using this solution, no updates on the DUT are needed, ie no expression readonly properties are required.

xamarin forms cannot implicitly convert type 'system.threading.tasks.task<System.collections.generic list to system.collections.generic List

Hi I am new to programming, but currently I encounter xamarin forms cannot implicitly convert type 'system.threading.tasks.task> to system.collections.generic.List
as I am trying to use global variable upon launching the app to optimized the app
when I am trying to set the List of menu items into the global variable which will be access by the other pages, it gave me that error. I have no idea how to solve that issue so someone please help me
Here is my
App.cs
private static int globalVariable = 1;
public static List<MenuItemModel> foodList = new List<MenuItemModel>();
private static List<MenuItemModel> beverageList = new List<MenuItemModel>();
public static int GlobalVariable
{
get { return globalVariable; }
set { globalVariable = value; }
}
public static List<MenuItemModel> FoodList
{
get { return foodList; }
set { foodList = value; }
}
public static List<MenuItemModel> BeverageList
{
get { return beverageList; }
set { beverageList = value; }
}
public App()
{
GlobalVariable = 10;
BeverageList = getBeverageList();
FoodList = getFoodList();
}
public async Task<List<MenuItemModel>> getBeverageList()
{
ConstantCS constant = new ConstantCS();
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://172.20.129.44/");
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = new HttpResponseMessage();
response = client.GetAsync("WebServices/menu.svc/GetBeveragesJSON").Result;
if (response.IsSuccessStatusCode)
{
string jsonString = await response.Content.ReadAsStringAsync();
dynamic dynamicObject = JsonConvert.DeserializeObject(jsonString);
int itemId_;
string itemName_;
string itemCategory_;
string itemSubCategory_;
string itemDescription_;
string itemImage_;
int itemQuantity_;
double itemPrice_;
string itemStatus_;
string itemAddOn_;
for (int i = 0; i < dynamicObject.d.Count; i++)
{
itemId_ = dynamicObject.d[i]["itemID"];
itemName_ = dynamicObject.d[i]["itemName"].ToString();
itemCategory_ = dynamicObject.d[i]["itemCategory"].ToString();
itemSubCategory_ = dynamicObject.d[i]["itemSubCategory"].ToString();
itemDescription_ = dynamicObject.d[i]["itemDesc"].ToString();
itemImage_ = dynamicObject.d[i]["itemImg"].ToString();
itemQuantity_ = int.Parse(dynamicObject.d[i]["itemQty"].ToString());
itemPrice_ = double.Parse(dynamicObject.d[i]["itemPrice"].ToString());
itemStatus_ = dynamicObject.d[i]["itemStatus"].ToString();
itemAddOn_ = dynamicObject.d[i]["itemRequest"].ToString();
string itemURL_ = constant.PhotoBaseURL + itemImage_;
beverageList.Add(new MenuItemModel(itemId_, itemName_, itemCategory_, itemSubCategory_, itemDescription_, itemURL_, itemQuantity_, itemPrice_, itemStatus_, itemAddOn_));
}
}
else
{
//Debug.WriteLine("It entered else not if");
}
return beverageList;
}
Thanks!
You're not doing anything async in getBeverageList(), so you can safely change its signature to
public List<MenuItemModel> getBeverageList()
After that, you should stop for a few days, and learn about async/await and TPL...

Is there a simpler way to return fields from static function?

I often want to parse a string into various bits and have a readable way to return them.
I like this approach, but it involves creating a specific class
long orderID = Utils.UnTradeIdent(tradeIdent).OrderID;
In Utils.cs:
public class TradeIdentData
{
public string AccountIdent;
public long OrderID;
public string SubID;
}
public static TradeIdentData UnTradeIdent(string tradeIdent)
{
TradeIdentData tradeIdentData = new TradeIdentData();
var parts = tradeIdent.Split('!');
tradeIdentData.AccountIdent = parts[0];
if (parts[1].Contains("."))
{
var bits = parts[1].Split('.');
tradeIdentData.OrderID = long.Parse(bits[1]);
tradeIdentData.SubID = bits[1];
}
else
{
tradeIdentData.OrderID = long.Parse(parts[1]);
tradeIdentData.SubID = "";
}
return tradeIdentData;
}
A separate class with well-named properties (which you are already using) is currently the most readable way of doing this.
In C# 7 you will be able to use tuples for return values, like so:
public static (string AccountIdent, string OrderID, string SubID) UnTradeIdent(string tradeIdent)
{
string accountIdent, orderID, subID ;
... Code to initialise accountIdent, orderID and subID appropriately ...
// Now return the data as a tuple:
return (accountIdent, orderID, subID);
}
You can consume this as follows:
long orderID = Utils.UnTradeIdent(tradeIdent).OrderID;
Or if you want all the values:
var result = Utils.UnTradeIdent(tradeIdent);
// Use result.OrderId, result.SubID or result.AccountIdent
This is not going to be available until some time next year, though.
Also, even though this new tuple support makes it more convenient to WRITE the code, it doesn't let you document it using XML comments as well. Spending the time to write a simple and well-documented class will still often be better than using the new C# 7 tuple support.
See here for more details.
You can also use the out keyword to pass arguments by reference, see MSDN article out (C# Reference):
public static void UnTradeIdent(string tradeIdent, out string AccountIdent, out long OrderID, out string SubID)
{
var parts = tradeIdent.Split('!');
AccountIdent = parts[0];
if (parts[1].Contains("."))
{
var bits = parts[1].Split('.');
OrderID = long.Parse(bits[1]);
SubID = bits[1];
}
else
{
OrderID = long.Parse(parts[1]);
SubID = "";
}
}
UPDATED with suggestion from comments:
public static bool UnTradeIdent(string tradeIdent, out string AccountIdent, out long OrderID, out string SubID)
{
bool result = false;
AccountIdent = "";
OrderID = 0;
SubID = "";
try
{
var parts = tradeIdent.Split('!');
AccountIdent = parts[0];
if (parts[1].Contains("."))
{
var bits = parts[1].Split('.');
OrderID = long.Parse(bits[1]);
SubID = bits[1];
}
else
{
OrderID = long.Parse(parts[1]);
SubID = "";
}
}
catch(ArgumentNullException ane)
{
// Handle parsing exception
}
catch (FormatException fe)
{
// Handle parsing exception
}
catch (OverflowException oe)
{
// Handle parsing exception
}
return result;
}
Its pretty simple to do just by changing the return type to dynamic and using an anonymous class
public static dynamic UnTradeIdent(string tradeIdent)
{
var value1 = //parselogic
var value2 = //parselogic
return new { Identity = value1, Item2 = value2};
}
I would consider making additional static methods. Your current implementation is cleaner when you require all of the returned properties, but something like below might be appropriate when you only need one of them.
public static string TradeIdentToAccountIdent(string tradeIdent)
{
var parts = tradeIdent.Split('!');
return parts[0];
}
public static long TradeIdentToOrderID(string tradeIdent)
{
var parts = tradeIdent.Split('!');
if (parts[1].Contains("."))
{
var bits = parts[1].Split('.');
return long.Parse(bits[1]); // Taken from your example, should probably be bits[0]?
}
else
return long.Parse(parts[1]);
}
// My own take on it this time, you could obviously use your logic as well.
public static string TradeIdentToSubID(string tradeIdent)
{
var order = tradeIdent.Split('!')[1];
if (order.Contains("."))
return order.Split('.')[1];
else
return String.Empty;
}

the binary expression cannot be converted to a predicate expression in LINQ

I want to get the week number of a certain given DateTime.
public static int WeekOf(DateTime? date)
{
if (date.HasValue)
{
GregorianCalendar gCalendar = new GregorianCalendar();
int WeekNumber = gCalendar.GetWeekOfYear(date.Value, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
return WeekNumber;
}
else
return 0;
}
And then I use the above method in:
public static List<ExpressionListDictionary> MyMethod(int weeknr)
{
using (DataAccessAdapter adapter = CreateAdapter())
{
LinqMetaData meta = new LinqMetaData(adapter);
var q = (from i in meta.Test
where WeekOf(i.StartDate) == weeknr
select new ExpressionListDictionary()
{
{"SomeId", i.Id}
}
);
return q.ToList();
}
}
And finally:
List<ExpressionListDictionary> someIDs = MyMethod(weeknr);
/* weeknr = 19 -> step by step debugging */
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: SD.LLBLGen.Pro.ORMSupportClasses.ORMQueryConstructionException: The binary expression '(WeekOf(Convert(EntityField(LPLA_1.StartDate AS StartDate))) == 19)' can't be converted to a predicate expression.
I do get the title error at return q.ToList(); . How can I achieve this?
I haven't ever used the LLBLGen library/framework... But probably this is the same problem that happens with Entity Framework/LINQ-to-SQL: you can't put in a query C# methods: the query must be executed by your db server, not locally, and your db server doesn't know how to execute C# code. So the problem would be in the
**WeekOf(i.StartDate)** == weeknr part of code (that is the only BinaryExpression of your query)
The exception you have posted is quite clear that the point of the error is the one that I have suggested. Then the reason is probably the one I gave you.
Taken from https://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=22861
If you are using SQL Server, that supports DATEPART(isowk, ...) (or if you have MySQL, that supports WEEK(...))
public class SQLFunctionMappings : FunctionMappingStore
{
public SQLFunctionMappings()
{
Add(new FunctionMapping(
typeof(SQLFunctions),
"WeekOf",
1,
"DATEPART(isowk, {0})") // For SQL Server
// "WEEK({0}, 1)") For MySQL
);
}
}
public class SQLFunctions
{
public static int? WeekOf(DateTime? date)
{
return null;
}
}
and then you would use it like:
Where there is the row with LinqMetaData meta = new LinqMetaData(adapter), add:
meta.CustomFunctionMappings = new SQLFunctionMappings();
and change the where:
where SQLFunctions.WeekOf(i.StartDate) == weeknr
Here there is the list of the functions already mapped by llblgen, and how to map other functions.
you can try to Make the method you have WeekOf takes string instead of Datetime?
public static int WeekOf(String dateAsString)
{
//if (!string.IsNullOrEmpty(dateAsString))
if (!dateAsString.equals(string.empty))
{
GregorianCalendar gCalendar = new GregorianCalendar();
int WeekNumber = gCalendar.GetWeekOfYear(date.Value, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
return WeekNumber;
}
else
return 0;
}
And then you use the above below in:
public static List<ExpressionListDictionary> MyMethod(int weeknr)
{
using (DataAccessAdapter adapter = CreateAdapter())
{
LinqMetaData meta = new LinqMetaData(adapter);
var q = (from i in meta.Test
where i.startDate != null && WeekOf(i.StartDate.tostring()) == weeknr
select new ExpressionListDictionary()
{
{"SomeId", i.Id}
}
);
return q.ToList();
}
}
Try something like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MyMethod(5);
}
public static int WeekOf(DateTime? date)
{
if (date.HasValue)
{
GregorianCalendar gCalendar = new GregorianCalendar();
int WeekNumber = gCalendar.GetWeekOfYear(date.Value, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
return WeekNumber;
}
else
return 0;
}
public static List<ExpressionListDictionary> MyMethod(int weeknr)
{
using (DataAccessAdapter adapter = CreateAdapter())
{
LinqMetaData meta = new LinqMetaData(adapter);
List<ExpressionListDictionary> q = (from i in meta.Test
where WeekOf(i.StartDate) == weeknr
select new ExpressionListDictionary()
{
Id = "SomeId"
}
).ToList();
return q;
}
}
public static DataAccessAdapter CreateAdapter()
{
return new DataAccessAdapter();
}
}
public class ExpressionListDictionary
{
public string Id { get; set; }
}
public class LinqMetaData
{
public List<LinqMetaData> Test {get;set;}
public DateTime StartDate {get;set;}
public int Id { get; set; }
public LinqMetaData(DataAccessAdapter adapter)
{
}
}
public class DataAccessAdapter : IDisposable
{
public void Dispose()
{
}
}
}
​

Categories

Resources