Dot Net Archives -

Category Archives: Dot Net

Building a Controlled Booking-to-Time Entry Import Framework Inside Dynamics 365 Project Operations for Texas-Based Operational Security & Cybersecurity Firms

Building a Controlled Booking-to-Time Entry Import Framework Inside Dynamics 365 Project Operations Summary Two Texas-based firms — one in Cybersecurity, another in Operational Security — required a streamlined and controlled Time Entry (TE) creation process inside Dynamics 365 Project Operations. Native D365 Project Operations limitations around Project Task visibility, booking-driven TE creation, and inconsistent resource submissions created operational inefficiencies. A fully customized solution was implemented directly inside Dynamics 365 CRM using HTML Web Resources, JavaScript, Dataverse Web API, Ribbon Enable Rules, and custom plugins. The solution centralized TE creation under Project Managers and Project Approvers, enabling controlled and secure booking-based TE management. A custom booking import framework dynamically surfaced only authorized projects and resources based on Project Approver relationships. Custom plugin logic and Resource Assignment–based task resolution automated Project Task mapping for accurate Time Entry creation. Key capabilities delivered included controlled booking imports, role-based visibility, automated task association, external comments support, and bulk TE creation. Dynamic filtering ensured Project Managers could only access resources and bookings associated with projects they were authorized to manage. The entire experience operated natively inside Dynamics 365 Project Operations without external portals, Power Apps screens, or third-party applications. The implementation reduced manual effort, improved TE submission reliability, increased operational flexibility, and enabled more accurate tracking of actual project work. Table of Contents Introduction The Business Problem & Pain Points The Solution Architecture Implementation Design Principles Business Impact Why This Approach Worked FAQs Conclusion 1 Introduction Two Texas-based firms operating in the Cybersecurity and Operational Security space relied heavily on Dynamics 365 Project Operations for project delivery tracking, resource management, and operational execution. As project operations scaled, Project Managers and Project Approvers required a faster and more controlled mechanism for creating Time Entries (TEs) directly from resource bookings. The organizations needed a solution that could simplify booking imports, improve Project Task mapping, enforce role-based visibility, and reduce the dependency on individual resources for manual TE submissions. Operationally, Project Managers were often responsible for validating and entering actual work performed, making the standard TE process inefficient and time-consuming. Key Challenges Standard Dynamics 365 Project Operations behavior did not fully support project-task-aware Time Entry creation from bookings. Project Task values were not consistently available across Resource Requirements and bookings in several PO environments. Resource-driven TE submission resulted in inconsistent and delayed operational reporting. Project Managers lacked centralized visibility and controlled access to resource bookings across approved projects. Native booking import and TE creation workflows lacked flexibility for operational governance and scalability. Goals of the Solution Centralize Time Entry creation under Project Managers and Project Approvers. Enable controlled booking imports with role-based project visibility. Automate Project Task association during TE creation. Allow bulk creation of booking-driven Time Entries directly inside CRM. Improve operational accuracy, flexibility, and governance without relying on external applications or custom portals. 2 The Business Problem & Pain Points 1. Native Booking-to-Time Entry Limitations Standard Dynamics 365 Project Operations behavior did not consistently expose Project Task information through Resource Requirements and Bookings. This created gaps in task-aware Time Entry creation and forced users to manually reconstruct operational context during the TE process. 2. Lack of Controlled Booking Visibility Default system behavior provided broader booking visibility than operationally required. The organizations needed a controlled access model where only designated Project Managers and Project Approvers could view and manage booking imports for authorized projects. 3. High Manual Effort in Time Entry Creation Project Managers and operational teams spent significant time manually entering project references, tasks, durations, and external comments for each Time Entry. This increased administrative overhead and reduced operational efficiency. 4. Inconsistent Resource-Driven Submission Process The organizations faced reliability challenges with resource-submitted Time Entries, leading to delays, missing entries, and inconsistencies in operational reporting. Project Managers required centralized ownership over TE creation to ensure accurate work tracking. 5. Fragmented User Experience Users were required to navigate across multiple Dynamics 365 screens and entities to complete routine booking import and Time Entry operations, making the process cumbersome and inefficient for daily operational usage. 6. Scalability and Maintainability Concerns The firms required a lightweight and scalable solution that could operate natively within Dynamics 365 Project Operations without introducing unnecessary Power Apps layers, external portals, or high-maintenance custom applications. 3 The Solution Architecture Architecture Diagram and Flow Figure: Complete Frontend – Backend behaviour of the TE Automation Module. Dynamics 365 Ribbon Workbench A custom “Import Resource Bookings” ribbon action was introduced to provide controlled access to the booking import process only for authorized Project Managers and Project Approvers. JavaScript + Dataverse Web API JavaScript and Dataverse Web API were used to handle dynamic project filtering, approver validation, booking retrieval, task mapping, and automated Time Entry creation directly inside CRM. HTML Web Resources Two custom HTML-based interfaces were developed: Resource Selection Interface — controlled resource visibility and selection Booking Import & TE Creation Interface — booking imports, task selection, external comments, and bulk Time Entry creation Dataverse Plugin Layer A lightweight custom C# plugin was implemented to support Project Task resolution, task validation, and booking-to-Time Entry automation scenarios not fully supported natively in Dynamics 365 Project Operations. Dataverse Entities Involved The solution leveraged multiple Project Operations entities: msdyn_project msdyn_projectteam msdyn_resourceassignment msdyn_projecttask bookableresource msdyn_resourcerequirement bookableresourcebooking msdyn_timeentry Together, these entities enabled secure, project-aware, and task-aware operational workflows directly inside Dynamics 365 CRM. Entity Relationships Figure: Relationships and associations of the involved entities. 4 Implementation 1. Role-Controlled Ribbon Visibility A custom ribbon action was implemented to ensure only authorized Project Managers and Project Approvers could access the booking import functionality. Visibility was dynamically controlled based on project approval relationships inside Dynamics 365. Figure: Case 1: When Logged in as a Project Approver/Manager. Figure: Case 2: When NOT Logged in as a Project Approver/Manager. 2. Resource Selection Experience A custom resource selection interface was developed to display only eligible resources associated with projects managed by the logged-in approver. This provided secure and simplified operational visibility. Figure: Bookable Resource Selection from a list of Active Bookable Resources, which are under any Project, where the current … Continue reading Building a Controlled Booking-to-Time Entry Import Framework Inside Dynamics 365 Project Operations for Texas-Based Operational Security & Cybersecurity Firms

