I'm making a MessageTemplate in nopCommerce and I want to add a token that implements a method from another class.
In the class "ProductService" I have a method called "DailyBestsellersReport" which I want to add as a token for my MessageTemplate in "MessageTokenProvider". However when I add "ProductService" as a reference in the MessageTokenProvider it tells me the method "DailyBestsellerReport" isn't valid in the current context which have me thinking there's a syntax error somewhere.
This is the method I want to add as token:
ProductService class:
public IList<BestsellersReportLine> DailyBestSellersReport(
int recordsToReturn = 5, int orderBy = 1, int groupBy = 1)
{
var yesterDay = DateTime.Now.Subtract(new TimeSpan(1, 0, 0, 0));
var earliest = new DateTime(yesterDay.Year, yesterDay.Month, yesterDay.Day, 0, 0, 0);
var latest = earliest.Add(new TimeSpan(1, 0, 0, 0, -1));
var currentDay = DateTime.Now;
var dayBefore = DateTime.Now.AddDays(-1);
var query1 = from opv in _opvRepository.Table
where earliest <= currentDay && latest >= dayBefore
join o in _orderRepository.Table on opv.OrderId equals o.Id
join pv in _productVariantRepository.Table on opv.ProductVariantId equals pv.Id
join p in _productRepository.Table on pv.ProductId equals p.Id
select opv;
var query2 = groupBy == 1 ?
//group by product variants
from opv in query1
group opv by opv.ProductVariantId into g
select new
{
EntityId = g.Key,
TotalAmount = g.Sum(x => x.PriceExclTax),
TotalQuantity = g.Sum(x => x.Quantity),
}
:
//group by products
from opv in query1
group opv by opv.ProductVariant.ProductId into g
select new
{
EntityId = g.Key,
TotalAmount = g.Sum(x => x.PriceExclTax),
TotalQuantity = g.Sum(x => x.Quantity),
}
;
switch (orderBy)
{
case 1:
{
query2 = query2.OrderByDescending(x => x.TotalQuantity);
}
break;
case 2:
{
query2 = query2.OrderByDescending(x => x.TotalAmount);
}
break;
default:
throw new ArgumentException("Wrong orderBy parameter", "orderBy");
}
if (recordsToReturn != 0 && recordsToReturn != int.MaxValue)
query2 = query2.Take(recordsToReturn);
var result = query2.ToList().Select(x =>
{
var reportLine = new BestsellersReportLine()
{
EntityId = x.EntityId,
TotalAmount = x.TotalAmount,
TotalQuantity = x.TotalQuantity
};
return reportLine;
}).ToList();
return result;
}
I want to add "DailyBestsellersReport" here:
MessageTokenProvider class
public void AddReportTokens(IList<Token> tokens, BestsellersReportLine DailyBestSellersReport, ProductService productService, int languageId)
{
tokens.Add(new Token("BestsellersReportLine.EntityId", DailyBestSellersReport.EntityId.ToString()));
tokens.Add(new Token("BestsellersReportLine.TotaAmount", DailyBestSellersReport.TotalAmount.ToString()));
tokens.Add(new Token("BestsellersReportLine.TotalQuantity", DailyBestSellersReport.TotalQuantity.ToString()));
tokens.Add(new Token("ProductService.DailyBestSellersReport", productService.DailyBestSellersReport.ToString)());
}
When I add:
tokens.Add(new Token("ProductService.DailyBestSellersReport", productService.DailyBestSellersReport.ToString)());
It tell me:
Error 10 'Nop.Services.Catalog.ProductService.DailyBestSellersReport(int, int, int)' is a 'method', which is not valid in the given context
I've also added tokens from "BestsellersReportLine" class which works fine, however these are properties and not methods like:
public partial class BestsellersReportLine
{
public int EntityId { get; set; }
public decimal TotalAmount { get; set; }
public int TotalQuantity { get; set; }
}
Any thoughts?
Thank you
The error itself tells the solution how can you call a method without passing any arguments to it when it accepts parameters.
You will need to write method which returns string depending on result in of productService.DailyBestSellersReport
public string ReturnTable()
{
var report = productService.DailyBestSellersReport(param1,param2,param2)
StringBuilder sb = new StringBuilder();
foreach (var r in report)
{
// I believe you are trying to build HTML table so you can append any string here to sb
}
return sb.ToString();
}
Then use
tokens.Add(new Token("ProductService.DailyBestSellersReport",ReturnTable());
sb.AppendLine("<table border=\"0\" style=\"width:100%;\">");//sb is stringbuilder's object
sb.AppendLine(string.Format("<tr style=\"background-color:{0};text-align:center;font-size:12px; \">", _templatesSettings.Color1));
sb.AppendLine(string.Format("<th>Sr. No.</th>"));
sb.AppendLine(string.Format("<th>Item1</th>"));
sb.AppendLine(string.Format("<th>Item2</th>"));
sb.AppendLine("</tr>");
// Header is closed
// Next is data which will be created using foreach on data from `IList<BestsellersReportLine>`
foreach (var item in result)
{
sb.AppendLine(string.Format("<tr style=\"background-color: {0};text-align: center;\">", _templatesSettings.Color2));
// you can place all your data in below tds, you can create any number of tds.
sb.AppendLine(string.Format("<td style=\"padding: 0.6em 0.4em;text-align: right;\">{0}</td>", item.Prop1));
sb.AppendLine("<td style=\"padding: 0.6em 0.4em;text-align: left;\">" + item.Prop2);
sb.AppendLine("</td>");
sb.AppendLine("</tr>");
}
sb.AppendLine("</table>"); // don't forget to close table
return sb.ToString();
Related
Good Day To you all
I have issue with using 'predicate'
I'm trying to make function to return the results of some search text
here is the body of the function
public List<SaddadVM> GetAllBills(int Page = 1, int Take = 10, int? SearchField = null, string SearchItem = null)
{
var predicate = PredicateBuilder.New<SaddadVM>();
if (!string.IsNullOrWhiteSpace(SearchItem))
{
predicate = predicate.And(x => x.BillAcct == SearchItem);
}
predicate = predicate.And(x => x.Id != 0);
var bill = (from d in _context.Saddad
join R in _context.Requests on d.ReqId equals R.Id
join l in _context.Documenter on R.DocumenterId equals l.Id
where d.RecordStatus != GeneralEnums.RecordStatus.Deleted
select new SaddadVM
{
BillAcct = d.BillAcct,
ReqID = d.ReqId,
DocName = l.FullName,
DueDt = d.DueDt,
BillAmount = d.BillAmount
}).Where(predicate).Skip((Page - 1) * Take).Take(Take).ToList();
return bill;
}
Knowing that the the Bill object should return at least 2 depending on running the same query on DB as follows :
enter image description here
I am trying to convert below SQL to LINQ query and I am stuck with filtering results using the Match in Left outer Join.
SELECT #batchID , IQ1.ID, #environment , 'IRD', IQ1.ReportingDate, IQ1.Match
FROM (
SELECT TD.*, RD.Match
FROM TransactionDetail TD
INNER JOIN .dbo.Measure M ON M.InternalID = TD.MetricCode-- and TD.BatchID = 'e07f9855-b286-4406-9189-5cfb2a7914c8'
LEFT OUTER JOIN (
SELECT tmp.ID, tmp.ReportingDate, 1 AS Match
FROM tmp
) AS RD ON RD.ID = M.Frequency AND RD.ReportingDate = TD.ReportingDate
WHERE RD.Match IS NULL AND
TD.BatchID = #batchID AND
NOT EXISTS (SELECT TransactionFailureReasonID FROM TransactionDetailFailureReasons R WHERE R.TransactionDetailID = TD.ID and R.TransactionFailureReasonID = 'NRD') AND
NOT EXISTS (SELECT TransactionFailureReasonID FROM TransactionDetailFailureReasons R WHERE R.TransactionDetailID = TD.ID and R.TransactionFailureReasonID = 'RDP') AND
NOT EXISTS (SELECT TransactionFailureReasonID FROM TransactionDetailFailureReasons R WHERE R.TransactionDetailID = TD.ID and R.TransactionFailureReasonID = 'RDF')
) AS IQ1
I have so far achieved below,
// Prepare data for left outer join
var rd = (from tt in result
select new { ID = tt.Id, tt.ReportingDate });
// inner join
var td = TransactionDetail.Join(
MesureTb,
t => t.MetricCode,
m => m.InternalId,
(t, m) => new
{
t.Id,
t.RowAction,
t.BatchId,
t.TrustCode,
t.MetricCode,
t.ReportingDate,
t.Value,
t.UpperBenchmark,
t.LowerBenchmark,
m.InternalId,
Frequency = m.Frequency
});
// left outer join
var failureTransactionDetail = (from p in td
join q in rd on new { ReportingDate = (DateTime)p.ReportingDate, ID = p.Frequency } equals new { q.ReportingDate, q.ID }
into LJ
//select new { p.Id, p.BatchId, p.ReportingDate, RD = q.ReportingDate, q.ID, p.Frequency });
from value in LJ.DefaultIfEmpty()
//where p.BatchId == batchId
select new {p.BatchId, p.Id, Match = 1, p.ReportingDate } into DJ
// LEFT OUTER JOIN
where DJ.BatchId == batchId
////&& DJ.Match == 0
&& !(TransactionDetailFailureReasons.Any(m => m.TransactionDetailId == DJ.Id && m.TransactionFailureReasonId == "NRD"))
&& !(TransactionDetailFailureReasons.Any(m => m.TransactionDetailId == DJ.Id && m.TransactionFailureReasonId == "RDP"))
&& !(TransactionDetailFailureReasons.Any(m => m.TransactionDetailId == DJ.Id && m.TransactionFailureReasonId == "RDF"))
select new { DJ.Id, DJ.ReportingDate, DJ.BatchId } );
My question being how i can achieve similar result as 1 AS Match does in SQL in Linq.
Could someone please guide me? Currently the SQL query returns 2 results based on Match value as null, but the LInq returns 8 results since it is not filtering the Match on Left join.
Any help is much appreciated.
Thanks in advance.
I'm just taking a stab at helping you out here because the question is a little unclear. But just comparing your sql statement to your linq query I can see that you may be trying to filter where: RD.Match IS NULL? If that assumption is correct then there is problem with your linq query.
Given the following objects:
public class TransactionDetail
{
public TransactionDetail(int id,
int batchId,
int metricCode,
DateTime reportingDate)
{
Id = id;
BatchId = batchId;
MetricCode = metricCode;
ReportingDate = reportingDate;
}
public int Id { get; }
public int BatchId { get; }
public int MetricCode { get; }
public DateTime ReportingDate { get; }
}
public class Measure
{
public Measure(int internalId,
int frequency)
{
InternalId = internalId;
Frequency = frequency;
}
public int InternalId { get; }
public int Frequency { get; }
}
public class Tmp
{
public Tmp(int id,
DateTime reportingDate)
{
Id = id;
ReportingDate = reportingDate;
}
public int Id { get; }
public DateTime ReportingDate { get; }
}
Sample Code:
static void Main(string[] args)
{
var transactionDetails = new List<TransactionDetail>
{
new TransactionDetail(id: 1, batchId: 1, metricCode: 1, reportingDate: new DateTime(2019, 1, 1)),
new TransactionDetail(id: 2, batchId: 1, metricCode: 2, reportingDate: new DateTime(2019, 1, 1))
};
var matches = new List<Measure>
{
new Measure(internalId: 1, frequency: 1),
new Measure(internalId: 2, frequency: 3)
};
var temporaryList = new List<Tmp>
{
new Tmp(1, new DateTime(2019, 1, 1)),
};
var transDetails = transactionDetails.Join(
matches,
t => t.MetricCode,
m => m.InternalId,
(t, m) => new
{
t.Id,
t.BatchId,
t.MetricCode,
t.ReportingDate,
m.InternalId,
m.Frequency
})
.ToList();
var failureTransactionDetail = transDetails
.GroupJoin(temporaryList,
trandetail => new { trandetail.ReportingDate, Id = trandetail.Frequency },
tmp => new { tmp.ReportingDate, tmp.Id },
(trandetail, tmp) => new { trandetail, tmp })
.SelectMany(t => t.tmp.DefaultIfEmpty(), (t, value) => new { t, value, Matches = 1 })
.Where(arg => !arg.t.tmp.Any());
Console.WriteLine(JsonConvert.SerializeObject(failureTransactionDetail, Formatting.Indented));
Console.ReadLine();
}
Examine the output and you'll see that you don't need Match = 1. .Where(arg => !arg.t.tmp.Any()) would be the equivalent to RD.Match IS NULL in your sql query.
Hope that puts you in the right direction.
I have a LINQ statement which returns an IQueryable of the class below.
Class:
public class SupplierSummaryReport {
public int Year { get; set; }
public string SupplierName { get; set; }
public decimal TurnOverValues { get; set; }
}
Eg: {2012,Supplier1,90},{2011,Supplier2,95}
However, I then need to convert this data into a Dictionary of Dictionaries. I have the extension method which me and a friend have built, however we are stumped at the final section.
Extension Method:
public static Dictionary<TFirstKey, Dictionary<TSecondKey, TValue>> Pivot<TSource, TFirstKey, TSecondKey, TValue>(this IEnumerable<TSource> source, Func<TSource, TFirstKey> firstKeySelector, Func<TSource, TSecondKey> secondKeySelector, Func<TSource, TValue> Value) {
var retVal = new Dictionary<TFirstKey, Dictionary<TSecondKey, TValue>>();
var l = source.ToLookup(firstKeySelector);
foreach (var item in l) {
var dict = new Dictionary<TSecondKey, TValue>();
retVal.Add(item.Key, dict);
var subdict = item.ToLookup(secondKeySelector);
foreach (var subitem in subdict) {
dict.Add(subitem.Key, subitem.Value /*Insert value here*/);
}
}
return retVal;
}
We call the method like so:
public Dictionary<string,Dictionary<int,decimal>> GetSupplierSummaryReportData(List<int> last5Years) {
_ctx.Database.CommandTimeout = 5 * 60;
//values - Gets the data required for the Supplier summary report in a hierachical order. E.g - {2012,Supplier1,3},{2011,Supplier1,4}
var values = (from i in _ctx.Invoices
where i.Turnover == true
group i by new { i.AccountName, i.InvoiceDate.Year } into summ
select new APData.Audit.Models.ReportModels.SupplierSummaryReport {
Year = summ.Key.Year,
SupplierName = summ.Key.AccountName,
TurnOverValues = summ.Sum(r => r.VATAmount_Home ?? 0)
});
//accounts - Get all the account names
var accounts = (from i in _ctx.Invoices
where i.Turnover == true
group i by new { i.AccountName } into summ
select new {
summ.Key.AccountName
});
/*crossJoin - select all SupplierNames from accounts and all years from last5Years and assign each SupplierName the last 5 years. Assign each turnover value null for each year.
This is in preparation for the cross join as not all suppliers will have the last 5 year in data */
var crossJoin = accounts.SelectMany(a => last5Years, (a, y) => new APData.Audit.Models.ReportModels.SupplierSummaryReport {
Year = y,
SupplierName = a.AccountName,
TurnOverValues = 0
});
/*Join crossJoin and values together, wherever the join is empty, assign the cross join values. If not assign the turnover value from a*/
var result =
(from cj in crossJoin
join v in values
on new { cj.Year, cj.SupplierName }
equals new { v.Year, v.SupplierName } into lJoin
from a in lJoin.DefaultIfEmpty(new APData.Audit.Models.ReportModels.SupplierSummaryReport {
Year = cj.Year,
SupplierName = cj.SupplierName,
TurnOverValues = cj.TurnOverValues
})
select new APData.Audit.Models.ReportModels.SupplierSummaryReport {
Year = cj.Year,
SupplierName = cj.SupplierName,
TurnOverValues = a.TurnOverValues
}).OrderBy(r => r.SupplierName).ThenBy(r => r.Year);
return result.Pivot(r => r.SupplierName, c => c.Year, y => y.TurnOverValues);
We need to insert the decimal value of TurnOverValues as the third item in the dictionary.
Expected outcome:
{Supplier1, {2012,60}}, {Supplier2, {2014,90}}
If anyone needs anymore information, please let me know.
TL;DR, but if what you have is an IEnumerable<SupplierSummaryReport> and you're sure that each SupplierName, Year, TurnOver combination is unique or can be made unique then ToDictionary makes this easy:
var data = new List<SupplierSummaryReport> { ... };
// avoiding var just to verify correct result Type
Dictionary<string, Dictionary<int, decimal>> result = data
.GroupBy(ssr => ssr.SupplierName)
.ToDictionary(g1 => g1.Key, g1 => (
g1.GroupBy(g2 => g2.Year)
.ToDictionary(g3 => g3.Key,
g3 => g3.First().TurnOverValues))
);
Maybe the g3.First() should become .Single() or .Sum() or something.
Trying to figure out why this method isn't returning the items within the timespan I specified with some DateTime variables. I do get a result but it makes no sense and provide incorrect values.
The method is supposed to return all bestsellers from yesterday (the past 24 hours). However it seems that the method returns all bestsellers that have been sold since the beginning. In the Database there's a column called "CreatedOnUtc" wich provide a date, guess this could be used as a date to test but i don't know how to access it as it's in another class.
public IList<BestsellersReportLine> DailyBestsellersReport()
{
int recordsToReturn = 5; int orderBy = 1; int groupBy = 1;
var yesterDay = DateTime.Now.Subtract(new TimeSpan(1, 0, 0, 0));
var earliest = new DateTime(yesterDay.Year, yesterDay.Month, yesterDay.Day, 0, 0, 0);
var latest = earliest.Add(new TimeSpan(1, 0, 0, 0, -1));
var currentDay = DateTime.Now;
var dayBefore = DateTime.Now.AddDays(-1);
var query1 = from opv in _opvRepository.Table
where earliest <= currentDay && latest >= dayBefore
join o in _orderRepository.Table on opv.OrderId equals o.Id
join pv in _productVariantRepository.Table on opv.ProductVariantId equals pv.Id
join p in _productRepository.Table on pv.ProductId equals p.Id
select opv;
var query2 = groupBy == 1 ?
//group by product variants
from opv in query1
where earliest <= currentDay && latest >= dayBefore
group opv by opv.ProductVariantId into g
select new
{
EntityId = g.Key,
TotalAmount = g.Sum(x => x.PriceExclTax),
TotalQuantity = g.Sum(x => x.Quantity),
}
:
//group by products
from opv in query1
where earliest <= currentDay && latest >= dayBefore
group opv by opv.ProductVariant.ProductId into g
select new
{
EntityId = g.Key,
TotalAmount = g.Sum(x => x.PriceExclTax),
TotalQuantity = g.Sum(x => x.Quantity),
}
;
switch (orderBy)
{
case 1:
{
query2 = query2.OrderByDescending(x => x.TotalQuantity);
}
break;
case 2:
{
query2 = query2.OrderByDescending(x => x.TotalAmount);
}
break;
default:
throw new ArgumentException("Wrong orderBy parameter", "orderBy");
}
if (recordsToReturn != 0 && recordsToReturn != int.MaxValue)
query2 = query2.Take(recordsToReturn);
var result = query2.ToList().Select(x =>
{
var reportLine = new BestsellersReportLine()
{
EntityId = x.EntityId,
TotalAmount = x.TotalAmount,
TotalQuantity = x.TotalQuantity
};
return reportLine;
}).ToList();
return result;
}
There is a similar method wich has specified startTime and endTime, i believe it searches the database within a time record. Allthough this method is displayed in a view with choosable startDate/endDate in textboxes. However i need the time record for DailyBestsellersReport to be specified in the code as this will be a process running in the background.
Here is a similar period with DateTime parameteers:
public virtual IList<BestsellersReportLine> BestSellersReport(DateTime? startTime,
DateTime? endTime,int recordsToReturn = 5, int orderBy = 1, int groupBy = 1)
{
some code...
}
Any thoughts?
where earliest <= currentDay && latest >= dayBefore
It's useless condition, it's allways true.
You need test for some 'time' fields from DB, if u want to filter your db records.
Update
I suposed, that you have OrderDate column in _orderRepository.Table
than you snippet can be transformed into something like bellow:
var currentTime = DateTime.Now;
var today = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, 0, 0, 0);
var yesterDay = today.Subtract(new TimeSpan(1, 0, 0, 0));
//suppose, that we gather all data for yesterday
var query1 = from opv in _opvRepository.Table
join o in _orderRepository.Table on opv.OrderId equals o.Id
join pv in _productVariantRepository.Table on opv.ProductVariantId equals pv.Id
join p in _productRepository.Table on pv.ProductId equals p.Id
where yesterDay <= o.OrderDate && today >= o.OrderDate
select opv;
var query2 = groupBy == 1 ?
//group by product variants
from opv in query1
group opv by opv.ProductVariantId into g
select new
{
EntityId = g.Key,
TotalAmount = g.Sum(x => x.PriceExclTax),
TotalQuantity = g.Sum(x => x.Quantity),
}
:
//group by products
from opv in query1
group opv by opv.ProductVariant.ProductId into g
select new
{
EntityId = g.Key,
TotalAmount = g.Sum(x => x.PriceExclTax),
TotalQuantity = g.Sum(x => x.Quantity),
}
;
I'm working on creating a custom task in NopCommerce that lists most sold products of the day and show this data in the admin panel. E g lists all products that has been sold and order them by number of sold.
Iv'e found some code that runs a BestSeller report which is great, allthough this method is quite large and i'm uncertain which part i actually need in order to display the list of bestsellers. Also the method for bestsellers is a "virtual IList and the execute method is void.
This is the code for bestsellers:
class MostSoldProductsTask : ITask
{
private readonly IRepository<Order> _orderRepository;
private readonly IRepository<OrderProductVariant> _opvRepository;
private readonly IRepository<Product> _productRepository;
private readonly IRepository<ProductVariant> _productVariantRepository;
private readonly IDateTimeHelper _dateTimeHelper;
private readonly IProductService _productService;
public virtual IList<BestsellersReportLine> BestSellersReport(DateTime? startTime,
DateTime? endTime, OrderStatus? os, PaymentStatus? ps, ShippingStatus? ss,
int billingCountryId = 0,
int recordsToReturn = 5, int orderBy = 1, int groupBy = 1, bool showHidden = false)
{
int? orderStatusId = null;
if (os.HasValue)
orderStatusId = (int)os.Value;
int? paymentStatusId = null;
if (ps.HasValue)
paymentStatusId = (int)ps.Value;
int? shippingStatusId = null;
if (ss.HasValue)
shippingStatusId = (int)ss.Value;
var query1 = from opv in _opvRepository.Table
join o in _orderRepository.Table on opv.OrderId equals o.Id
join pv in _productVariantRepository.Table on opv.ProductVariantId equals pv.Id
join p in _productRepository.Table on pv.ProductId equals p.Id
where (!startTime.HasValue || startTime.Value <= o.CreatedOnUtc) &&
(!endTime.HasValue || endTime.Value >= o.CreatedOnUtc) &&
(!orderStatusId.HasValue || orderStatusId == o.OrderStatusId) &&
(!paymentStatusId.HasValue || paymentStatusId == o.PaymentStatusId) &&
(!shippingStatusId.HasValue || shippingStatusId == o.ShippingStatusId) &&
(!o.Deleted) &&
(!p.Deleted) &&
(!pv.Deleted) &&
(billingCountryId == 0 || o.BillingAddress.CountryId == billingCountryId) &&
(showHidden || p.Published) &&
(showHidden || pv.Published)
select opv;
var query2 = groupBy == 1 ?
//group by product variants
from opv in query1
group opv by opv.ProductVariantId into g
select new
{
EntityId = g.Key,
TotalAmount = g.Sum(x => x.PriceExclTax),
TotalQuantity = g.Sum(x => x.Quantity),
}
:
//group by products
from opv in query1
group opv by opv.ProductVariant.ProductId into g
select new
{
EntityId = g.Key,
TotalAmount = g.Sum(x => x.PriceExclTax),
TotalQuantity = g.Sum(x => x.Quantity),
}
;
switch (orderBy)
{
case 1:
{
query2 = query2.OrderByDescending(x => x.TotalQuantity);
}
break;
case 2:
{
query2 = query2.OrderByDescending(x => x.TotalAmount);
}
break;
default:
throw new ArgumentException("Wrong orderBy parameter", "orderBy");
}
if (recordsToReturn != 0 && recordsToReturn != int.MaxValue)
query2 = query2.Take(recordsToReturn);
var result = query2.ToList().Select(x =>
{
var reportLine = new BestsellersReportLine()
{
EntityId = x.EntityId,
TotalAmount = x.TotalAmount,
TotalQuantity = x.TotalQuantity
};
return reportLine;
}).ToList();
return result;
}
public void Execute()
{
throw new NotImplementedException("Return something");
}
I also have to return this list via the "Execute" -method that is implementing the ITask interface. My best guess is to have one method creating the list of bestsellers and have have the "Execute method implementing the first one and return it.
Thank you
I believe you misunderstood the purpose if ITask interface. ITask is used to run some background, non-UI tasks, so you can never get it to 'return' the list in admin panel.
What you want to do, instead, is to run it periodically and save the data in some custom table. Then use it