泛型静态类 & function作为参数
/// <summary> /// /// </summary> /// <typeparam name="OD">original datas type:get from proxy api</typeparam> /// <typeparam name="SD">save datas type</typeparam> public static class ReportOperation<OD,SD> where OD : class where SD : class { static int _syncCallApiMaxNum= ConfigHelper.SyncCallApiMaxNum; static int _MaxSaveDataNum = ConfigHelper.MaxSaveDataNum; static string OriginalDatasType = typeof(OD).FullName; static string SaveDatasType = typeof(SD).FullName; private static bool TaskSplitForSave(List<ReportSaveTask<SD>> taskList, ILogBase _logger) { bool saveResult = true; try { _logger.Info($"TaskSplitForSave.SaveDatasType:{SaveDatasType};"); if (taskList == null || taskList.Count() == 0) { return false; } int index = 0; int sumNum = taskList.Count(); int syncCallApiNum = sumNum > 0 ? _syncCallApiMaxNum : sumNum; while (index < sumNum) { List<ReportSaveTask<SD>> temp = new List<ReportSaveTask<SD>>(); syncCallApiNum = syncCallApiNum > sumNum - index ? sumNum - index : syncCallApiNum; temp = taskList.GetRange(index, syncCallApiNum); index = index + syncCallApiNum; System.Threading.Thread.Sleep(5000); foreach (var oneT in temp) { _logger.Info($"start save Report datas to database. start:{index},num:{syncCallApiNum},request:{JsonConvert.SerializeObject(oneT.Data)}"); oneT.SaveResult.Start(); } Task.WaitAll(temp.Select(each => each.SaveResult).ToArray()); foreach (var teskOne in temp) { var saveTempResult = teskOne.SaveResult.Result; saveResult = saveResult && saveTempResult; if (!saveTempResult) { _logger.Warn($"failed to async Report datas to database!,request:{JsonConvert.SerializeObject(teskOne.Data)}"); } else { _logger.Info($"report datas to DB successed!,request:{JsonConvert.SerializeObject(teskOne.Data)}"); } } } _logger.Info($"TaskSplitForSave result:{JsonConvert.SerializeObject(saveResult)};"); return saveResult; } catch (Exception ex) { _logger.Error($"ProxyReportCallSplit:{ex.ToString()}"); throw ex; } } private static List<ReportSaveTask<SD>> DataSplitForSave(List<SD> reportDB,Func<List<SD>,bool> saveOperate, ILogBase _logger) { List<ReportSaveTask<SD>> taskList = new List<ReportSaveTask<SD>>(); try { _logger.Info($"DataSplitForSave request.reportDB:{JsonConvert.SerializeObject(reportDB)};"); if (reportDB == null || reportDB.Count() == 0) { return null; } int index = 0; int sumNum = reportDB.Count(); int eachInsert = sumNum > 0 ? _MaxSaveDataNum : sumNum; while (index < sumNum) { List<SD> temp = new List<SD>(); eachInsert = eachInsert > sumNum - index ? sumNum - index : eachInsert; temp = reportDB.GetRange(index, eachInsert); index = index + eachInsert; var taskTemp = new Task<bool>(()=>saveOperate(temp));//_FacebookReportClient.Save(temp) taskList.Add(new ReportSaveTask<SD>() { SaveResult = taskTemp, Data = temp }); } return taskList; } catch (Exception ex) { _logger.Error($"save datas to DB error:{ex.ToString()},request:{JsonConvert.SerializeObject(reportDB)}"); throw ex; } } public static bool ProxyApiSplitToCall(List<Task<List<OD>>> taskList,Func<List<OD>,List<SD>> DateConvertToDB, Func<List<SD>,bool> saveOperate, ILogBase _logger) { bool result = true; try { _logger.Info($"ProxyApiSplitToCall"); if (taskList == null || taskList.Count() == 0) { return false; } int index = 0; int sumNum = taskList.Count(); int syncCallApiNum = sumNum > 0 ? _syncCallApiMaxNum : sumNum; while (index < sumNum) { syncCallApiNum = syncCallApiNum > sumNum - index ? sumNum - index : syncCallApiNum; List<Task<List<OD>>> temp = taskList.GetRange(index, syncCallApiNum); index = index + syncCallApiNum; System.Threading.Thread.Sleep(5000); foreach (var oneT in temp) { oneT.Start(); } Task.WaitAll(temp.ToArray()); #region save data List<OD> allReports = new List<OD>(); CommandHelper.UnionAllTaskResult<OD>(temp, ref allReports); if (allReports == null || allReports.Count() == 0) { _logger.Warn($"no datas can get from proxy call![{JsonConvert.SerializeObject(allReports)}]"); continue; } _logger.Info($"datas get from proxy call:{JsonConvert.SerializeObject(allReports)}"); List<SD> reportDB = DateConvertToDB(allReports); if (reportDB == null || reportDB.Count() == 0) { _logger.Warn($"no datas need to be created or updated:{JsonConvert.SerializeObject(reportDB)}"); continue; } _logger.Info($"datas need to be save :{JsonConvert.SerializeObject(reportDB)}"); List<ReportSaveTask<SD>> DataSaveT= DataSplitForSave(reportDB, saveOperate, _logger); bool saveResult = TaskSplitForSave(DataSaveT, _logger); _logger.Info($"datas save result:{JsonConvert.SerializeObject(saveResult)}"); #endregion result = result & saveResult; } return result; } catch (Exception ex) { _logger.Error($"ProxyReportCallSplit:{ex.ToString()}"); throw ex; } } }
静态类的使用
bool saveResult = ReportOperation<FacebookDailyReportConvertFromClient, FacebookImpressDeviceReport>.ProxyApiSplitToCall(taskList, dataConvertFunc, dataSaveFunc, _logger);
function作为参数的使用
Func<List<FacebookDailyReportConvertFromClient>, List<FacebookImpressDeviceReport>> dataConvertFunc = (originalData) => { return DateConvertToDB(originalData, accounts); }; Func<List<FacebookImpressDeviceReport>, bool> dataSaveFunc = (saveDB) => { return SaveReportsToDB(saveDB); }; bool saveResult = ReportOperation<FacebookDailyReportConvertFromClient, FacebookImpressDeviceReport>.ProxyApiSplitToCall(taskList, dataConvertFunc, dataSaveFunc, _logger);
泛型抽象类:
/// <summary> /// get reoports from proxy client /// </summary> /// <typeparam name="RQ">request type</typeparam> /// <typeparam name="RP">response list type</typeparam> /// <typeparam name="CRQ">proxy client request type</typeparam> /// <typeparam name="CRP">proxy client response type</typeparam> public abstract class ReportDownloadBase<RQ, RP,CRQ,CRP> where RQ : class where RP : class where CRQ : class where CRP : class { protected string exportPath; protected System.Collections.Specialized.NameValueCollection appSettings; protected ILogBase _logger; protected string _plantform; public ReportDownloadBase(ILogBase logger,string plantform) { _plantform = plantform; appSettings = WestWin.Common.Configuration.ConfigurationManager.Default.AppSettings; exportPath = Path.Combine(System.IO.Directory.GetCurrentDirectory(), appSettings["ReportRawPath"], plantform); _logger = logger; } /// <summary> /// Generate ReportRequest for proxy client /// </summary> /// <param name="req">request</param> /// <returns></returns> protected abstract CRQ GenerateReportRequest(RQ req); /// <summary> /// Generate Results to return /// </summary> /// <param name="resp">ReportResponse</param> /// <param name="breakdownValue">breakdownValue </param> /// <returns>result list</returns> protected abstract List<RP> GenerateResultsByReportResponse(CRP resp, RQ req); /// <summary> /// get client response from client request /// </summary> /// <param name="req"></param> /// <returns></returns> protected abstract CRP GetResponseFromRequest(CRQ req); /// <summary> /// Get Results By Request /// </summary> /// <param name="request"></param> /// <param name="breakdownValue"></param> /// <returns></returns> protected List<RP> Process(RQ request,string breakdownValue) { try { _logger.Info($"{_plantform} GetReport request:{JsonConvert.SerializeObject(request)}"); var req = GenerateReportRequest(request); _logger.Info($"{_plantform} proxy client request:{JsonConvert.SerializeObject(req)}"); CRP response = null; int maxTry = ConfigHelper.ApiTryMaxNum; int count = 0; while (count < maxTry) { count++; response = null; try { response = GetResponseFromRequest(req); } catch (Exception e) { _logger.Error($"{_plantform} proxy client get report failed:Round {count}", e); if(count== maxTry) { _logger.Error($"{_plantform} proxy client get report: exception & retry time:{count}", e); throw e; } } if (response != null) break; _logger.Warn($"{_plantform} proxy client get report failed:retry Num: {count},request:{JsonConvert.SerializeObject(req)}"); System.Threading.Thread.Sleep(5000); } if (response == null) { return null; } _logger.Info($"{_plantform} proxy client Get Report sucess:{JsonConvert.SerializeObject(response)}"); var result = GenerateResultsByReportResponse(response, request); _logger.Info($"{_plantform} return Report result:{JsonConvert.SerializeObject(result)}"); CommandHelper.CreateDictionaryIfNotExists(exportPath); if (result == null || result.Count == 0) { _logger.Warn($"{_plantform} return empty result for request:{JsonConvert.SerializeObject(req)}"); } else { var path = Path.Combine(exportPath, $"{_plantform}-row-{breakdownValue}-{DateTime.Now.ToString("yyyyMMddHHmmss")}-{Guid.NewGuid().ToString()}.csv"); bool saveSucess = CommandHelper.SaveDataToCSVFile<RP>(result, path); _logger.Info($"{_plantform} report save local file result:{saveSucess}"); } return result; } catch (Exception ex) { _logger.Error($"exception. request.request: {JsonConvert.SerializeObject(request)}; request.breakdownValue: {JsonConvert.SerializeObject(breakdownValue)};error:{ex.ToString()}"); throw ex; } } }
被使用:
public class FacebookCountryCmd : ReportDownloadBase<FacebookDailyReportEachRequest, FacebookDailyReportConvertFromClient, FacebookGetAdsInsightRequest, FacebookGetAdsInsightsResponse>, IFacebookCountryCmd { IFacebookCountryReportService _facebookCountryReportService; IFacebookProxyService _FacebookProxyClient; IAccountCampaignOperation _campaignOperation; IFacebookCampaignHelper _facebookCampaignHelper; Platform.Service.Enterprise.AccountChannel _accountChannel = Platform.Service.Enterprise.AccountChannel.Facebook; Dictionary<string, FacebookSearchAdgeolocationEntity> _countryDic=new Dictionary<string, FacebookSearchAdgeolocationEntity>(); public FacebookCountryCmd(ILogBase logger, IFacebookCountryReportService facebookCountryReportService, IAccountCampaignOperation campaignOperation, IFacebookProxyService FacebookProxyClient,IFacebookCampaignHelper facebookCampaignHelper) : base(logger, "facebook") { _facebookCountryReportService = facebookCountryReportService; _FacebookProxyClient = FacebookProxyClient; _campaignOperation = campaignOperation; _facebookCampaignHelper = facebookCampaignHelper; GetAllCountry(); } public List<FacebookCountryReport> DateConvertToDB(List<FacebookDailyReportConvertFromClient> reportDatas, List<BusinessAdsPlatformAccountDetail> accounts) { //***** } public void Execute(FacebookCmdOptions opt) { //***** } public bool SaveReportsToDB(List<FacebookCountryReport> reportDB) { //**** } protected override FacebookGetAdsInsightRequest GenerateReportRequest(FacebookDailyReportEachRequest req) { //**** } protected override List<FacebookDailyReportConvertFromClient> GenerateResultsByReportResponse(FacebookGetAdsInsightsResponse response, FacebookDailyReportEachRequest req) { //*** } protected override FacebookGetAdsInsightsResponse GetResponseFromRequest(FacebookGetAdsInsightRequest req) { //**** } private bool IfNextPage(FacebookGetAdsInsightsResponse response, ref FacebookGetAdsInsightRequest request) { //**** } }
public interface IFacebookCountryCmd: IReportCmdBase<FacebookCountryReport, FacebookCmdOptions, FacebookDailyReportConvertFromClient> { }
/// <summary> /// execute download report /// </summary> /// <typeparam name="RDB">report type define by DB</typeparam> /// <typeparam name="CMD">command type</typeparam> /// <typeparam name="RP">report response including all data get from proxy client</typeparam> public interface IReportCmdBase<RDB,CMD,RP> where RDB : class where CMD:class where RP:class { /// <summary> /// Save Reports To DB /// </summary> /// <param name="reportDB"></param> /// <returns></returns> bool SaveReportsToDB(List<RDB> reportDB); /// <summary> /// convert report to match datebase define /// </summary> /// <param name="reportDatas"></param> /// <returns></returns> List<RDB> DateConvertToDB(List<RP> reportDatas, List<BusinessAdsPlatformAccountDetail> accounts); /// <summary> /// Execute Download Report :get from proxy client api & save original data to local file & save to DB /// </summary> /// <param name="opt">command</param> void Execute(CMD opt); }