Share Story :

Real-Time PDF Report Generation on Power Pages: Replacing SSRS with Azure Function Apps for a US-Based Cybersecurity Firm

Summary A Houston-based cybersecurity firm eliminated report failures (~65%) by replacing SSRS with an Azure Function App pipeline. Dynamics 365 bound action ensured authentication stayed internal, bypassing Defender-related token failures. Integrated Power Pages, Power Automate, Dynamics 365, and Azure Functions for real-time PDF generation. Report generation time reduced from 3–8 minutes to under 15 seconds with zero infrastructure overhead. Table of Contents 1. About the Customer 2. The Challenge 3. The Solution 4. Technical Implementation 5. Business Impact 6. FAQs 7. Conclusion 1. About the Customer The client is a technology consulting and cybersecurity services firm based in Houston, Texas. They manage multiple concurrent client engagements using Dynamics 365 Project Operations as their core platform. Project managers and clients access live project data through a customer-facing portal built on Microsoft Power Pages. 2. The Challenge The organization needed one-click downloadable Project Status Reports from their Power Pages portal covering risks, issues, logs, and timelines. Their SSRS-based solution failed frequently due to authentication breakdowns caused by Microsoft Defender for Cloud Apps across multiple service boundaries. Key pain points: Silent authentication failures with no clear errors Retry delays of 60–90 seconds per attempt Separate SSRS infrastructure dependency Slow report customization cycle Project managers avoided generating reports during live meetings due to reliability concerns. 3. The Solution At Cloudfronts, while working on this project, I replaced the SSRS pipeline entirely with a synchronous, serverless architecture that keeps the authentication context inside the Dynamics 365 service layer. Technologies Used: Dynamics 365 Project Operations Power Pages Power Automate Plugins Azure Function Apps The solution generates fully formatted PDFs in real time using structured JSON payloads. This eliminated authentication failures while significantly improving speed and reliability. 4. Technical Implementation 1] Power Pages Button triggers Flow A “Download Report” button captures the project GUID and triggers a Power Automate flow with real-time progress feedback. 2] Dynamics 365 Plugin prepares JSON payload A bound action plugin retrieves all project data and converts it into a clean JSON payload for PDF generation. 3] Azure Function generates PDF The Azure Function processes the JSON and generates a formatted PDF, returning it as a Base64 string. 4] SharePoint Integration The generated PDF is automatically stored in the associated SharePoint document location linked to the project. This ensures centralized document management, version control, and easy access for stakeholders directly within the project workspace. 5] Portal PDF Preview The Base64 PDF is rendered directly in the portal using an iframe, allowing instant preview and download. Video: End-to-end implementation of real-time PDF report generation. 5. Business Impact 100% success rate — zero failures post deployment Under 15 seconds report generation time No infrastructure — fully serverless Zero authentication failures Faster iteration for report updates Project managers can now confidently generate reports during live client meetings. 6. FAQs Why not fix the SSRS authentication issue instead of replacing SSRS entirely? The authentication failures were a structural consequence of traversing multiple service boundaries in an environment with strict Defender for Cloud Apps session policies. Fixing them would have required either relaxing those policies — which the client’s security posture did not permit — or re-architecting the data retrieval to stay inside the platform, which is exactly what the bound action approach achieves. Replacing SSRS also removed a separate infrastructure dependency and gave the client full control over report formatting in code. Can this pattern be reused for other document types in Dynamics 365? Yes. The Azure Function App’s renderer is data-driven — it consumes a JSON payload and builds tables from whatever keys are present. The Dynamics 365 plugin can be adapted to query any entity and produce an equivalent payload. CloudFronts has applied the same pattern to inspection records, summary reports, and client-facing status documents across Professional Services and Manufacturing implementations. Does this work for environments without Microsoft Defender for Cloud Apps? Yes. The architectural benefits — synchronous generation, serverless PDF rendering, no SSRS infrastructure, and in-browser preview — apply regardless of the security layer on the environment. 7. Conclusion Replacing SSRS with an Azure Function App-based PDF renderer resolved both the reliability and authentication problems in a single architectural shift, delivering instant, professional-quality Project Status Reports from a Microsoft Power Pages portal with no legacy reporting infrastructure to maintain. The key lesson from this project is that keeping authentication within the Dynamics 365 service layer — rather than bridging to external systems — eliminates an entire category of environment-specific failures that are otherwise very difficult to diagnose and fix. By keeping authentication within Dynamics 365 and leveraging serverless architecture, the solution delivers instant, high-quality reports without infrastructure overhead. This approach demonstrates how modern cloud-native patterns can eliminate entire classes of system failures while improving user experience dramatically. Ready to modernise document generation in your Dynamics 365 environment?CloudFronts builds scalable Power Platform and Dynamics 365 solutions that replace legacy reporting infrastructure and automate document workflows. Reach out at transform@cloudfronts.com. Shashank Keny Associate Consultant · CloudFronts Shashank Keny is an Associate Consultant at CloudFronts with 1.5+ years of experience in cloud, data, and business applications. He specializes in building scalable, API-driven architectures and integrating enterprise systems across the Microsoft ecosystem. He is a Certified Databricks Data Engineer with hands-on experience in Dynamics 365 Project Operations and Dynamics 365 Sales, along with delivering business intelligence solutions using Power BI. His expertise also extends to modern AI solutions, including building custom copilots and implementing intelligent applications using Azure AI Foundry. Passionate about solving real-world business challenges through data and AI, he focuses on delivering efficient, scalable, and production-ready solutions. Experience: 1.5+ years Certification: Databricks Certified Data Engineer Specialization: Dynamics 365 Project Operations, Power BI, Azure Integrations, AI Solutions View LinkedIn Profile

