Use Case: (Earlier Pattern) Customizing application logic of SyteLine IDO hand-coded method that used Composition Root (deprecated)
Scope:Logic exists only in .NET. Similar scenarios exist as EXTGEN.
Category:Full Code
Tier:OB
Notes: OB - copied extensibility - merging required
Using Rpt_InventoryCost for this simple example, with the customization in this case being to replace a bound column with a literal such that Cost Method description will display as βStdβ for non-lot-tracked items. The base class containing the logic is in Rpt_InventoryCostCRUD class. This use case describes a change that minimizes the amount of code of which to take ownership.
- Create an IDO that extends SLInventoryCostReport IDO (see Mongoose documentation β the typical process involves selecting or creating an IDO Project required during new IDO creation).
- Create a new IDO Method.
- Copy SyteLine method parameters.
- Extension Class Code Changes (base code is located within SDK)
- Sample of custom code included after code descriptions
- New custom project: Custom_InventoryCostReport
- For this example, custom project is created for the entire report.
- Copy of Rpt_InventoryCostCRUD.cs: Custom_Rpt_InventoryCostCRUD.cs
- Changes
- Namespace: Custom_InventoryCostReport
- Customization: Change in 1 method: SelectInsert_Tv_ItemGeneral
- Could take over entire class or in this example, took
over one method of class
- Use base code for other methods
- Pass in base class into constructor of custom CRUD class to use base code for other methods
- Implement methods in custom class to call base methods
- Some changes to using statements and variable definitions
- Changes
- New Custom Class: Custom_InventoryCostReportExtensionClassBase.cs
- SyteLine uses composition root pattern to compose an instance of code to execute functionality. This includes the class containing the method being performed and any dependent classes it needs.
- The same will be true for this customization.
- This class will allow changing the default implementation, via
the interface, to use the custom class.
- When there is a call for the base interface, instead of base class, the registration within this class specifies the custom class to be included.
- It is inherited from base SyteLine class used to support composition root.
- It contains override for GetService method.
- This class also registers base CRUD class to support custom CRUD class calling base methods that are not being changed by the custom CRUD class.
- Copy of SLInventoryCostReport.cs: Custom_SLInventoryCostReport.cs
- This is the entry point for IDO.
- Note: file name may differ from the custom IDO name; however, the values used in C# must be properly mapped in the custom IDO.
- Changes:
- Namespace: Custom_InventoryCostReport
- Instead of inheriting from CSIExtensionBase, use new custom class Custom_InventoryCostReportExtensionClassBase
- Note:
- No new interface is required for Custom_Rpt_InventoryCostCRUD class because base interface is pointed to new Custom_Rpt_InventoryCostCRUD instead of base Rpt_InventoryCostCRUD.
- Base application class is used because changes are not being made to that application class.
- Sample of custom code included after code descriptions
- Compile the solution.
- Upload Custom dll into IDO Custom Assemblies form - (see Mongoose documentation). Cloud naming convention shown for Assembly Name (ue_Custom_InventoryCostReport) mapped to C# ue_Custom_InventoryCostReport.dll.
- Update new IDO.
- IDOCustom Assembly Name: Custom or ue_Custom
- ue_Custom_InventoryCostReport
- ExtClass Name: Name of C# class β could be different than IDO name
- Custom_SLInventoryCostReport
- Namespace:Custom
- Custom_InventoryCostReport
- IDOCustom Assembly Name: Custom or ue_Custom
- Unload IDO Cache.
- Change target report viewer to use the custom IDO and unload the form. When you run the report for a lot-tracked item and a non-lot-tracked item, both with standard cost method, the description for the non-lot-tracked item is now displayed as Std instead of Standard.
- Code:
Custom_SLInventoryCostReport.cs: using System; using System.Data; using Mongoose.IDO; using Mongoose.IDO.Protocol; using CSI.Reporting; using System.Runtime.InteropServices; using CSI.Data.RecordSets; using Microsoft.Extensions.DependencyInjection; namespace Custom_InventoryCostReport { [IDOExtensionClass("Custom_SLInventoryCostReport")] public class Custom_SLInventoryCostReport : Custom_InventoryCostReportExtensionClassBase { [IDOMethod(MethodFlags.CustomLoad, "Infobar")] public DataTable Rpt_InventoryCostSp([Optional] string ExbegWhse, [Optional] string ExendWhse, [Optional] string ExbegLoc, [Optional] string ExendLoc, [Optional] string ExbegProductcode, [Optional] string ExendProductcode, [Optional] string ExbegItem, [Optional] string ExendItem, [Optional, DefaultParameterValue("AOS")] string ExOptgoItemStat, [Optional, DefaultParameterValue("MTFO")] string ExOptgoMatlType, [Optional, DefaultParameterValue("PMT")] string ExOptprPMTCode, [Optional, DefaultParameterValue("B")] string ExOptszStocked, [Optional, DefaultParameterValue("ABC")] string ExOptacAbcCode, [Optional, DefaultParameterValue(0)] int? ExOptprPrZeroQty, [Optional, DefaultParameterValue(0)] int? ShowDetail, [Optional, DefaultParameterValue(0)] int? PrintCost, [Optional] int? DisplayHeader, [Optional] string PMessageLanguage, [Optional] string pSite, [Optional] Guid? ProcessId) { var iRpt_InventoryCostExt = this.GetService<IRpt_InventoryCost>(); var result = iRpt_InventoryCostExt.Rpt_InventoryCostSp(ExbegWhse, ExendWhse, ExbegLoc, ExendLoc, ExbegProductcode, ExendProductcode, ExbegItem, ExendItem, ExOptgoItemStat, ExOptgoMatlType, ExOptprPMTCode, ExOptszStocked, ExOptacAbcCode, ExOptprPrZeroQty, ShowDetail, PrintCost, DisplayHeader, PMessageLanguage, pSite, ProcessId); if (result.Data is null) return new DataTable(); else { IRecordCollectionToDataTable recordCollectionToDataTable = new RecordCollectionToDataTable(); return recordCollectionToDataTable.ToDataTable(result.Data.Items); } } } } Custom_Rpt_InventoryCostCRUD.cs: using System; using CSI.MG; using CSI.Data.CRUD; using System.Collections.Generic; using CSI.Data.SQL; using CSI.Data.Cache; using CSI.Reporting; namespace Custom_InventoryCostReport { public class Custom_Rpt_InventoryCostCRUD : IRpt_InventoryCostCRUD { readonly IApplicationDB appDB; readonly ICollectionNonTriggerInsertRequestFactory collectionNonTriggerInsertRequestFactory; readonly IRpt_InventoryCostCRUD rpt_InventoryCostCRUD; public Custom_Rpt_InventoryCostCRUD( IApplicationDB appDB, ICollectionNonTriggerInsertRequestFactory collectionNonTriggerInsertRequestFactory, Rpt_InventoryCostCRUD rpt_InventoryCostCRUD ) { this.appDB = appDB; this.collectionNonTriggerInsertRequestFactory = collectionNonTriggerInsertRequestFactory; this.rpt_InventoryCostCRUD = rpt_InventoryCostCRUD; } public void SelectInsert_Tv_ItemGeneral(Guid? processId, string ExbegWhse, string ExendWhse, string ExbegLoc, string ExendLoc, string ExbegProductcode, string ExendProductcode, string ExbegItem, string ExendItem, string ExOptgoItemStat, string ExOptgoMatlType, string ExOptprPMTCode, string ExOptacAbcCode, int? TStock, string ParmsCurrCode, DateTime? GetSiteDate, int? ExOptprPrZeroQty, string CostPriceFormat, int? CostPricePlaces) { var selectInsertRequest = collectionNonTriggerInsertRequestFactory.SQLInsert(targetTableName: "tmp_rpt_inventory_cost", targetColumns: new List<string> { "process_id", "whse", "item", "loc", "lot", "status", "item_desc", "item_stocked", "matl_type", "cost_method", "u_m", "pmt_code", "product_code", "cost_type", "itemloc_inv_acct", "itemloc_lbr_acct", "itemloc_fovhd_acct", "itemloc_vovhd_acct", "itemloc_out_acct", "lot_tracked", "itemprice_unit_price1", "qty_on_hand", "cpr_cost", "matl_cost", "lbr_cost", "fovhd_cost", "vovhd_cost", "out_cost", "CostPriceFormat", "CostPricePlaces", "matl_type_description", "cost_method_description", "cost_type_description", }, valuesByExpressionToAssign: new Dictionary<string, IParameterizedCommand>() { {"process_id", collectionNonTriggerInsertRequestFactory.Clause("{0}", processId)}, {"whse",collectionNonTriggerInsertRequestFactory.Clause("itemloc.whse")}, {"item",collectionNonTriggerInsertRequestFactory.Clause("itemloc.item")}, {"loc",collectionNonTriggerInsertRequestFactory.Clause("itemloc.loc")}, {"lot",collectionNonTriggerInsertRequestFactory.Clause("lot_loc.lot")}, {"status",collectionNonTriggerInsertRequestFactory.Clause("item.stat")}, {"item_desc",collectionNonTriggerInsertRequestFactory.Clause("item.description")}, {"item_stocked",collectionNonTriggerInsertRequestFactory.Clause("item.stocked")}, {"matl_type",collectionNonTriggerInsertRequestFactory.Clause("item.matl_type")}, {"cost_method",collectionNonTriggerInsertRequestFactory.Clause("item.cost_method")}, {"u_m",collectionNonTriggerInsertRequestFactory.Clause("item.u_m")}, {"pmt_code",collectionNonTriggerInsertRequestFactory.Clause("item.p_m_t_code")}, {"product_code",collectionNonTriggerInsertRequestFactory.Clause("item.product_code")}, {"cost_type",collectionNonTriggerInsertRequestFactory.Clause("item.cost_type")}, {"itemloc_inv_acct",collectionNonTriggerInsertRequestFactory.Clause("itemloc.inv_acct")}, {"itemloc_lbr_acct",collectionNonTriggerInsertRequestFactory.Clause("itemloc.lbr_acct")}, {"itemloc_fovhd_acct",collectionNonTriggerInsertRequestFactory.Clause("itemloc.fovhd_acct")}, {"itemloc_vovhd_acct",collectionNonTriggerInsertRequestFactory.Clause("itemloc.vovhd_acct")}, {"itemloc_out_acct",collectionNonTriggerInsertRequestFactory.Clause("itemloc.out_acct")}, {"lot_tracked",collectionNonTriggerInsertRequestFactory.Clause("item.lot_tracked")}, {"itemprice_unit_price1",collectionNonTriggerInsertRequestFactory.Clause("isnull((SELECT TOP 1 unit_price1 FROM itemprice WHERE itemprice.item = item.item AND itemprice.effect_date <= {1} AND itemprice.curr_code = {0} ORDER BY itemprice.effect_date DESC), 0)", ParmsCurrCode,GetSiteDate)}, {"qty_on_hand",collectionNonTriggerInsertRequestFactory.Clause("lot_loc.qty_on_hand")}, {"cpr_cost",collectionNonTriggerInsertRequestFactory.Clause("CASE WHEN item.cost_type = 'S' OR item.cost_method IN ('A', 'C', 'L', 'F') THEN item.unit_cost ELSE lot_loc.unit_cost END")}, {"matl_cost",collectionNonTriggerInsertRequestFactory.Clause("CASE WHEN item.cost_type = 'S' OR item.cost_method IN ('A', 'C', 'L', 'F') THEN item.matl_cost ELSE lot_loc.matl_cost END")}, {"lbr_cost",collectionNonTriggerInsertRequestFactory.Clause("CASE WHEN item.cost_type = 'S' OR item.cost_method IN ('A', 'C', 'L', 'F') THEN item.lbr_cost ELSE lot_loc.lbr_cost END")}, {"fovhd_cost",collectionNonTriggerInsertRequestFactory.Clause("CASE WHEN item.cost_type = 'S' OR item.cost_method IN ('A', 'C', 'L', 'F') THEN item.fovhd_cost ELSE lot_loc.fovhd_cost END")}, {"vovhd_cost",collectionNonTriggerInsertRequestFactory.Clause("CASE WHEN item.cost_type = 'S' OR item.cost_method IN ('A', 'C', 'L', 'F') THEN item.vovhd_cost ELSE lot_loc.vovhd_cost END")}, {"out_cost",collectionNonTriggerInsertRequestFactory.Clause("CASE WHEN item.cost_type = 'S' OR item.cost_method IN ('A', 'C', 'L', 'F') THEN item.out_cost ELSE lot_loc.out_cost END")}, {"CostPriceFormat", collectionNonTriggerInsertRequestFactory.Clause("{0}", CostPriceFormat)}, {"CostPricePlaces", collectionNonTriggerInsertRequestFactory.Clause("{0}", CostPricePlaces)}, {"matl_type_description", collectionNonTriggerInsertRequestFactory.Clause("mt.matl_type_description")}, //{"cost_method_description", collectionNonTriggerInsertRequestFactory.Clause("cm.cost_method_description")}, {"cost_method_description", collectionNonTriggerInsertRequestFactory.Clause("'Std'")}, {"cost_type_description", collectionNonTriggerInsertRequestFactory.Clause("ct.cost_type_description")}, }, fromClause: collectionNonTriggerInsertRequestFactory.Clause(@"item inner join itemloc on item.item = itemloc.item inner join whse on itemloc.whse = whse.whse inner join location on itemloc.loc = location.loc inner join lot_loc on lot_loc.item = itemloc.item and lot_loc.whse = itemloc.whse and lot_loc.loc = itemloc.loc and({0} = 1 or lot_loc.qty_on_hand != 0) INNER JOIN #tv_MatlType AS mt ON mt.matl_type = item.matl_type INNER JOIN #tv_CostType AS ct ON ct.cost_type = item.cost_type INNER JOIN #tv_CostMethod AS cm ON cm.cost_method = item.cost_method", ExOptprPrZeroQty), whereClause: collectionNonTriggerInsertRequestFactory.Clause("item.lot_tracked = 1 AND whse.whse BETWEEN {6} AND {7} AND location.loc BETWEEN {10} AND {11} AND itemloc.item BETWEEN {8} AND {9} AND (item.product_code BETWEEN {0} AND {1}) AND (CHARINDEX(item.matl_type, {2}) <> 0 OR ISNULL({2}, '') = '') AND (CHARINDEX(item.p_m_t_code, {4}) > 0) AND (item.stocked = {12} OR ISNULL({12}, 2) = 2) AND (CHARINDEX(item.abc_code, {5}) <> 0 OR ISNULL({5}, '') = '') AND (CHARINDEX(item.stat, {3}) <> 0 OR ISNULL({3}, '') = '')", ExbegProductcode, ExendProductcode, ExOptgoMatlType, ExOptgoItemStat, ExOptprPMTCode, ExOptacAbcCode, ExbegWhse, ExendWhse, ExbegItem, ExendItem, ExbegLoc, ExendLoc, TStock), orderByClause: collectionNonTriggerInsertRequestFactory.Clause("")); this.appDB.InsertWithoutTrigger(selectInsertRequest); } (ICollectionLoadResponse Data, int? ReturnCode) IRpt_InventoryCostCRUD.AltExtGen_Rpt_InventoryCostSp(string AltExtGenSp, string ExbegWhse, string ExendWhse, string ExbegLoc, string ExendLoc, string ExbegProductcode, string ExendProductcode, string ExbegItem, string ExendItem, string ExOptgoItemStat, string ExOptgoMatlType, string ExOptprPMTCode, string ExOptszStocked, string ExOptacAbcCode, int? ExOptprPrZeroQty, int? ShowDetail, int? PrintCost, int? DisplayHeader, string PMessageLanguage, string pSite, Guid? ProcessID) { return rpt_InventoryCostCRUD.AltExtGen_Rpt_InventoryCostSp(AltExtGenSp, ExbegWhse, ExendWhse, ExbegLoc, ExendLoc, ExbegProductcode, ExendProductcode, ExbegItem, ExendItem, ExOptgoItemStat, ExOptgoMatlType, ExOptprPMTCode, ExOptszStocked, ExOptacAbcCode, ExOptprPrZeroQty, ShowDetail, PrintCost, DisplayHeader, PMessageLanguage, pSite, ProcessID); } void IRpt_InventoryCostCRUD.CleanupStagingTable(Guid? processId) { rpt_InventoryCostCRUD.CleanupStagingTable(processId); } (int? CostPricePlaces, string CostPriceFormat, int? rowCount) IRpt_InventoryCostCRUD.CurrencyLoad(string ParmsCurrCode, string CostPriceFormat, int? CostPricePlaces) { return rpt_InventoryCostCRUD.CurrencyLoad(ParmsCurrCode, CostPriceFormat, CostPricePlaces); } (string ParmsCurrCode, int? rowCount) IRpt_InventoryCostCRUD.CurrparmsLoad(string ParmsCurrCode) { return rpt_InventoryCostCRUD.CurrparmsLoad(ParmsCurrCode); } (int? CostItemAtWhse, int? rowCount) IRpt_InventoryCostCRUD.Dbo_InvparmsLoad(int? CostItemAtWhse) { return rpt_InventoryCostCRUD.Dbo_InvparmsLoad(CostItemAtWhse); } void IRpt_InventoryCostCRUD.Nontable10Insert(ICollectionLoadResponse nonTable10LoadResponse) { rpt_InventoryCostCRUD.Nontable10Insert(nonTable10LoadResponse); } ICollectionLoadResponse IRpt_InventoryCostCRUD.Nontable10Select(string Description) { return rpt_InventoryCostCRUD.Nontable10Select(Description); } void IRpt_InventoryCostCRUD.Nontable1Insert(ICollectionLoadResponse nonTable1LoadResponse) { rpt_InventoryCostCRUD.Nontable1Insert(nonTable1LoadResponse); } ICollectionLoadResponse IRpt_InventoryCostCRUD.Nontable1Select(string Description) { return rpt_InventoryCostCRUD.Nontable1Select(Description); } void IRpt_InventoryCostCRUD.Nontable2Insert(ICollectionLoadResponse nonTable2LoadResponse) { rpt_InventoryCostCRUD.Nontable2Insert(nonTable2LoadResponse); } ICollectionLoadResponse IRpt_InventoryCostCRUD.Nontable2Select(string Description) { return rpt_InventoryCostCRUD.Nontable2Select(Description); } void IRpt_InventoryCostCRUD.Nontable3Insert(ICollectionLoadResponse nonTable3LoadResponse) { rpt_InventoryCostCRUD.Nontable3Insert(nonTable3LoadResponse); } ICollectionLoadResponse IRpt_InventoryCostCRUD.Nontable3Select(string Description) { return rpt_InventoryCostCRUD.Nontable3Select(Description); } void IRpt_InventoryCostCRUD.Nontable4Insert(ICollectionLoadResponse nonTable4LoadResponse) { rpt_InventoryCostCRUD.Nontable4Insert(nonTable4LoadResponse); } ICollectionLoadResponse IRpt_InventoryCostCRUD.Nontable4Select(string Description) { return rpt_InventoryCostCRUD.Nontable4Select(Description); } void IRpt_InventoryCostCRUD.Nontable5Insert(ICollectionLoadResponse nonTable5LoadResponse) { rpt_InventoryCostCRUD.Nontable5Insert(nonTable5LoadResponse); } ICollectionLoadResponse IRpt_InventoryCostCRUD.Nontable5Select(string Description) { return rpt_InventoryCostCRUD.Nontable5Select(Description); } void IRpt_InventoryCostCRUD.Nontable6Insert(ICollectionLoadResponse nonTable6LoadResponse) { rpt_InventoryCostCRUD.Nontable6Insert(nonTable6LoadResponse); } ICollectionLoadResponse IRpt_InventoryCostCRUD.Nontable6Select(string Description) { return rpt_InventoryCostCRUD.Nontable6Select(Description); } void IRpt_InventoryCostCRUD.Nontable7Insert(ICollectionLoadResponse nonTable7LoadResponse) { rpt_InventoryCostCRUD.Nontable7Insert(nonTable7LoadResponse); } ICollectionLoadResponse IRpt_InventoryCostCRUD.Nontable7Select(string Description) { return rpt_InventoryCostCRUD.Nontable7Select(Description); } void IRpt_InventoryCostCRUD.Nontable8Insert(ICollectionLoadResponse nonTable8LoadResponse) { rpt_InventoryCostCRUD.Nontable8Insert(nonTable8LoadResponse); } ICollectionLoadResponse IRpt_InventoryCostCRUD.Nontable8Select(string Description) { return rpt_InventoryCostCRUD.Nontable8Select(Description); } void IRpt_InventoryCostCRUD.Nontable9Insert(ICollectionLoadResponse nonTable9LoadResponse) { rpt_InventoryCostCRUD.Nontable9Insert(nonTable9LoadResponse); } ICollectionLoadResponse IRpt_InventoryCostCRUD.Nontable9Select(string Description) { return rpt_InventoryCostCRUD.Nontable9Select(Description); } void IRpt_InventoryCostCRUD.NontableInsert(ICollectionLoadResponse nonTableLoadResponse) { rpt_InventoryCostCRUD.NontableInsert(nonTableLoadResponse); } ICollectionLoadResponse IRpt_InventoryCostCRUD.NontableSelect(string Description) { return rpt_InventoryCostCRUD.NontableSelect(Description); } void IRpt_InventoryCostCRUD.Optional_Module1Insert(ICollectionLoadResponse optional_module1LoadResponse) { rpt_InventoryCostCRUD.Optional_Module1Insert(optional_module1LoadResponse); } ICollectionLoadResponse IRpt_InventoryCostCRUD.Optional_Module1Select() { return rpt_InventoryCostCRUD.Optional_Module1Select(); } bool IRpt_InventoryCostCRUD.Optional_ModuleForExists() { return rpt_InventoryCostCRUD.Optional_ModuleForExists(); } ICollectionLoadResponse IRpt_InventoryCostCRUD.SelectBunchPageFromStaging(Guid? processId, int recordCap, LoadType loadType, int? printCost) { return rpt_InventoryCostCRUD.SelectBunchPageFromStaging(processId, recordCap, loadType, printCost); } void IRpt_InventoryCostCRUD.SelectInsert1_Tv_ItemGeneral(Guid? processId, string ExbegWhse, string ExendWhse, string ExbegLoc, string ExendLoc, string ExbegProductcode, string ExendProductcode, string ExbegItem, string ExendItem, string ExOptgoItemStat, string ExOptgoMatlType, string ExOptprPMTCode, string ExOptacAbcCode, int? TStock, string ParmsCurrCode, DateTime? GetSiteDate, int? ExOptprPrZeroQty, string CostPriceFormat, int? CostPricePlaces) { rpt_InventoryCostCRUD.SelectInsert1_Tv_ItemGeneral(processId, ExbegWhse, ExendWhse, ExbegLoc, ExendLoc, ExbegProductcode, ExendProductcode, ExbegItem, ExendItem, ExOptgoItemStat, ExOptgoMatlType, ExOptprPMTCode, ExOptacAbcCode, TStock, ParmsCurrCode, GetSiteDate, ExOptprPrZeroQty, CostPriceFormat, CostPricePlaces); } (string ALTGEN_SpName, int? rowCount) IRpt_InventoryCostCRUD.Tv_ALTGEN1Load(string ALTGEN_SpName) { return rpt_InventoryCostCRUD.Tv_ALTGEN1Load(ALTGEN_SpName); } void IRpt_InventoryCostCRUD.Tv_ALTGEN2Delete(ICollectionLoadResponse tv_ALTGEN2LoadResponse) { rpt_InventoryCostCRUD.Tv_ALTGEN2Delete(tv_ALTGEN2LoadResponse); } ICollectionLoadResponse IRpt_InventoryCostCRUD.Tv_ALTGEN2Select(string ALTGEN_SpName) { return rpt_InventoryCostCRUD.Tv_ALTGEN2Select(ALTGEN_SpName); } bool IRpt_InventoryCostCRUD.Tv_ALTGENForExists() { return rpt_InventoryCostCRUD.Tv_ALTGENForExists(); } void IRpt_InventoryCostCRUD.UpdateTmpItemGeneral0(Guid? processId) { rpt_InventoryCostCRUD.UpdateTmpItemGeneral0(processId); } void IRpt_InventoryCostCRUD.UpdateTmpItemGeneral1(Guid? processId) { rpt_InventoryCostCRUD.UpdateTmpItemGeneral1(processId); } void IRpt_InventoryCostCRUD.UpdateTmpItemGeneral2(Guid? processId) { rpt_InventoryCostCRUD.UpdateTmpItemGeneral2(processId); } void IRpt_InventoryCostCRUD.UpdateTmpItemGeneral3(Guid? processId) { rpt_InventoryCostCRUD.UpdateTmpItemGeneral3(processId); } } } Custom_InventoryCostReportExtensionClassBase.cs: using System; using CSI.MG; using CSI; using Microsoft.Extensions.DependencyInjection; using CSI.Reporting; namespace Custom_InventoryCostReport { public class Custom_InventoryCostReportExtensionClassBase : CSIExtensionClassBase { IServiceProvider serviceProvider; public override object GetService(Type serviceType) { var cr = new CompositionRoot(); var sc = cr.GetMongooseBasedServiceCollection(new MGCoreFeatures(this)); //classes sc.AddScoped<Rpt_InventoryCostCRUD>(); //interfaces sc.AddScoped<IRpt_InventoryCostCRUD, Custom_Rpt_InventoryCostCRUD>(); serviceProvider = sc.BuildSyteLineServiceProvider(); return serviceProvider.GetService(serviceType); } } }