Share Story :

Implementing Plugin for Automated Lead Creation in Dynamics 365

Dynamics 365 CRM plugins are a powerful way to enforce business logic on the server but choosing when and how to use them is just as important as writing the code itself. In one implementation for a Netherlands-based sustainability certification organization, the client needed their certification journey to begin with a custom application entity while still ensuring that applicant and company details were captured as leads for downstream sales and engagement processes. This blog explores how a server-side plugin was used to bridge that gap, reliably creating and associating lead records at runtime while keeping the solution independent of UI behavior and future integrations. In this scenario, the certification application was the starting point of the business process, but sales and engagement still needed to operate on leads. Simply storing the same information in one place wasn’t enough, the system needed a reliable way to translate an application into a lead at the right moment, every time. That transformation logic is neither data storage nor UI behavior; its core business process logic, which is why it was implemented using a Dynamics 365 plugin. Scenario: Certification Application Not Flowing into Sales Users reported the following challenge: a. A user submits or creates a Certification Applicationb. Applicant and company details are captured on a custom entityc. Sales teams expect a Lead to be created for follow-upd. No Lead exists unless created manually or through inconsistent automatione. Application and sales data become disconnected This breaks the intended business flow, as certification teams and sales teams end up working in parallel systems without a reliable link between applications and leads. Possible Solution: Handling Lead Creation Through Manual Processes (Original Approach) Before implementing the plugin, the organization attempted to manage lead creation manually or through disconnected automation. How It Worked (Initially) a. A Certification Application was submittedb. Users reviewed the applicationc. Sales team manually created a Lead with applicant/company detailsd. They tried to match accounts/contacts manuallye. Both records remained loosely connected. Why This Might Look Reasonable a. Simple to explain operationallyb. No development effortc. Works as long as users follow the steps perfectly The Hidden Problems 1] Inconsistent Data Entry a. Users forgot to create leadsb. Leads were created with missing fieldsc. Duplicate accounts/contacts were createdd. Sales lost visibility into new certification inquiries 2] Broken Cross-Department Workflow a. Certification team worked in the custom entityb. Sales team worked in Leadsc. No structural linkage existed between the twod. Downstream reporting (pipeline, conversion, source tracking) became unreliable. Workaround to This Approach: Use Server-Side Logic Instead of Manual Steps Practically, the transformation of an application into a lead is business logic, not user behavior. Once that boundary is respected, the solution becomes stable, predictable, and automation-friendly. Practical Solution: A Server-Side Plugin (Improved Approach) Instead of depending on people or scattered automation, the lead is created centrally and automatically through a plugin registered on the Certification Application entity. Why a Plugin? a. Executes consistently regardless of data sourceb. Not tied to form events or UI interactionsc. Can safely check for existing accounts/contactsd. Ensures one source of truth for lead and application linkagee. Works for portal submissions, integrations, and bulk imports This is essential for a client, where applications may originate from multiple channels and must feed accurately into the sales funnel. How the Plugin-Based Solution Works The solution was implemented using a server-side plugin registered on the Certification Application entity. The plugin executes when a new application is created, retrieves the necessary applicant and organization details, performs basic checks for existing accounts and contacts, creates a Lead using the extracted data, and finally links the Lead back to the originating application record. This ensures that every certification application automatically enters the sales pipeline in a consistent and reliable manner. Implementation Steps (For Developers New to Plugins) If you’re new to Dynamics 365 plugins, the implementation followed these core steps: Build and Register the Plugin. Once the plugin logic is implemented, build the project to generate the signed assembly. After a successful build: After registration, every new Certification Application will automatically trigger the plugin, ensuring that a Lead is created and linked without any manual intervention. a. Open the Plugin Registration Toolb. Connect to the target Dynamics 365 environmentc. Register the compiled assemblyd. Register the plugin step on the Create message of the Certification Application entitye. Configure the execution stage (typically post-operation) and execution mode (Synchronous or Asynchronous, depending on business needs) To encapsulate, this solution shows why server-side plugins are the right place for core business logic in Dynamics 365. By automatically creating and linking a Lead when a Certification Application is created, the organization removed manual steps, prevented data inconsistencies, and ensured that every application reliably flowed into the sales pipeline. We hope you found this blog useful, and if you would like to discuss anything, you can reach out to us at transform@cloudfronts.com

Share Story :

Plugin Class Code Recovery using XRMToolBox & C# DotPeek.

In an ideal Dynamics 365 (Dataverse) project, plugin source code lives safely in a version-controlled repository, flows cleanly through Azure DevOps pipelines, and is always recoverable. In reality, many of us inherit environments where that discipline didn’t exist. I recently worked with a customer where: This created a common but uncomfortable challenge in the Dynamics 365 world:How do you maintain, debug, or enhance plugins when the source code is lost? Rewriting everything from scratch was risky and time-consuming. Guessing behavior based on runtime results wasn’t reliable. Fortunately, Dynamics 365 and the .NET ecosystem give us a practical and effective alternative. Using XrmToolBox and JetBrains dotPeek, it is possible to recover readable C# plugin code directly from the deployed assembly. (Though the C# Class code recovered won’t be 100% exact, as the variable names would be different and generic; it is only suitable for close logic, structure & functional recovery) The Practical Solution The approach consists of two main steps: This does not magically restore comments or original formatting, but it does give a working, understandable code that closely reflects the original plugin logic. Tools Used Step 1: Extract the Plugin Assembly from Dataverse 1. Connect to the Environment 2. Load the Assembly Recovery Tool 3. Download the DLL At this point, you have successfully recovered the compiled plugin assembly exactly as it exists in the environment. Step 2: Decompile the DLL Using JetBrains dotPeek 1. Open dotPeek 2. Explore the Decompiled Code dotPeek will: One can now browse through: This is usually more than enough to understand how the plugin works. 3. Export to a Visual Studio Project (Optional but Recommended) One of dotPeek’s most powerful features is Export to Project: This gives you a proper .csproj with class files that you can open, build, and extend. Possibilities with the Recovered Code Once you have the decompiled C# code, several options open up: 1. Rebuild the Plugin Assembly 2. Re-register the Plugin 3. Maintain or Enhance Functionality Important Considerations Key Takeaway Losing plugin source code does not mean losing control of your Dynamics 365 solution. With XrmToolBox’s Assembly Recovery Tool and JetBrains dotPeek, you can: There are chances while working in Dynamics 365 technologies, that a developer might face this situation. Knowing this technique can save days-or weeks-of effort and give your customer confidence that their system remains fully supportable. We hope you found this blog useful, and if you would like to discuss anything, you can reach out to us at transform@cloudfronts.com

Share Story :

Seamlessly Switching Lead-Based BPFs After Qualification in Dynamics 365 CRM

In Microsoft Dynamics 365 CRM, Business Process Flows (BPFs) are powerful tools that guide users through defined business stages. However, when working with Lead-based BPFs that persist into Opportunity, certain platform limitations surface-especially when multiple Lead-rooted BPFs are involved. This blog walks through a real-world challenge I encountered while working with a Houston-based technology consulting and cybersecurity services firm. The firm specializes in modern digital transformation and enterprise security solutions. I explore issues with Lead → Opportunity Business Process Flow (BPF) switching, explain why the out-of-the-box behavior falls short, and detail how I designed a robust client-side and server-side solution to safely and reliably switch BPFs-even after a Lead has already been qualified. How BPFs Work (Quick Recap) It ideally won’t allow a switch, either via brute forcing via client side or server side as – The Problem In my scenario: The Challenge Once a Lead is qualified: This is non-intuitive, error-prone, and inefficient, especially considering the manual effort that goes into it. Solution Overview I implemented a guided, safe, and reversible BPF switching mechanism that: High-Level Architecture This solution uses: Step-by-Step Methodology 1. Entry Point: Opportunity Ribbon Button A custom ribbon button on the Opportunity form: These fields act as a controlled handshake between Opportunity and Lead. 2. Lead OnLoad: Controlled Trigger Execution On Lead form load: if (diffSeconds > 20) { return;} Xrm.WebApi.updateRecord(“lead”, formContext.data.entity.getId(), { cf_shouldtrigger: false}); This ensures: 3. Identifying and Aborting the Existing BPF Before switching: var activeProcess = formContext.data.process.getActiveProcess(); Xrm.WebApi.updateRecord(bpfEntityName,result.entities[0].businessprocessflowinstanceid,{statecode: 1, // Inactivestatuscode: 3 // Aborted}); This is a critical step—without aborting the old instance, Dynamics can behave unpredictably. 4. Switching the UI BPF After aborting: 5. Handling BPF Instance Creation (First-Time Switch Logic) The solution explicitly checks: If it exists: If it does NOT exist (first switch): This dual-path logic makes the solution idempotent and reusable. 6. Server-Side Plugin: Persisting the Truth A plugin ensures that: // Identify BPF typebool isNewBpf = (context.PrimaryEntityName == “new_bpf_entity”); // Resolve related LeadGuid leadId = isNewBpf? ((EntityReference)target[“bpf_leadid”]).Id: ((EntityReference)target[“leadid”]).Id; // Retrieve related Opportunity via LeadEntity opportunity = GetOpportunityByLead(service, leadId); // Determine stages and pathstring qualifyStageId = isNewBpf ? NEW_QUALIFY_STAGE : OLD_QUALIFY_STAGE;string finalStageId = isNewBpf ? NEW_FINAL_STAGE : OLD_FINAL_STAGE;string traversedPath =START_STAGE + “,” + qualifyStageId + “,” + finalStageId; // PATCH 1 – Qualify stageservice.Update(new Entity(target.LogicalName, target.Id){[“activestageid”] = new EntityReference(“processstage”, new Guid(qualifyStageId)),[“traversedpath”] = START_STAGE + “,” + qualifyStageId}); // PATCH 2 – Final stage + Opportunity bindservice.Update(new Entity(target.LogicalName, target.Id){[“activestageid”] = new EntityReference(“processstage”, new Guid(finalStageId)),[“traversedpath”] = traversedPath,[isNewBpf ? “bpf_opportunityid” : “opportunityid”] =new EntityReference(“opportunity”, opportunity.Id)}); // Mark Lead as successfully processedservice.Update(new Entity(“lead”, leadId){[“cf_pluginsuccess”] = new OptionSetValue(1) // Yes}); This guarantees data consistency and auditability. 7. Final UI Sync & Redirect After successful completion:   Xrm.Navigation.openForm({ entityName: “opportunity”, entityId: opportunityId }); From the user’s perspective: “I clicked a button, confirmed the switch, and landed back in my Opportunity—done.” Why This Solution Works ✔ Respects Dynamics 365 BPF constraints✔ Prevents orphaned or conflicting BPF instances✔ Handles first-time and repeat switches✔ Ensures server-side persistence✔ Minimal user disruption✔ Fully reversible Most importantly, it bridges the gap between platform limitations and real business needs. Dynamics 365 BPFs are powerful-but when multiple Lead-rooted processes coexist, manual switching is not enough. This solution demonstrates how: can be combined to deliver a seamless, enterprise-grade experience without unsupported hacks. If you’re facing similar challenges with Lead → Opportunity BPF transitions, this pattern can be adapted and reused with confidence. We hope you found this blog useful, and if you would like to discuss anything, you can reach out to us at transform@cloudfronts.com

Share Story :

C# Code to retrieve lookup value id from target entity in D365 CE.

Let us consider below example as use case We have Plugin that triggers on Update of Contact Table and wanted to retrieve Customer related to Contacts. Customer is Lookup field on Contact Table. Hence here our target entity is Contact. Code – Entity targetEntity = (Entity)context.InputParameters[“Target”];   Guid ContactId = targetEntity.Id; Using the above code we get the target entity Contact Guid and now we need to retrieve Customer lookup from the target Entity. var cols = new ColumnSet(new String[] { “parentcustomerid” }); Since we only want Customer lookup from Contact hence retrieving only Customer and you can retrieve columns as per your requirement. Entity parententity = service.Retrieve(“contact”, targetEntity.Id, cols); We have stored Retrieved values in parententity. Guid ParentAccount = ((EntityReference)parententity.Attributes[“parentcustomerid”]).Id; And in above step we get the Guid of Customer. Conclusion – This was simple example of accounts and Contacts, you can use the above code(specify the schema name of lookup field you want to retrieve) to retrieve any lookups from your target entity based on your requirement Hope this helps !

Share Story :

SEARCH BLOGS:

FOLLOW CLOUDFRONTS BLOG :


Categories

Secured By miniOrange